Message Draft
tool-ui/message-draftFreeBlock
Review and confirm drafted messages before sending.
See it running
Open the demo on tool-ui
www.tool-ui.com/components/message-draftInstall it
npx shadcn@latest add https://www.tool-ui.com/r/message-draft.jsonSource
1"use client";23import * as React from "react";4import { cn, Button } from "./_adapter";5import type {6 MessageDraftProps,7 SerializableEmailDraft,8 SerializableSlackDraft,9} from "./schema";10import { ActionButtons } from "../shared/action-buttons";11import type { Action } from "../shared/schema";12import { Check, ChevronDown } from "lucide-react";1314type DraftState = "review" | "sending" | "sent" | "cancelled";15type DraftOutcome = MessageDraftProps["outcome"];1617const DEFAULT_GRACE_PERIOD = 5000;18const COLLAPSED_BODY_HEIGHT = 280;1920interface RecipientRowProps {21 label: string;22 recipients: string[];23 maxVisible?: number;24 muted?: boolean;25}2627function RecipientRow({28 label,29 recipients,30 maxVisible = 3,31 muted = false,32}: RecipientRowProps) {33 const visibleRecipients = recipients.slice(0, maxVisible);34 const overflowCount = recipients.length - maxVisible;3536 return (37 <tr className="text-sm">38 <td className="text-muted-foreground w-0 pr-4 pb-1 text-right align-top font-medium whitespace-nowrap">39 {label}40 </td>41 <td className={cn("pb-1 align-top", muted && "text-muted-foreground")}>42 {visibleRecipients.join(", ")}43 {overflowCount > 0 && (44 <span className="text-muted-foreground"> +{overflowCount} more</span>45 )}46 </td>47 </tr>48 );49}5051interface SingleFieldRowProps {52 label: string;53 value: string;54}5556function SingleFieldRow({ label, value }: SingleFieldRowProps) {57 return (58 <tr className="text-sm">59 <td className="text-muted-foreground w-0 pr-4 pb-1 text-right align-top font-medium whitespace-nowrap">60 {label}61 </td>62 <td className="pb-1 align-top">{value}</td>63 </tr>64 );65}6667interface ExpandableBodyProps {68 body: string;69 isExpanded: boolean;70 onNeedsExpansionChange?: (needsExpansion: boolean) => void;71}7273function ExpandableBody({74 body,75 isExpanded,76 onNeedsExpansionChange,77}: ExpandableBodyProps) {78 const [needsExpansion, setNeedsExpansion] = React.useState<boolean | null>(79 null,80 );81 const contentRef = React.useRef<HTMLDivElement>(null);8283 React.useLayoutEffect(() => {84 if (contentRef.current) {85 const needs = contentRef.current.scrollHeight > COLLAPSED_BODY_HEIGHT;86 setNeedsExpansion(needs);87 onNeedsExpansionChange?.(needs);88 }89 }, [body, onNeedsExpansionChange]);9091 return (92 <div className="relative">93 <div94 ref={contentRef}95 className={cn(96// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from tool-ui
All 27 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Approval Cardapproval-card | tool-ui | Blocks | Free | 2 deps · 11 files | |
| Audioaudio | tool-ui | Blocks | Free | 2 deps · 9 files | |
| Chartchart | tool-ui | Blocks | Free | 2 deps · 8 files | |
| Citationcitation | tool-ui | Blocks | Free | 2 deps · 15 files | |
| Code Blockcode-block | tool-ui | Blocks | Free | 3 deps · 11 files | |
| Code Diffcode-diff | tool-ui | Blocks | Free | 3 deps · 10 files | |
| Data Tabledata-table | tool-ui | Blocks | Free | 1 dep · 17 files | |
| Geo Mapgeo-map | tool-ui | Blocks | Free | 4 deps · 12 files |
