UNPKG

laif-ds

Version:

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

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