50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
import { useState } from "react";
|
|
|
|
const LABELS: Record<string, string> = { back: "Go back", exit: "Exit", other: "Other — specify" };
|
|
|
|
export function ReservedControls({
|
|
reserved,
|
|
onControl,
|
|
}: {
|
|
reserved?: string[];
|
|
onControl: (c: string, text?: string) => void;
|
|
}) {
|
|
const [otherOpen, setOtherOpen] = useState(false);
|
|
const [text, setText] = useState("");
|
|
if (!reserved?.length) return null;
|
|
return (
|
|
<div className="flex flex-col gap-2 border-t border-border/60 pt-3">
|
|
<div className="flex flex-wrap gap-2">
|
|
{reserved.map((c) => (
|
|
<button
|
|
key={c}
|
|
className="rounded-md border border-border/60 px-2.5 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
|
|
onClick={() => (c === "other" ? setOtherOpen(true) : onControl(c))}
|
|
>
|
|
{LABELS[c] ?? c}
|
|
</button>
|
|
))}
|
|
</div>
|
|
{otherOpen && (
|
|
<div className="flex flex-col gap-2">
|
|
<textarea
|
|
data-awaiting-input="true"
|
|
className="thot-awaiting-input min-h-20 w-full resize-y rounded-lg border p-3 text-sm shadow-xs outline-none transition-[border-color,box-shadow]"
|
|
value={text}
|
|
onChange={(e) => setText(e.target.value)}
|
|
onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey && text.trim()) { e.preventDefault(); onControl("freetext", text); } }}
|
|
placeholder="Describe your alternative…"
|
|
/>
|
|
<button
|
|
className="self-start rounded-md bg-primary px-3 py-1.5 text-sm font-semibold text-primary-foreground shadow-xs transition-colors hover:bg-[oklch(var(--primary-hover))] disabled:cursor-not-allowed disabled:opacity-50"
|
|
disabled={!text.trim()}
|
|
onClick={() => onControl("freetext", text)}
|
|
>
|
|
Send
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|