UNPKG

laif-ds

Version:

Design System di Laif con componenti React basati su principi di Atomic Design

340 lines (339 loc) 11.2 kB
"use client"; import { jsxs as o, jsx as e } from "react/jsx-runtime"; import { useState as y, useEffect as S, useRef as J } from "react"; import { AnimatePresence as v, motion as w } from "framer-motion"; import { a as T } from "../../node_modules/remeda/dist/chunk-KI5X74E2.js"; import { cn as C } from "../../lib/utils.js"; import { useAudioRecording as Q } from "../../hooks/use-audio-recording.js"; import { useAutosizeTextArea as X } from "../../hooks/use-autosize-textarea.js"; import { AudioVisualizer as Y } from "./audio-visualizer.js"; import { Button as g } from "./button.js"; import { FilePreview as Z } from "./file-preview.js"; import { InterruptPrompt as _ } from "./interrupt-prompt.js"; import P from "../../node_modules/lucide-react/dist/esm/icons/paperclip.js"; import $ from "../../node_modules/lucide-react/dist/esm/icons/mic.js"; import G from "../../node_modules/lucide-react/dist/esm/icons/square.js"; import ee from "../../node_modules/lucide-react/dist/esm/icons/arrow-up.js"; import te from "../../node_modules/lucide-react/dist/esm/icons/info.js"; import re from "../../node_modules/lucide-react/dist/esm/icons/loader-circle.js"; function ie({ placeholder: i = "Ask AI...", className: n, onKeyDown: d, submitOnEnter: l = !0, stop: s, isGenerating: u, enableInterrupt: A = !0, transcribeAudio: I, ...r }) { const [R, x] = y(!1), [N, f] = y(!1), { isListening: F, isSpeechSupported: L, isRecording: D, isTranscribing: M, audioStream: O, toggleListening: j, stopRecording: k } = Q({ transcribeAudio: I, onTranscriptionComplete: (t) => { r.onChange?.({ target: { value: t } }); } }); S(() => { u || f(!1); }, [u]); const h = (t) => { r.allowAttachments && r.setFiles((a) => a === null ? t : t === null ? a : [...a, ...t]); }, q = (t) => { r.allowAttachments === !0 && (t.preventDefault(), x(!0)); }, E = (t) => { r.allowAttachments === !0 && (t.preventDefault(), x(!1)); }, H = (t) => { if (x(!1), r.allowAttachments !== !0) return; t.preventDefault(); const a = t.dataTransfer; a.files.length && h(Array.from(a.files)); }, K = (t) => { const a = t.clipboardData?.items; if (!a) return; const c = t.clipboardData.getData("text"); if (c && c.length > 500 && r.allowAttachments) { t.preventDefault(); const m = new Blob([c], { type: "text/plain" }), W = new File([m], "Pasted text", { type: "text/plain", lastModified: Date.now() }); h([W]); return; } const b = Array.from(a).map((m) => m.getAsFile()).filter((m) => m !== null); r.allowAttachments && b.length > 0 && h(b); }, U = (t) => { if (l && t.key === "Enter" && !t.shiftKey) { if (t.preventDefault(), u && s && A) { if (N) s(), f(!1), t.currentTarget.form?.requestSubmit(); else if (r.value || r.allowAttachments && r.files?.length) { f(!0); return; } } t.currentTarget.form?.requestSubmit(); } d?.(t); }, p = J( null ), [V, B] = y(0); S(() => { p.current && B(p.current.offsetHeight); }, [r.value]); const z = r.allowAttachments && r.files && r.files.length > 0; return X({ ref: p, maxHeight: 240, borderWidth: 1, dependencies: [r.value, z] }), /* @__PURE__ */ o( "div", { className: "relative flex w-full", onDragOver: q, onDragLeave: E, onDrop: H, children: [ A && /* @__PURE__ */ e( _, { isOpen: N, close: () => f(!1) } ), /* @__PURE__ */ e( oe, { isVisible: D, onStopRecording: k } ), /* @__PURE__ */ e("div", { className: "relative flex w-full items-center space-x-2", children: /* @__PURE__ */ o("div", { className: "relative flex-1", children: [ /* @__PURE__ */ e( "textarea", { "aria-label": "Write your prompt here", placeholder: i, ref: p, onPaste: K, onKeyDown: U, className: C( "border-d-input bg-d-input ring-offset-d-background placeholder:text-d-muted-foreground focus-visible:border-d-primary z-10 w-full grow resize-none rounded-xl border p-3 pr-24 text-sm transition-[border] focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50", z && "pb-16", n ), ...r.allowAttachments ? T(r, ["allowAttachments", "files", "setFiles"]) : T(r, ["allowAttachments"]) } ), r.allowAttachments && /* @__PURE__ */ e("div", { className: "absolute inset-x-3 bottom-2 z-20 overflow-x-scroll py-3 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: /* @__PURE__ */ e("div", { className: "flex space-x-3", children: /* @__PURE__ */ e(v, { mode: "popLayout", children: r.files?.map((t) => /* @__PURE__ */ e( Z, { file: t, onRemove: () => { r.setFiles((a) => { if (!a) return null; const c = Array.from(a).filter( (b) => b !== t ); return c.length === 0 ? null : c; }); } }, t.name + String(t.lastModified) )) }) }) }) ] }) }), /* @__PURE__ */ o("div", { className: "absolute top-3 right-3 z-20 flex gap-2", children: [ r.allowAttachments && /* @__PURE__ */ e( g, { type: "button", size: "icon", variant: "outline", className: "h-8 w-8", "aria-label": "Attach a file", onClick: async () => { const t = await ne(); h(t); }, children: /* @__PURE__ */ e(P, { className: "h-4 w-4" }) } ), L && /* @__PURE__ */ e( g, { type: "button", variant: "outline", className: C("h-8 w-8", F && "text-d-primary"), "aria-label": "Voice input", size: "icon", onClick: j, children: /* @__PURE__ */ e($, { className: "h-4 w-4" }) } ), u && s ? /* @__PURE__ */ e( g, { type: "button", size: "icon", className: "h-8 w-8", "aria-label": "Stop generating", onClick: s, children: /* @__PURE__ */ e(G, { className: "h-3 w-3 animate-pulse", fill: "currentColor" }) } ) : /* @__PURE__ */ e( g, { type: "submit", size: "icon", className: "h-8 w-8 transition-opacity", "aria-label": "Send message", disabled: r.value === "" || u, children: /* @__PURE__ */ e(ee, { className: "h-5 w-5" }) } ) ] }), r.allowAttachments && /* @__PURE__ */ e(ae, { isDragging: R }), /* @__PURE__ */ e( se, { isRecording: D, isTranscribing: M, audioStream: O, textAreaHeight: V, onStopRecording: k } ) ] } ); } ie.displayName = "MessageInput"; function ae({ isDragging: i }) { return /* @__PURE__ */ e(v, { children: i && /* @__PURE__ */ o( w.div, { className: "border-d-border bg-d-background text-d-secondary-foreground pointer-events-none absolute inset-0 z-20 flex items-center justify-center space-x-2 rounded-xl border border-dashed text-sm", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, "aria-hidden": !0, children: [ /* @__PURE__ */ e(P, { className: "h-4 w-4" }), /* @__PURE__ */ e("span", { children: "Drop your files here to attach them." }) ] } ) }); } function ne() { if (typeof document > "u") return Promise.resolve(null); const i = document.createElement("input"); return i.type = "file", i.multiple = !0, i.accept = "*/*", i.click(), new Promise((n) => { i.onchange = (d) => { const l = d.currentTarget.files; if (l) { n(Array.from(l)); return; } n(null); }; }); } function le() { return /* @__PURE__ */ o( w.div, { className: "bg-d-background/80 flex h-full w-full flex-col items-center justify-center rounded-xl backdrop-blur-sm", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, children: [ /* @__PURE__ */ o("div", { className: "relative", children: [ /* @__PURE__ */ e(re, { className: "text-d-primary h-8 w-8 animate-spin" }), /* @__PURE__ */ e( w.div, { className: "bg-d-primary/20 absolute inset-0 h-8 w-8 animate-pulse rounded-full", initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1.2, opacity: 1 }, transition: { duration: 1, repeat: 1 / 0, repeatType: "reverse", ease: "easeInOut" } } ) ] }), /* @__PURE__ */ e("p", { className: "text-d-secondary-foreground mt-4 text-sm font-medium", children: "Transcribing audio..." }) ] } ); } function oe({ isVisible: i, onStopRecording: n }) { return /* @__PURE__ */ e(v, { children: i && /* @__PURE__ */ e( w.div, { initial: { top: 0, filter: "blur(5px)" }, animate: { top: -40, filter: "blur(0px)", transition: { type: "spring", filter: { type: "tween" } } }, exit: { top: 0, filter: "blur(5px)" }, className: "bg-d-background border-d-border text-d-secondary-foreground absolute left-1/2 flex -translate-x-1/2 cursor-pointer overflow-hidden rounded-full border py-1 text-center text-sm whitespace-nowrap", onClick: n, children: /* @__PURE__ */ o("span", { className: "mx-2.5 flex items-center", children: [ /* @__PURE__ */ e(te, { className: "mr-2 h-3 w-3" }), "Click to finish recording" ] }) } ) }); } function se({ isRecording: i, isTranscribing: n, audioStream: d, textAreaHeight: l, onStopRecording: s }) { return i ? /* @__PURE__ */ e( "div", { className: "absolute inset-[1px] z-50 overflow-hidden rounded-xl", style: { height: l - 2 }, children: /* @__PURE__ */ e( Y, { stream: d, isRecording: i, onClick: s } ) } ) : n ? /* @__PURE__ */ e( "div", { className: "absolute inset-[1px] z-50 overflow-hidden rounded-xl", style: { height: l - 2 }, children: /* @__PURE__ */ e(le, {}) } ) : null; } export { ie as MessageInput };