import { SendHorizontal, Square } from "lucide-react"; import type { KeyboardEvent, ReactNode } from "react"; import { useCallback, useLayoutEffect, useRef, useState } from "react"; import type { GuestClient, GuestSnapshot } from "../../lib/client"; export interface ComposerProps { client: GuestClient; snapshot: GuestSnapshot; } /** Textarea metrics: line-height 20px + 8px vertical padding × 2 (kept in sync with shell.css). */ const LINE_PX = 20; const PAD_Y = 16; const MAX_ROWS = 8; function autosize(el: HTMLTextAreaElement | null): void { if (!el) return; el.style.height = "0px"; const max = MAX_ROWS * LINE_PX + PAD_Y; el.style.height = `${Math.max(LINE_PX + PAD_Y, Math.min(el.scrollHeight, max))}px`; el.style.overflowY = el.scrollHeight > max ? "auto" : "hidden"; } interface AskEditorProps { prefill: string | undefined; onSubmit(value: string): void; } /** * Editor ask input. Rendered with `key={reqId}` so a new request remounts it with a fresh * draft seeded from `prefill`, while re-sends of the same request never clobber a half-typed * draft. Submits verbatim — whitespace-only responses are intentional. */ function AskEditor({ prefill, onSubmit }: AskEditorProps): ReactNode { const [draft, setDraft] = useState(prefill ?? ""); const taRef = useRef(null); useLayoutEffect(() => { autosize(taRef.current); }, [draft]); const onKeyDown = (e: KeyboardEvent): void => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); onSubmit(draft); } }; return (