@gradeui/ui 3.3.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../lib/demo/types.ts","../lib/demo/sleep.ts","../lib/motion/index.ts","../lib/demo/use-scripted-demo.ts","../lib/utils.ts","../components/ui/composer.tsx"],"names":["DEMO_SPEED_PRESETS","DEMO_IN_VIEW_AMOUNT","sleep","ms","signal","resolve","reject","timer","onAbort","typeText","text","onTick","stagger","i","isAbortError","err","MOTION_ATTR","MOTION_OFF","REDUCE_QUERY","readReduced","osReduced","toggledOff","useReducedMotion","reduced","setReduced","z","update","mql","observer","usePageActive","active","setActive","framed","compute","DEFAULT_LOOP_DELAY_MS","INSTANT_PRESET","useScriptedDemo","opts","steps","interpret","speed","trigger","playProp","loop","loopDelay","maxLoops","containerRef","onComplete","onLoopReset","preset","effectiveLoop","pageActive","isPlaying","setIsPlaying","b","isComplete","setIsComplete","currentIndex","setCurrentIndex","noopRef","inView","useInView","liveInView","playbackActive","manualPlayTick","setManualPlayTick","shouldPlay","interpretRef","completeRef","loopResetRef","controllerRef","restartTimerRef","stop","play","n","restart","delayMs","controller","ctx","cycles","cn","inputs","twMerge","clsx","SubmitPlugin","onSubmit","enabled","editor","useLexicalComposerContext","e","KEY_ENTER_COMMAND","event","COMMAND_PRIORITY_HIGH","PastePlugin","onImageFiles","rootElement","handler","imageFiles","it","f","AutoFocusPlugin","FORMAT_TEXT_KEYS","applyFormat","format","textKey","FORMAT_TEXT_COMMAND","INSERT_UNORDERED_LIST_COMMAND","INSERT_ORDERED_LIST_COMMAND","selection","$getSelection","$isRangeSelection","tag","$setBlocksType","$createHeadingNode","node","$createQuoteNode","insertMentionNode","value","data","$createBeautifulMentionNode","selectSubstring","needle","found","root","$getRoot","idx","cursor","startNode","startOffset","endNode","endOffset","walk","tn","len","nodeStart","nodeEnd","endIdx","child","sn","en","clearEditor","para","$createParagraphNode","snapshotContent","json","mentions","m","FORMAT_BUTTONS","Bold","Italic","Underline","Strikethrough","CodeIcon","Heading1","Heading2","Heading3","Quote","ListIcon","ListOrdered","ComposerToolbar","formats","activeFormats","setActiveFormats","mergeRegister","editorState","next","fmt","visible","Icon","label","isActive","AttachmentChips","attachments","onRemove","AnimatePresence","motion","att","X","ComposerInner","placeholder","triggers","attachmentsCfg","formatList","showToolbar","isLoading","onStop","maxLength","autoFocus","submitOnEnter","leftActions","rightActions","hideSend","bare","className","onChange","readOnly","handleEditorReady","submitRef","restartRef","setAttachments","ingestImages","fileInputRef","hasContent","setHasContent","onChangeRef","handleSubmit","content","hasText","hasAttachments","a","demoRestart","step","sel","focus","partial","head","p","$createTextNode","stripLen","char","sel2","showDefaultSend","showDefaultAttach","showActionRow","id","prev","target","RichTextPlugin","ContentEditable","LexicalErrorBoundary","HistoryPlugin","ListPlugin","LinkPlugin","OnChangePlugin","BeautifulMentionsPlugin","acc","t","item","Paperclip","Square","Send","Composer","props","forwardedRef","initialText","initialJson","toolbar","attachmentsProp","rest","obj","attachmentsRef","files","candidates","tok","room","file","editorRef","_steps","lexicalTheme","initialConfig","error","HeadingNode","QuoteNode","ListNode","ListItemNode","LinkNode","AutoLinkNode","CodeNode","CodeHighlightNode","BeautifulMentionNode","richMode","innerRest","LexicalRoot","ComposerReply","ref"],"mappings":"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","file":"composer.js","sourcesContent":["/**\n * Shared types + presets for scripted component demos.\n *\n * Lives at the bottom of the demo primitive stack so the hook, the\n * cursor, and any component that opts in (`<Code>`, `<Composer>`,\n * `<DemoStage>`) all read from one definition of \"what slow / normal /\n * fast feels like\" and one definition of \"when do we start playing\".\n *\n * If you ever want to retune the cadence of every demo on the marketing\n * site at once, this is the file to edit.\n */\n\n/**\n * Animation feel. Maps onto a triple of timing values so authors can\n * pick a vibe (slow / normal / fast) instead of hand-tuning ms.\n * Components that need finer control can still override the resolved\n * values per-instance.\n */\nexport type DemoSpeed = \"slow\" | \"normal\" | \"fast\";\n\n/**\n * What kicks the demo off:\n * - `mount` plays immediately on first paint\n * - `inView` waits for the container to cross the viewport threshold\n * - `manual` driven by the `play` prop or imperative ref\n */\nexport type DemoTrigger = \"mount\" | \"inView\" | \"manual\";\n\n/**\n * Speed presets shared across every scripted-demo surface. Three\n * unambiguously distinct feels: `slow` is \"I am being shown\", `normal`\n * is \"I am being told\", `fast` is \"I am being briefed\".\n *\n * - `tokenStagger` per-character cadence for typing-style steps\n * - `lineStagger` per-line cadence for reveal-style demos\n * - `preDelay` pause after the trigger fires before the first tick\n * - `fadeMs` default enter-transition duration for revealed parts\n */\nexport const DEMO_SPEED_PRESETS: Record<\n DemoSpeed,\n {\n tokenStagger: number;\n lineStagger: number;\n preDelay: number;\n fadeMs: number;\n }\n> = {\n slow: { tokenStagger: 70, lineStagger: 200, preDelay: 500, fadeMs: 480 },\n normal: { tokenStagger: 22, lineStagger: 55, preDelay: 200, fadeMs: 280 },\n fast: { tokenStagger: 8, lineStagger: 18, preDelay: 60, fadeMs: 160 },\n};\n\n/**\n * `inView` threshold + `once` semantics applied by the hook. Marketing\n * surfaces want the reveal to fire once, after enough of the block is\n * visible that the user actually sees it animate.\n */\nexport const DEMO_IN_VIEW_AMOUNT = 0.55;\n","/**\n * Cancellable sleep + type helpers for scripted demos.\n *\n * The runner threads an `AbortSignal` through every step so a `stop()`\n * call (or an unmount) can short-circuit long waits and typing loops\n * cleanly. Consumers write `await sleep(ms, signal)` inside their\n * interpret callback and the cancellation is automatic.\n *\n * Note: this throws DOMException(\"Aborted\", \"AbortError\") on cancel.\n * The runner's outer try/catch swallows that specific error and exits;\n * any other rejection bubbles up so authoring bugs aren't silenced.\n */\n\n/**\n * Promisified setTimeout that resolves after `ms` milliseconds, or\n * rejects with an AbortError if the signal fires first. Resolves\n * immediately if `ms <= 0`.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) return Promise.resolve();\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n const timer = window.setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n window.clearTimeout(timer);\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/**\n * Type `text` one character at a time, calling `onTick(partial)` for\n * each prefix. Stagger between ticks defaults to 22ms (the `normal`\n * speed preset's `tokenStagger`).\n *\n * `onTick` receives the cumulative typed text (not the new char), so\n * consumers can do `setBuffer(prefix + partial)` without tracking state\n * themselves. The final call fires with the complete text — there's no\n * separate \"done\" callback.\n */\nexport async function typeText(\n text: string,\n onTick: (partial: string) => void,\n stagger = 22,\n signal?: AbortSignal,\n): Promise<void> {\n // Non-positive stagger (the reduced-motion preset, or any caller that\n // wants no typing animation): emit the whole string in a single tick so\n // the surface lands on its final state without per-character motion, or\n // the flicker a 0ms loop would produce.\n if (stagger <= 0) {\n onTick(text);\n return;\n }\n for (let i = 1; i <= text.length; i++) {\n onTick(text.slice(0, i));\n if (i < text.length) await sleep(stagger, signal);\n }\n}\n\n/**\n * Helper for treating an unknown error as the runner's abort sentinel.\n * Returns true if the value is the AbortError thrown by `sleep` / a\n * downstream `fetch` / etc. Used by the runner's catch block to\n * distinguish cancellation (silent exit) from real bugs (rethrow).\n */\nexport function isAbortError(err: unknown): boolean {\n return (\n err instanceof DOMException && err.name === \"AbortError\"\n );\n}\n","/**\n * lib/motion — the global motion control for gradeui.\n *\n * One choke point for \"should this animate?\". Every animated component\n * (ThreeScene, RivePlayer, VideoPlayer, aura surfaces) asks\n * `useReducedMotion()`, so flipping motion off in one place stills them all.\n *\n * Two independent inputs, ORed together (reduce-only by design — the toggle\n * can ADD restriction but never override a user's OS preference to force\n * motion ON):\n *\n * 1. the OS `prefers-reduced-motion: reduce` media query, and\n * 2. a `data-motion=\"off\"` attribute on the document root (`<html>`),\n * the manual toggle.\n *\n * The attribute is the same mechanism the renderer's `data-fidelity` flag\n * uses: stamp it on `<html>` and CSS + components react. Inside Studio's\n * Fast Frame / embed / share iframes it is driven over postMessage\n * (`grade:set-motion`), so the toggle reaches into the sandbox where the\n * ThreeScene surfaces actually run. A matching `[data-motion=\"off\"]` CSS\n * reset in `styles/globals.css` covers pure-CSS animation/transition.\n *\n * Sibling to lib/demo (the scripted-reveal spine).\n */\n\nimport * as React from \"react\";\n\n/** The attribute stamped on `<html>` to force motion off. */\nexport const MOTION_ATTR = \"data-motion\";\nconst MOTION_OFF = \"off\";\n\nconst REDUCE_QUERY = \"(prefers-reduced-motion: reduce)\";\n\n/** Read the current effective reduced-motion state (OS query OR the global\n * toggle). SSR-safe: returns `false` when there's no `window`. */\nfunction readReduced(): boolean {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return false;\n }\n const osReduced = window.matchMedia(REDUCE_QUERY).matches;\n const toggledOff =\n document.documentElement.getAttribute(MOTION_ATTR) === MOTION_OFF;\n return osReduced || toggledOff;\n}\n\n/**\n * Returns `true` when motion should be suppressed — either the OS reports\n * `prefers-reduced-motion: reduce`, or the global `data-motion=\"off\"` toggle\n * is set on `<html>`. Stays live: re-reads on media-query change and on the\n * attribute mutating.\n *\n * SSR-safe — defaults to `false` (motion allowed) on the server and\n * rehydrates in an effect, so it never causes a hydration mismatch.\n */\nexport function useReducedMotion(): boolean {\n const [reduced, setReduced] = React.useState(false);\n\n React.useEffect(() => {\n const update = () => setReduced(readReduced());\n update();\n\n const mql = window.matchMedia(REDUCE_QUERY);\n mql.addEventListener(\"change\", update);\n\n // Watch the toggle attribute on <html>.\n const observer = new MutationObserver(update);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [MOTION_ATTR],\n });\n\n return () => {\n mql.removeEventListener(\"change\", update);\n observer.disconnect();\n };\n }, []);\n\n return reduced;\n}\n\n/**\n * @deprecated Prefer {@link useReducedMotion}. Kept for back-compat with the\n * components that import it from `media-surface`; it now also folds in the\n * global `data-motion=\"off\"` toggle, not just the OS query.\n */\nexport const usePrefersReducedMotion = useReducedMotion;\n\n/**\n * Returns `true` when the page is actually being watched — the tab is visible\n * AND (for a top-level document) the window is focused. Inside an iframe the\n * focus check is skipped, because an iframe rarely \"has focus\" even when its\n * tab is frontmost; it falls back to visibility, which correctly tracks the\n * top tab. Use it to PAUSE autoplay loops when nobody's looking: a movie stops\n * when you tab away.\n *\n * SSR-safe — defaults to `true` and rehydrates in an effect.\n *\n * Scope, deliberately: this knows about tab visibility + window focus, NOT\n * whether the element is scrolled into view (pair it with an\n * IntersectionObserver — e.g. motion's `useInView` — for that), and NOT\n * whether a cross-document iframe has scrolled off its PARENT's viewport. An\n * iframe can't see the parent's scroll; the parent must observe the host and\n * pause it. See the grid poster/promote policy in STUDIO-CAPTURE.md.\n */\nexport function usePageActive(): boolean {\n const [active, setActive] = React.useState(true);\n\n React.useEffect(() => {\n // window.top identity check is safe cross-origin (no property access).\n const framed = window.self !== window.top;\n const compute = () =>\n document.visibilityState !== \"hidden\" && (framed || document.hasFocus());\n const update = () => setActive(compute());\n update();\n\n document.addEventListener(\"visibilitychange\", update);\n window.addEventListener(\"focus\", update);\n window.addEventListener(\"blur\", update);\n window.addEventListener(\"pageshow\", update);\n\n return () => {\n document.removeEventListener(\"visibilitychange\", update);\n window.removeEventListener(\"focus\", update);\n window.removeEventListener(\"blur\", update);\n window.removeEventListener(\"pageshow\", update);\n };\n }, []);\n\n return active;\n}\n\n/**\n * Imperatively set the global motion toggle on `<html>`.\n *\n * setMotion(false) → stamps `data-motion=\"off\"` (animation suppressed)\n * setMotion(true) → removes the attribute (default: respect the OS only)\n *\n * Reduce-only: turning motion \"on\" never forces animation for a viewer whose\n * OS asks for reduced motion — `useReducedMotion()` still honours the query.\n * No-op on the server.\n */\nexport function setMotion(enabled: boolean): void {\n if (typeof document === \"undefined\") return;\n const root = document.documentElement;\n if (enabled) root.removeAttribute(MOTION_ATTR);\n else root.setAttribute(MOTION_ATTR, MOTION_OFF);\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { useInView } from \"motion/react\";\nimport {\n DEMO_IN_VIEW_AMOUNT,\n DEMO_SPEED_PRESETS,\n type DemoSpeed,\n type DemoTrigger,\n} from \"./types\";\nimport { isAbortError, sleep } from \"./sleep\";\nimport { useReducedMotion, usePageActive } from \"../motion\";\n\n/**\n * useScriptedDemo — the shared step-machine hook behind every\n * scripted-demo surface in gradeui (`<Code>`, `<Composer>`,\n * `<DemoStage>`, anything else that wants the same play / stop / speed\n * semantics).\n *\n * Generic over the Step type. Each consumer defines its own verbs\n * (Code has `output`, Composer has `mention`, DemoStage has `reveal`)\n * and passes an `interpret(step, ctx)` callback that executes one\n * step. The hook owns: sequencing, cancellation, trigger detection\n * (mount / inView / manual), loop, pre-delay, completion signal, and\n * the imperative play() / stop() API.\n *\n * Reduced motion: this hook is the declarative-motion layer's accessibility\n * boundary. When the OS reports `prefers-reduced-motion: reduce` OR the\n * global `data-motion=\"off\"` toggle is set (both via `useReducedMotion`),\n * the runner settles on the FINAL frame instead of animating — zeroed\n * timings run every step instantly and the sequence never loops, so the\n * end state shows and holds. That keeps lib/demo honouring the same motion\n * control as ThreeScene and the CSS reset; without it, a screen built with\n * <Code> would keep typing under reduced motion and would not be accessible.\n *\n * Authoring guide for `interpret`:\n * - `await sleep(ms, ctx.signal)` for any pause so stop() can short\n * a long wait cleanly.\n * - `await typeText(text, onTick, stagger, ctx.signal)` for typing\n * loops, again so stop() interrupts mid-character. A non-positive\n * stagger (what the reduced-motion preset supplies) emits the whole\n * string in one tick, so the final state shows with no animation.\n * - Read `ctx.speed` to grab the resolved DEMO_SPEED_PRESETS entry\n * when a step doesn't pin its own cadence.\n * - Throw nothing on cancel — the helpers do it for you. Anything\n * else thrown is treated as a real bug and bubbles to the console.\n */\n\nexport interface ScriptedDemoContext {\n /** Resolved speed preset for the current run. Zeroed under reduced motion. */\n speed: (typeof DEMO_SPEED_PRESETS)[DemoSpeed];\n /** AbortSignal that fires on stop() / unmount / steps change. */\n signal: AbortSignal;\n /** Live cancellation check for code paths that can't take a signal. */\n cancelled: () => boolean;\n /** True when the run is in reduced-motion mode (settling, not animating).\n * Most interpreters don't need this — zeroed timings handle it — but a\n * step that does something non-timing-based (confetti, sound) can skip it. */\n reduced: boolean;\n}\n\nexport interface UseScriptedDemoOptions<TStep> {\n /** The steps to run. Undefined or empty means \"no script\". */\n steps?: TStep[];\n /**\n * Per-step interpreter. Receives one step + a context with timing\n * helpers, runs whatever the step means, and returns when done.\n * Synchronous or async — the runner awaits either.\n */\n interpret: (step: TStep, ctx: ScriptedDemoContext) => Promise<void> | void;\n /** Animation feel. Defaults to `normal`. */\n speed?: DemoSpeed;\n /** What kicks the script off. Defaults to `mount`. */\n trigger?: DemoTrigger;\n /** For `trigger=\"manual\"` — flip true to play. */\n play?: boolean;\n /** Loop the sequence forever after completion. Pause length controlled by `loopDelay`. */\n loop?: boolean;\n /** Cap the number of loop cycles, then settle and stop. A demo is a movie —\n * it shouldn't spin forever. Default Infinity. Grid/embed surfaces set a\n * small number so the loop ends instead of running unattended. */\n maxLoops?: number;\n /**\n * Milliseconds to pause between loop cycles. Only applies when\n * `loop` is true. Defaults to 2000. Marketing surfaces that want\n * the demo to breathe between repeats bump this to 4000-6000; tight\n * inline demos drop it to 800.\n */\n loopDelay?: number;\n /** Container ref for inView detection. Required when `trigger=\"inView\"`. */\n containerRef?: React.RefObject<HTMLElement | null>;\n /**\n * Fires when one loop iteration completes (or the whole run, when\n * `loop` is false). Consumers can use this to reset their buffer or\n * fire a parent callback.\n */\n onComplete?: () => void;\n /**\n * Fires before each loop iteration starts (after the 2s pause).\n * Use to reset per-iteration state in the consumer.\n */\n onLoopReset?: () => void;\n}\n\nexport interface ScriptedDemoState {\n /** True while the runner is actively walking steps. */\n isPlaying: boolean;\n /** True after the last step has run (and stays true until reset). */\n isComplete: boolean;\n /** 0-indexed pointer to the currently executing step, or -1 idle. */\n currentIndex: number;\n /** Imperative trigger. Mostly for `trigger=\"manual\"` ref handles. */\n play: () => void;\n /** Cancel the in-flight script. Idempotent. */\n stop: () => void;\n /**\n * One-shot replay. Cancels any in-flight run, then re-plays from\n * step 0. Pass a delay in ms to schedule the replay (useful for\n * \"play, finish, breathe, play once more\" cadences without the\n * commitment of `loop`).\n */\n restart: (delayMs?: number) => void;\n}\n\nconst DEFAULT_LOOP_DELAY_MS = 2000;\n\n// Reduced-motion timings — everything instant. `typeText` treats a\n// non-positive stagger as \"emit the whole string in one tick\", so steps\n// complete without the typing animation (or the flicker a 0ms loop causes)\n// and the surface lands on its final frame.\nconst INSTANT_PRESET: (typeof DEMO_SPEED_PRESETS)[DemoSpeed] = {\n tokenStagger: 0,\n lineStagger: 0,\n preDelay: 0,\n fadeMs: 0,\n};\n\nexport function useScriptedDemo<TStep>(\n opts: UseScriptedDemoOptions<TStep>,\n): ScriptedDemoState {\n const {\n steps,\n interpret,\n speed = \"normal\",\n trigger = \"mount\",\n play: playProp,\n loop = false,\n loopDelay = DEFAULT_LOOP_DELAY_MS,\n maxLoops = Infinity,\n containerRef,\n onComplete,\n onLoopReset,\n } = opts;\n\n // Reduced motion (OS preference OR the global data-motion toggle): settle\n // on the final frame instead of animating. Zeroed timings + no loop.\n const reduced = useReducedMotion();\n const preset = reduced ? INSTANT_PRESET : DEMO_SPEED_PRESETS[speed];\n const effectiveLoop = reduced ? false : loop;\n\n // Playback gate part 1 of 2: is the page even being watched? Pauses every\n // loop when the tab is hidden/unfocused — a movie stops when you tab away.\n // (Part 2, element-in-view, is wired below once we have the container ref.)\n const pageActive = usePageActive();\n\n const [isPlaying, setIsPlaying] = React.useState(false);\n const [isComplete, setIsComplete] = React.useState(false);\n const [currentIndex, setCurrentIndex] = React.useState(-1);\n\n // inView wiring — only active when trigger=\"inView\" AND a container\n // ref was supplied. amount + once mirror the marketing-hero contract.\n // `useInView` accepts a nullable ref so we always pass the ref, but\n // it only fires when actually observable.\n // motion's typing requires a non-null element ref. We assert via cast\n // because passing { current: null } is legal at runtime and behaves\n // as \"never in view\".\n const noopRef = React.useRef<HTMLElement>(null);\n const inView = useInView(\n (containerRef ?? noopRef) as React.RefObject<Element>,\n {\n once: true,\n amount: DEMO_IN_VIEW_AMOUNT,\n },\n );\n\n // Playback gate part 2 of 2: a LIVE in-view (re-fires on leave, unlike the\n // once-only trigger above). Only meaningful when a container ref is being\n // observed; with no ref we can't see the element, so we don't gate on it\n // (tab visibility still applies). Together: pause when nobody's watching.\n const liveInView = useInView(\n (containerRef ?? noopRef) as React.RefObject<Element>,\n { amount: DEMO_IN_VIEW_AMOUNT },\n );\n const playbackActive = pageActive && (containerRef ? liveInView : true);\n\n // Manual play trigger — a counter we bump from the imperative play()\n // method. The runner effect depends on it so a second play() call\n // (after stop() or after completion) cleanly re-runs the script.\n const [manualPlayTick, setManualPlayTick] = React.useState(0);\n\n const shouldPlay = React.useMemo(() => {\n if (trigger === \"mount\") return true;\n if (trigger === \"inView\") return inView;\n // manual: explicit prop OR imperative play() call (tick > 0)\n return Boolean(playProp) || manualPlayTick > 0;\n }, [trigger, inView, playProp, manualPlayTick]);\n\n // Stable interpret ref so the runner effect doesn't restart on every\n // render just because the consumer passes an inline function.\n const interpretRef = React.useRef(interpret);\n interpretRef.current = interpret;\n\n const completeRef = React.useRef(onComplete);\n completeRef.current = onComplete;\n const loopResetRef = React.useRef(onLoopReset);\n loopResetRef.current = onLoopReset;\n\n // Active AbortController so stop() can fire from outside the effect.\n const controllerRef = React.useRef<AbortController | null>(null);\n // Pending restart timeout id so a second restart() call supersedes\n // the first (and unmount cleans up before it fires).\n const restartTimerRef = React.useRef<number | null>(null);\n\n const stop = React.useCallback(() => {\n controllerRef.current?.abort();\n controllerRef.current = null;\n if (restartTimerRef.current !== null) {\n window.clearTimeout(restartTimerRef.current);\n restartTimerRef.current = null;\n }\n setIsPlaying(false);\n }, []);\n\n const play = React.useCallback(() => {\n // For mount/inView triggers, calling play() manually still works\n // (treated as a manual re-run): we bump the tick and rely on the\n // effect dependency to restart.\n setManualPlayTick((n) => n + 1);\n }, []);\n\n const restart = React.useCallback((delayMs = 0) => {\n // Cancel any in-flight run and any pending restart so the new\n // call is the source of truth.\n controllerRef.current?.abort();\n controllerRef.current = null;\n if (restartTimerRef.current !== null) {\n window.clearTimeout(restartTimerRef.current);\n restartTimerRef.current = null;\n }\n if (delayMs > 0) {\n restartTimerRef.current = window.setTimeout(() => {\n restartTimerRef.current = null;\n setManualPlayTick((n) => n + 1);\n }, delayMs);\n return;\n }\n setManualPlayTick((n) => n + 1);\n }, []);\n\n // Unmount cleanup for any orphaned restart timeout.\n React.useEffect(() => {\n return () => {\n if (restartTimerRef.current !== null) {\n window.clearTimeout(restartTimerRef.current);\n restartTimerRef.current = null;\n }\n };\n }, []);\n\n React.useEffect(() => {\n if (!steps || steps.length === 0) return;\n // Under reduced motion, run once to settle on the final frame even if\n // the normal trigger (inView / manual) hasn't fired — the content\n // should be present, just not animated.\n if (!reduced && (!shouldPlay || !playbackActive)) return;\n\n const controller = new AbortController();\n controllerRef.current = controller;\n const { signal } = controller;\n const cancelled = () => signal.aborted;\n\n const ctx: ScriptedDemoContext = { speed: preset, signal, cancelled, reduced };\n\n let active = true;\n let cycles = 0;\n\n const run = async () => {\n do {\n setIsPlaying(true);\n setIsComplete(false);\n setCurrentIndex(-1);\n\n try {\n // Initial pre-delay so the static state is visible for a\n // beat before the first step fires. Mostly matters for\n // `trigger=\"inView\"` (the eye needs an anchor) but it's\n // cheap to apply universally. Zero under reduced motion.\n await sleep(trigger === \"inView\" ? preset.preDelay : 0, signal);\n\n for (let i = 0; i < steps.length; i++) {\n if (signal.aborted) return;\n setCurrentIndex(i);\n await interpretRef.current(steps[i], ctx);\n }\n\n if (signal.aborted) return;\n setCurrentIndex(-1);\n setIsComplete(true);\n completeRef.current?.();\n\n cycles += 1;\n // Stop when not looping, or once we've hit the loop cap — settle on\n // the final frame and don't spin unattended.\n if (!effectiveLoop || cycles >= maxLoops) {\n setIsPlaying(false);\n return;\n }\n\n // Loop: pause (`loopDelay`, default 2000ms) then reset and replay.\n await sleep(loopDelay, signal);\n if (signal.aborted) return;\n loopResetRef.current?.();\n } catch (err) {\n if (isAbortError(err)) return;\n // Re-throw real errors so authoring bugs surface in the\n // console rather than being swallowed silently.\n if (process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.error(\"[useScriptedDemo] step error:\", err);\n }\n setIsPlaying(false);\n return;\n }\n } while (active && effectiveLoop && !signal.aborted);\n };\n\n void run();\n\n return () => {\n active = false;\n controller.abort();\n if (controllerRef.current === controller) controllerRef.current = null;\n };\n // `interpret` is intentionally NOT in the dep list — we read it\n // through interpretRef so the effect doesn't restart on every\n // render. Same for the completion callbacks. `reduced` IS a dep so\n // toggling motion re-runs (settles instantly when turned off,\n // re-animates when turned on).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n steps,\n shouldPlay,\n playbackActive,\n effectiveLoop,\n loopDelay,\n preset,\n trigger,\n manualPlayTick,\n reduced,\n ]);\n\n return { isPlaying, isComplete, currentIndex, play, stop, restart };\n}\n","import { type ClassValue, clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport {\n LexicalComposer as LexicalRoot,\n type InitialConfigType,\n} from \"@lexical/react/LexicalComposer\";\nimport { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\nimport { PlainTextPlugin } from \"@lexical/react/LexicalPlainTextPlugin\";\nimport { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\nimport { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\nimport { HistoryPlugin } from \"@lexical/react/LexicalHistoryPlugin\";\nimport { OnChangePlugin } from \"@lexical/react/LexicalOnChangePlugin\";\nimport { ListPlugin } from \"@lexical/react/LexicalListPlugin\";\nimport { LinkPlugin } from \"@lexical/react/LexicalLinkPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport {\n HeadingNode,\n QuoteNode,\n $createHeadingNode,\n $createQuoteNode,\n type HeadingTagType,\n} from \"@lexical/rich-text\";\nimport {\n ListNode,\n ListItemNode,\n INSERT_ORDERED_LIST_COMMAND,\n INSERT_UNORDERED_LIST_COMMAND,\n} from \"@lexical/list\";\nimport { LinkNode, AutoLinkNode } from \"@lexical/link\";\nimport { CodeNode, CodeHighlightNode } from \"@lexical/code\";\nimport { $setBlocksType } from \"@lexical/selection\";\nimport { mergeRegister } from \"@lexical/utils\";\nimport {\n $getRoot,\n $getSelection,\n $createParagraphNode,\n $createTextNode,\n $isRangeSelection,\n FORMAT_TEXT_COMMAND,\n KEY_ENTER_COMMAND,\n CLEAR_EDITOR_COMMAND,\n COMMAND_PRIORITY_HIGH,\n type TextFormatType,\n type LexicalEditor,\n type LexicalNode,\n type TextNode,\n} from \"lexical\";\nimport {\n BeautifulMentionsPlugin,\n BeautifulMentionNode,\n $createBeautifulMentionNode,\n type BeautifulMentionsItem,\n} from \"lexical-beautiful-mentions\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport {\n Bold,\n Italic,\n Underline,\n Strikethrough,\n Code as CodeIcon,\n Heading1,\n Heading2,\n Heading3,\n Quote,\n List as ListIcon,\n ListOrdered,\n Paperclip,\n Send,\n Square,\n X,\n} from \"lucide-react\";\nimport {\n useScriptedDemo,\n BlinkingCursor,\n sleep,\n typeText,\n type DemoSpeed,\n type DemoTrigger,\n} from \"@/lib/demo\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Composer — the generic text composition surface for the design system.\n *\n * The answer wherever a user is composing a message: AI chat input,\n * comment thread reply, post-body editor, future copilot panels.\n * Replaces the textarea-with-buttons pattern that hosts kept rolling\n * by hand.\n *\n * Built on Lexical (Meta's React-first editor framework) so it can do:\n * - rich text formatting (B / I / U / S / code, headings, blockquote,\n * pullquote, lists)\n * - mentions and slash commands via lexical-beautiful-mentions, with\n * a typeahead popover and theme-able tokens\n * - image attachments (paperclip + clipboard paste) when opted in\n * - scripted demo playback for marketing surfaces (types text, opens\n * mention popovers, applies formatting, all via the same step\n * vocabulary as <Code>)\n *\n * Slot-based composition for the action row: hosts that need custom\n * affordances (template picker, voice button, attach-document) pass\n * `leftActions` / `rightActions`. Default Send / Stop / paperclip\n * render only when the host hasn't replaced the slot.\n *\n * Hosts that want the canned \"chat composer with paperclip + send\"\n * preset should reach for `<AIChatComposer>` instead, which configures\n * this Composer with the right slots wired up.\n *\n * Scripted demos: same `speed` / `trigger` / `play` / `loop` vocabulary\n * as `<Code>`, sharing the underlying `useScriptedDemo` hook from\n * `lib/demo/`. The Composer adds its own verbs (`mention`, `format`,\n * `select`, `submit`) on top of the universal `type` / `wait` / `clear`.\n */\n\n// ─── Public types ────────────────────────────────────────────────────\n\nexport type ComposerFormat =\n | \"bold\"\n | \"italic\"\n | \"underline\"\n | \"strikethrough\"\n | \"code\"\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"blockquote\"\n | \"pullquote\"\n | \"ul\"\n | \"ol\";\n\nexport interface ComposerMentionItem {\n id: string;\n /** Display value (without the trigger char). */\n value: string;\n /** Optional secondary label shown in the suggester. */\n label?: string;\n /** Avatar URL or initials for the suggester row. */\n avatar?: string;\n /** Arbitrary payload the host can attach to the mention. */\n data?: Record<string, unknown>;\n}\n\nexport interface ComposerTriggerConfig {\n /** The trigger character, eg. \"@\" or \"/\". */\n char: string;\n /**\n * Items to populate the suggester. Either a static array or a\n * resolver function (sync or async) that receives the typed query.\n * The plugin filters automatically when items is an array.\n */\n items:\n | ComposerMentionItem[]\n | ((query: string) => ComposerMentionItem[] | Promise<ComposerMentionItem[]>);\n /**\n * Whether to strip the trigger char on insert. Defaults: keep for\n * \"@\" (mentions read as \"@alice\"), strip for \"/\" (commands read as\n * \"Insert image\" not \"/insert-image\").\n */\n stripTrigger?: boolean;\n}\n\nexport interface ComposerAttachmentConfig {\n /** Master enable. Set true on the prop to use defaults, or pass a config object. */\n enabled?: boolean;\n /** HTML accept attribute on the file input. Default \"image/*\". */\n accept?: string;\n /** Max number of attachments. Default 10. */\n maxItems?: number;\n /** Allow multiple selection in the file picker. Default true. */\n multiple?: boolean;\n}\n\nexport interface ComposerAttachment {\n id: string;\n file: File;\n /** Object URL owned by the composer. Hosts must NOT revoke it. */\n previewUrl: string;\n name: string;\n}\n\nexport interface ComposerContent {\n /** Plain text representation of the editor contents (whitespace preserved). */\n text: string;\n /** Lexical editor state serialised to JSON (for round-trip persistence). */\n json: string;\n /** Resolved mention tokens in document order. */\n mentions: Array<{ trigger: string; value: string; data?: Record<string, unknown> }>;\n}\n\nexport interface ComposerHandle {\n /** Run a demo script imperatively (vs. via `steps` + `trigger=\"manual\"`). */\n play: (steps: ComposerStep[]) => void;\n /** Cancel an in-flight demo. Idempotent. */\n stop: () => void;\n /**\n * One-shot replay of the configured `steps`. Cancels any in-flight\n * run, clears the editor, replays from step 0. Pass a delay (ms) to\n * schedule the replay (useful for chaining demos). Requires `steps`\n * to be configured.\n */\n restart: (delayMs?: number) => void;\n /** Move focus into the editor. */\n focus: () => void;\n /** Wipe the editor. */\n clear: () => void;\n /** Insert plain text at the current selection. */\n insert: (text: string) => void;\n /** Snapshot the current content + mentions. */\n getContent: () => ComposerContent;\n /** Direct access to the underlying Lexical editor (escape hatch). */\n getEditor: () => LexicalEditor | null;\n}\n\n/**\n * Demo step vocabulary for Composer scripts. Shares `type` / `wait` /\n * `clear` with the universal `lib/demo` verbs; adds composer-specific\n * `mention`, `format`, `select`, `newline`, `submit` on top.\n */\nexport type ComposerStep =\n | { type: \"type\"; text: string; speed?: DemoSpeed }\n | { type: \"wait\"; ms: number }\n | { type: \"clear\" }\n | { type: \"newline\" }\n | { type: \"submit\" }\n | {\n type: \"mention\";\n /** Trigger char (must match a registered ComposerTriggerConfig.char). */\n trigger: string;\n /** Value to insert (without the trigger). Looks up the matching item by `value`. */\n value: string;\n /** Optional pre-typed query — the demo types this after the trigger char before \"selecting\" the value, to show the typeahead in action. */\n query?: string;\n }\n | { type: \"format\"; format: ComposerFormat }\n | {\n type: \"select\";\n /** Substring to find and select. First match wins. */\n text: string;\n };\n\nexport interface ComposerProps {\n /** Placeholder copy shown when empty. */\n placeholder?: string;\n /** Initial plain text content. For richer initial state, use `initialJson`. */\n initialText?: string;\n /** Initial Lexical state JSON (from a previous `onSubmit` round-trip). */\n initialJson?: string;\n /**\n * Available formats. Pass false to disable rich text entirely\n * (plain text mode, half the bundle weight, no toolbar). Default\n * enables a sensible set for most chat / comment surfaces.\n */\n formats?: ComposerFormat[] | false;\n /**\n * Render the formatting toolbar. Default false because most uses\n * are short-form. Set true (or \"top\") to show the toolbar above the\n * editor. \"floating\" is planned; not yet implemented.\n */\n toolbar?: boolean | \"top\";\n /**\n * Mention / slash command configs. Each entry registers one trigger\n * char and its items. Pass `[{ char: \"@\", items: people }, { char: \"/\", items: commands }]`\n * for the common chat-app setup.\n */\n triggers?: ComposerTriggerConfig[];\n /**\n * Image attachments (paperclip + clipboard paste). Pass true for\n * defaults, an object to customise, or omit/false to skip the\n * attachment plumbing entirely.\n */\n attachments?: boolean | ComposerAttachmentConfig;\n /** Fires when the user submits (Enter, click Send, or scripted `submit` step). */\n onSubmit?: (content: ComposerContent, attachments?: ComposerAttachment[]) => void;\n /**\n * Fires on every editor change with the current plain text. Use for\n * length validation, controlled-value bridges (eg. AIChatComposer\n * forwarding to a host's `value`/`onChange` pair), or live preview\n * surfaces. Cheap, called frequently; debounce if you need the\n * Lexical state JSON (use `getContent()` via ref instead).\n */\n onChange?: (text: string) => void;\n /**\n * Loading state — disables the editor + paperclip and swaps the\n * default Send button for Stop. Has no effect when `rightActions`\n * overrides the default Send.\n */\n isLoading?: boolean;\n /** Stop handler — required for Stop to be active when loading. */\n onStop?: () => void;\n /** Hard character cap. */\n maxLength?: number;\n /** Auto-focus the editor on mount. Default false. */\n autoFocus?: boolean;\n /** Whether Enter submits. Default true (Shift-Enter still inserts a newline). */\n submitOnEnter?: boolean;\n /**\n * Custom content for the left action slot. Replaces the default\n * paperclip button when `attachments` is enabled.\n */\n leftActions?: React.ReactNode;\n /**\n * Custom content for the right action slot. Replaces the default\n * Send / Stop button. Use the `useComposer()` hook inside to access\n * imperative methods.\n */\n rightActions?: React.ReactNode;\n /** Hide the default Send button without replacing it. */\n hideSend?: boolean;\n /** Scripted demo steps. */\n steps?: ComposerStep[];\n /** What kicks the script off. Defaults to \"mount\". */\n trigger?: DemoTrigger;\n /** For trigger=\"manual\" — flip true to play. */\n play?: boolean;\n /** Animation feel. */\n speed?: DemoSpeed;\n /** Loop the script forever. */\n loop?: boolean;\n /**\n * Pause between loop iterations (ms). Defaults to 2000. Marketing\n * heroes that want the demo to breathe between repeats bump this\n * higher; tight inline demos drop it.\n */\n loopDelay?: number;\n /**\n * Fires once per loop cycle, AFTER the loopDelay pause and BEFORE\n * the script replays. Use to reset parent state that the script\n * mutated via onSubmit (e.g., wipe a messages list back to its\n * seed before the demo types into it again). The editor is cleared\n * automatically — you only need this hook if state outside the\n * Composer needs to reset too.\n */\n onLoopReset?: () => void;\n /**\n * Bare mode — strip the card chrome (border / bg / rounding). Use\n * when embedding inside an existing card or column layout.\n */\n bare?: boolean;\n /**\n * Read-only mode — disables editing AND focusability. Programmatic\n * updates (including scripted demo playback) still work. Use for\n * marketing surfaces that render a Composer purely for show, so the\n * scripted typing doesn't steal focus from other inputs on the page.\n * Hides the default Send / paperclip action row.\n */\n readOnly?: boolean;\n className?: string;\n}\n\n// ─── Plugins (internal) ──────────────────────────────────────────────\n\n/**\n * SubmitPlugin — wires Enter to submit (Shift-Enter still inserts a\n * newline). Captures the editor command before the rich-text plugin\n * inserts a paragraph break.\n */\nfunction SubmitPlugin({\n onSubmit,\n enabled,\n}: {\n onSubmit: () => void;\n enabled: boolean;\n}) {\n const [editor] = useLexicalComposerContext();\n\n React.useEffect(() => {\n if (!enabled) return;\n return editor.registerCommand(\n KEY_ENTER_COMMAND,\n (event) => {\n if (event && (event as KeyboardEvent).shiftKey) return false;\n event?.preventDefault();\n onSubmit();\n return true;\n },\n COMMAND_PRIORITY_HIGH,\n );\n }, [editor, enabled, onSubmit]);\n\n return null;\n}\n\n/**\n * PastePlugin — intercepts clipboard image pastes when attachments\n * are enabled, routes them to the attachment intake instead of\n * letting Lexical try to insert them as nodes.\n */\nfunction PastePlugin({\n onImageFiles,\n enabled,\n}: {\n onImageFiles: (files: File[]) => void;\n enabled: boolean;\n}) {\n const [editor] = useLexicalComposerContext();\n\n React.useEffect(() => {\n if (!enabled) return;\n const rootElement = editor.getRootElement();\n if (!rootElement) return;\n const handler = (e: ClipboardEvent) => {\n const items = Array.from(e.clipboardData?.items ?? []);\n const imageFiles = items\n .filter((it) => it.kind === \"file\" && it.type.startsWith(\"image/\"))\n .map((it) => it.getAsFile())\n .filter((f): f is File => f !== null);\n if (imageFiles.length > 0) {\n e.preventDefault();\n onImageFiles(imageFiles);\n }\n };\n rootElement.addEventListener(\"paste\", handler);\n return () => rootElement.removeEventListener(\"paste\", handler);\n }, [editor, enabled, onImageFiles]);\n\n return null;\n}\n\n/**\n * AutoFocusPlugin — focus the editor on mount when `autoFocus` is on.\n */\nfunction AutoFocusPlugin({ enabled }: { enabled: boolean }) {\n const [editor] = useLexicalComposerContext();\n React.useEffect(() => {\n if (!enabled) return;\n editor.focus();\n }, [editor, enabled]);\n return null;\n}\n\n/**\n * RefBridgePlugin — exposes the LexicalEditor instance up to the\n * outer forwardRef so ComposerHandle methods can drive it.\n */\nfunction RefBridgePlugin({\n onEditor,\n}: {\n onEditor: (editor: LexicalEditor) => void;\n}) {\n const [editor] = useLexicalComposerContext();\n React.useEffect(() => {\n onEditor(editor);\n }, [editor, onEditor]);\n return null;\n}\n\n// ─── Demo step interpreter ───────────────────────────────────────────\n\nconst FORMAT_TEXT_KEYS: Partial<Record<ComposerFormat, TextFormatType>> = {\n bold: \"bold\",\n italic: \"italic\",\n underline: \"underline\",\n strikethrough: \"strikethrough\",\n code: \"code\",\n};\n\n/**\n * Apply a block-level format to the current selection. Splits text\n * vs. block formats internally.\n */\nfunction applyFormat(editor: LexicalEditor, format: ComposerFormat) {\n const textKey = FORMAT_TEXT_KEYS[format];\n if (textKey) {\n editor.dispatchCommand(FORMAT_TEXT_COMMAND, textKey);\n return;\n }\n if (format === \"ul\") {\n editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);\n return;\n }\n if (format === \"ol\") {\n editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);\n return;\n }\n // Block-level conversions go through $setBlocksType inside an update.\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n if (format === \"h1\" || format === \"h2\" || format === \"h3\") {\n const tag = format as HeadingTagType;\n $setBlocksType(selection, () => $createHeadingNode(tag));\n return;\n }\n if (format === \"blockquote\" || format === \"pullquote\") {\n // Pullquote is a styled variant of blockquote: same node, plus a\n // data attribute the CSS targets. Lexical doesn't ship a custom\n // attribute API per quote, so we tag the DOM via theme below\n // and use a separate $createPullquoteNode if/when this graduates\n // into a custom node type.\n $setBlocksType(selection, () => {\n const node = $createQuoteNode();\n if (format === \"pullquote\") {\n // Best-effort marker so the theme can style it differently.\n // Stored on the element via a getter override later if we\n // need it round-trippable.\n (node as unknown as { __pullquote?: boolean }).__pullquote = true;\n }\n return node;\n });\n }\n });\n}\n\n/**\n * Insert a beautiful-mention node programmatically at the current\n * selection. Used by demo `mention` steps and the imperative\n * ComposerHandle.insert flow.\n */\nfunction insertMentionNode(\n editor: LexicalEditor,\n trigger: string,\n value: string,\n data?: Record<string, unknown>,\n) {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n // BeautifulMentionsItemData restricts to primitives (string | number\n // | boolean | null). Our public `data` is wider (Record<string,\n // unknown>) so callers can pass through richer payloads — but at the\n // node-creation boundary we cast since the plugin will JSON-roundtrip\n // it and anything non-primitive would silently drop anyway.\n const node = $createBeautifulMentionNode(\n trigger,\n value,\n data as Record<string, string | boolean | number | null> | undefined,\n );\n selection.insertNodes([node]);\n // Insert a trailing space so the caret sits ready for the next\n // word rather than glued to the mention pill.\n selection.insertText(\" \");\n });\n}\n\n/**\n * Find a substring in the editor's plain text and set the selection\n * to it. Returns true on success, false if not found.\n */\nfunction selectSubstring(editor: LexicalEditor, needle: string): boolean {\n let found = false;\n editor.update(() => {\n const root = $getRoot();\n const fullText = root.getTextContent();\n const idx = fullText.indexOf(needle);\n if (idx === -1) return;\n // Walk the text nodes to translate idx -> (node, offset).\n let cursor = 0;\n let startNode: TextNode | null = null;\n let startOffset = 0;\n let endNode: TextNode | null = null;\n let endOffset = 0;\n const walk = (node: LexicalNode) => {\n if (startNode && endNode) return;\n if (node.getType() === \"text\") {\n const tn = node as TextNode;\n const len = tn.getTextContentSize();\n const nodeStart = cursor;\n const nodeEnd = cursor + len;\n if (!startNode && idx >= nodeStart && idx < nodeEnd) {\n startNode = tn;\n startOffset = idx - nodeStart;\n }\n const endIdx = idx + needle.length;\n if (!endNode && endIdx > nodeStart && endIdx <= nodeEnd) {\n endNode = tn;\n endOffset = endIdx - nodeStart;\n }\n cursor = nodeEnd;\n return;\n }\n if (\"getChildren\" in node) {\n for (const child of (node as unknown as { getChildren: () => LexicalNode[] }).getChildren()) {\n walk(child);\n }\n } else {\n cursor += node.getTextContentSize();\n }\n };\n walk(root);\n // Cast inside the truthy branch. TS's control-flow analysis of a\n // let-with-`null`-initial mutated inside a closure narrows the\n // truthy-branch type to `never` (closure mutations aren't tracked\n // for flow purposes). The `as TextNode` tells TS we know better —\n // walk() either populated both or returned early.\n if (startNode && endNode) {\n const sn = startNode as TextNode;\n const en = endNode as TextNode;\n const selection = sn.select(startOffset, 0);\n selection.focus.set(en.getKey(), endOffset, \"text\");\n found = true;\n }\n });\n return found;\n}\n\n/**\n * Wipe the editor contents and leave a fresh empty paragraph with\n * a collapsed selection. Used wherever we need to \"reset to empty\" —\n * after submit, on imperative clear(), on loop reset, on restart().\n *\n * Why not `dispatchCommand(CLEAR_EDITOR_COMMAND)`: that command is\n * registered by RichTextPlugin / PlainTextPlugin and short-circuits\n * silently in some editor states (notably readOnly mode, but also\n * observed in some controlled flows). Explicit root mutation always\n * works because it bypasses the command layer entirely.\n */\nfunction clearEditor(editor: LexicalEditor) {\n editor.update(() => {\n const root = $getRoot();\n root.clear();\n const para = $createParagraphNode();\n root.append(para);\n para.select();\n });\n}\n\n/**\n * Snapshot the current editor content into the ComposerContent shape\n * exposed to onSubmit and via ComposerHandle.getContent.\n */\nfunction snapshotContent(editor: LexicalEditor): ComposerContent {\n let text = \"\";\n let json = \"\";\n const mentions: ComposerContent[\"mentions\"] = [];\n editor.getEditorState().read(() => {\n text = $getRoot().getTextContent();\n json = JSON.stringify(editor.getEditorState().toJSON());\n const walk = (node: LexicalNode) => {\n if (node.getType() === \"beautifulMention\") {\n const m = node as unknown as {\n getTrigger: () => string;\n getValue: () => string;\n getData: () => Record<string, unknown> | undefined;\n };\n mentions.push({\n trigger: m.getTrigger(),\n value: m.getValue(),\n data: m.getData(),\n });\n }\n if (\"getChildren\" in node) {\n for (const child of (node as unknown as { getChildren: () => LexicalNode[] }).getChildren()) {\n walk(child);\n }\n }\n };\n walk($getRoot());\n });\n return { text, json, mentions };\n}\n\n// ─── Toolbar ─────────────────────────────────────────────────────────\n\nconst FORMAT_BUTTONS: Array<{\n format: ComposerFormat;\n icon: React.ComponentType<{ className?: string }>;\n label: string;\n}> = [\n { format: \"bold\", icon: Bold, label: \"Bold\" },\n { format: \"italic\", icon: Italic, label: \"Italic\" },\n { format: \"underline\", icon: Underline, label: \"Underline\" },\n { format: \"strikethrough\", icon: Strikethrough, label: \"Strikethrough\" },\n { format: \"code\", icon: CodeIcon, label: \"Inline code\" },\n { format: \"h1\", icon: Heading1, label: \"Heading 1\" },\n { format: \"h2\", icon: Heading2, label: \"Heading 2\" },\n { format: \"h3\", icon: Heading3, label: \"Heading 3\" },\n { format: \"blockquote\", icon: Quote, label: \"Blockquote\" },\n { format: \"ul\", icon: ListIcon, label: \"Bulleted list\" },\n { format: \"ol\", icon: ListOrdered, label: \"Numbered list\" },\n];\n\nfunction ComposerToolbar({ formats }: { formats: ComposerFormat[] }) {\n const [editor] = useLexicalComposerContext();\n const [activeFormats, setActiveFormats] = React.useState<Set<TextFormatType>>(\n () => new Set(),\n );\n\n React.useEffect(() => {\n return mergeRegister(\n editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n const next = new Set<TextFormatType>();\n for (const fmt of [\"bold\", \"italic\", \"underline\", \"strikethrough\", \"code\"] as TextFormatType[]) {\n if (selection.hasFormat(fmt)) next.add(fmt);\n }\n setActiveFormats(next);\n });\n }),\n );\n }, [editor]);\n\n const visible = FORMAT_BUTTONS.filter((b) => formats.includes(b.format));\n\n return (\n <div\n data-gds-part=\"composer-toolbar\"\n className={cn(\n \"flex flex-wrap items-center gap-0.5\",\n // No bottom border — the toolbar sits inside the same card\n // as the editor and the action row. Internal dividers were\n // reading as too many seams; let the surface flow as one.\n \"px-2 py-1\",\n )}\n >\n {visible.map(({ format, icon: Icon, label }) => {\n const textKey = FORMAT_TEXT_KEYS[format];\n const isActive = textKey ? activeFormats.has(textKey) : false;\n return (\n <button\n key={format}\n type=\"button\"\n aria-label={label}\n title={label}\n data-gds-part=\"composer-toolbar-button\"\n data-gds-active={isActive ? \"true\" : \"false\"}\n onClick={() => applyFormat(editor, format)}\n className={cn(\n \"h-7 w-7 inline-flex items-center justify-center rounded\",\n \"text-[var(--gds-composer-toolbar-fg)]\",\n \"hover:bg-[var(--gds-composer-toolbar-hover-bg)]\",\n \"focus:outline-none focus:ring-2 focus:ring-primary\",\n isActive && \"bg-[var(--gds-composer-toolbar-active-bg)] text-[var(--gds-composer-toolbar-active-fg)]\",\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n </button>\n );\n })}\n </div>\n );\n}\n\n// ─── Attachment chip row ─────────────────────────────────────────────\n\nfunction AttachmentChips({\n attachments,\n onRemove,\n}: {\n attachments: ComposerAttachment[];\n onRemove: (id: string) => void;\n}) {\n return (\n <AnimatePresence initial={false}>\n {attachments.length > 0 && (\n <motion.div\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: \"auto\" }}\n exit={{ opacity: 0, height: 0 }}\n transition={{ duration: 0.18 }}\n className=\"overflow-hidden\"\n >\n <div\n data-gds-part=\"composer-attachments\"\n className=\"flex flex-wrap gap-2 px-2 py-2\"\n >\n {attachments.map((att) => (\n <div key={att.id} className=\"relative group\">\n {att.file.type.startsWith(\"image/\") ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={att.previewUrl}\n alt={att.name}\n className=\"h-14 w-14 rounded-md object-cover border border-[var(--gds-composer-border)]\"\n />\n ) : (\n <div className=\"h-14 w-14 rounded-md border border-[var(--gds-composer-border)] flex items-center justify-center text-xs px-1 text-center text-[var(--gds-composer-muted-fg)]\">\n {att.name.slice(0, 18)}\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => onRemove(att.id)}\n aria-label={`Remove ${att.name}`}\n className={cn(\n \"absolute -top-1.5 -right-1.5 h-5 w-5 rounded-full\",\n \"bg-[var(--gds-composer-chip-remove-bg)]\",\n \"text-[var(--gds-composer-chip-remove-fg)]\",\n \"flex items-center justify-center\",\n \"opacity-0 group-hover:opacity-100 focus:opacity-100\",\n \"focus:outline-none focus:ring-2 focus:ring-primary\",\n \"transition-opacity\",\n )}\n >\n <X className=\"w-3 h-3\" />\n </button>\n </div>\n ))}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n}\n\n// ─── Inner component (inside LexicalRoot) ────────────────────────────\n\ninterface InnerProps extends Omit<\n ComposerProps,\n \"initialJson\" | \"initialText\" | \"readOnly\" | \"attachments\"\n> {\n readOnly: boolean;\n /**\n * Bridge for the outer forwardRef to surface useScriptedDemo's\n * `restart()` on ComposerHandle. The inner component populates\n * this; the outer reads from it inside useImperativeHandle.\n */\n restartRef: React.MutableRefObject<(delayMs?: number) => void>;\n /** Resolved + normalised. */\n triggers: ComposerTriggerConfig[];\n attachmentsCfg: Required<ComposerAttachmentConfig> | null;\n formatList: ComposerFormat[];\n showToolbar: boolean;\n handleEditorReady: (editor: LexicalEditor) => void;\n /** Used by the demo player to drive submission. */\n submitRef: React.MutableRefObject<() => void>;\n /** Internal attachment state lifted up so the rightActions Send\n * button + the demo's submit step both see it. */\n attachments: ComposerAttachment[];\n setAttachments: React.Dispatch<React.SetStateAction<ComposerAttachment[]>>;\n /** Image intake callback (shared by paperclip + paste). */\n ingestImages: (files: File[]) => void;\n}\n\nfunction ComposerInner({\n placeholder,\n triggers,\n attachmentsCfg,\n formatList,\n showToolbar,\n isLoading,\n onStop,\n maxLength,\n autoFocus,\n submitOnEnter = true,\n leftActions,\n rightActions,\n hideSend,\n steps,\n trigger = \"mount\",\n play,\n speed = \"normal\",\n loop = false,\n loopDelay,\n onLoopReset,\n bare,\n className,\n onSubmit,\n onChange,\n readOnly,\n handleEditorReady,\n submitRef,\n restartRef,\n attachments,\n setAttachments,\n ingestImages,\n}: InnerProps) {\n const [editor] = useLexicalComposerContext();\n const containerRef = React.useRef<HTMLDivElement>(null);\n const fileInputRef = React.useRef<HTMLInputElement>(null);\n\n // Send-button enable state — driven by editor content.\n const [hasContent, setHasContent] = React.useState(false);\n\n React.useEffect(() => {\n handleEditorReady(editor);\n }, [editor, handleEditorReady]);\n\n // Read-only toggle — flips Lexical's editable flag. The contenteditable\n // element becomes non-focusable so a scripted demo running in this\n // composer can't steal focus from other inputs on the page.\n // editor.update() still applies, so demo playback continues to work.\n React.useEffect(() => {\n editor.setEditable(!readOnly);\n }, [editor, readOnly]);\n\n // Stable ref for onChange so the update listener doesn't re-register\n // every render. Read via ref so inline arrow functions don't churn it.\n const onChangeRef = React.useRef(onChange);\n onChangeRef.current = onChange;\n\n React.useEffect(() => {\n return editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n const text = $getRoot().getTextContent();\n setHasContent(text.trim().length > 0);\n onChangeRef.current?.(text);\n });\n });\n }, [editor]);\n\n // ── Submit handler — shared by Enter, Send button, demo \"submit\" step.\n const handleSubmit = React.useCallback(() => {\n if (isLoading) return;\n const content = snapshotContent(editor);\n const hasText = content.text.trim().length > 0;\n const hasAttachments = attachments.length > 0;\n if (!hasText && !hasAttachments) return;\n onSubmit?.(content, hasAttachments ? attachments : undefined);\n // Reset for the next message. Explicit root.clear() rather than\n // CLEAR_EDITOR_COMMAND so it works reliably in every state\n // (readOnly, controlled-value flows, etc) — the command path\n // short-circuits silently in some configurations.\n clearEditor(editor);\n attachments.forEach((a) => URL.revokeObjectURL(a.previewUrl));\n setAttachments([]);\n }, [editor, isLoading, attachments, onSubmit, setAttachments]);\n\n // Keep submitRef pointing at the latest closure for the demo player.\n submitRef.current = handleSubmit;\n\n // ── Demo player ────────────────────────────────────────────────────\n //\n // The interpret callback runs Lexical updates per step. Typing\n // splits into per-character updates so the user sees the text\n // appear; mention inserts the node directly (we could open the\n // popover UI, but for v1 keep it simple); format dispatches the\n // matching command; submit calls handleSubmit; select walks text\n // nodes to set a range.\n const { restart: demoRestart } = useScriptedDemo<ComposerStep>({\n steps,\n speed,\n trigger,\n play,\n loop,\n loopDelay,\n containerRef,\n onLoopReset: () => {\n clearEditor(editor);\n // Consumer-provided callback fires after the editor clear so\n // any external state (parent messages list, etc.) resets in\n // the same tick before the script replays.\n onLoopReset?.();\n },\n interpret: async (step, ctx) => {\n const signal = ctx.signal;\n if (step.type === \"wait\") return sleep(step.ms, signal);\n if (step.type === \"clear\") {\n clearEditor(editor);\n return sleep(120, signal);\n }\n if (step.type === \"newline\") {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n selection.insertParagraph();\n });\n return sleep(60, signal);\n }\n if (step.type === \"submit\") {\n handleSubmit();\n return sleep(120, signal);\n }\n if (step.type === \"format\") {\n applyFormat(editor, step.format);\n // Collapse the selection to its end so the next type step\n // appends instead of replacing the (still-selected) text.\n // Without this, scripted \"select word → format italic → type\n // more\" sequences would have the new typing wipe out the\n // formatted word. Lexical selection has no direct collapse\n // method, but anchor.set() with the focus's key/offset/type\n // produces a zero-width range at the end of the selection.\n editor.update(() => {\n const sel = $getSelection();\n if (!$isRangeSelection(sel) || sel.isCollapsed()) return;\n const focus = sel.focus;\n sel.anchor.set(focus.key, focus.offset, focus.type);\n });\n return sleep(80, signal);\n }\n if (step.type === \"select\") {\n selectSubstring(editor, step.text);\n return sleep(120, signal);\n }\n if (step.type === \"mention\") {\n // Optional pre-typed query — shows the typeahead in flight.\n if (step.query) {\n editor.update(() => {\n const sel = $getSelection();\n if ($isRangeSelection(sel)) sel.insertText(step.trigger);\n });\n await typeText(\n step.query,\n (partial) => {\n editor.update(() => {\n const root = $getRoot();\n const text = root.getTextContent();\n // Replace the trailing trigger + partial query each tick.\n const head = text.slice(0, text.length - step.trigger.length - (partial.length - 1));\n root.clear();\n const p = $createParagraphNode();\n if (head) p.append($createTextNode(head));\n p.append($createTextNode(step.trigger + partial));\n root.append(p);\n });\n },\n ctx.speed.tokenStagger,\n signal,\n );\n await sleep(180, signal);\n // Now strip the trigger + query and insert the mention.\n editor.update(() => {\n const root = $getRoot();\n const text = root.getTextContent();\n const stripLen = step.trigger.length + step.query!.length;\n const head = text.slice(0, text.length - stripLen);\n root.clear();\n const p = $createParagraphNode();\n if (head) p.append($createTextNode(head));\n root.append(p);\n p.select();\n });\n }\n insertMentionNode(editor, step.trigger, step.value);\n return sleep(120, signal);\n }\n // type — append one char per tick. Lexical wants its own update\n // transaction per insert, so we can't use typeText() directly\n // (that's a setter-style API for components that own a string\n // buffer). Run our own cancellable loop here instead.\n const stagger = step.speed\n ? { slow: 70, normal: 22, fast: 8 }[step.speed]\n : ctx.speed.tokenStagger;\n for (let i = 0; i < step.text.length; i++) {\n if (signal.aborted) return;\n const char = step.text[i];\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n // No active selection (eg. initial mount before the user\n // focused). Anchor at the end of the doc so the demo can\n // still type.\n $getRoot().selectEnd();\n const sel2 = $getSelection();\n if ($isRangeSelection(sel2)) sel2.insertText(char);\n return;\n }\n selection.insertText(char);\n });\n if (i < step.text.length - 1) await sleep(stagger, signal);\n }\n },\n });\n\n // Bridge useScriptedDemo's restart() up to the outer ComposerHandle.\n // Wrap it so the inner component also wipes the editor before the\n // new run begins (otherwise the replay's first type step would\n // append to the leftover text).\n React.useEffect(() => {\n restartRef.current = (delayMs?: number) => {\n clearEditor(editor);\n demoRestart(delayMs);\n };\n }, [editor, demoRestart, restartRef]);\n\n // ── Action row ─────────────────────────────────────────────────────\n\n // Read-only composers (marketing demos) shouldn't render the action\n // row — there's no user input to send, no attachments to attach.\n const showDefaultSend = !readOnly && !rightActions && !hideSend;\n const showDefaultAttach = !readOnly && !leftActions && attachmentsCfg !== null;\n const showActionRow = !readOnly && (showDefaultAttach || leftActions || showDefaultSend || rightActions);\n\n return (\n <div\n ref={containerRef}\n data-gds-part=\"composer\"\n data-gds-loading={isLoading ? \"true\" : \"false\"}\n className={cn(\n \"w-full\",\n // Match Input's chrome — rounded-md + border-input + shadow-sm\n // + softer focus ring. The Composer reads as a heavier sibling\n // of Input (multi-line, toolbar, attachments) and should sit\n // in the same form rhythm without looking like a different\n // family of control.\n !bare && [\n \"rounded-md\",\n \"bg-transparent\",\n \"border border-input\",\n \"shadow-sm\",\n \"focus-within:outline-none focus-within:ring-1 focus-within:ring-ring\",\n \"transition-colors\",\n ],\n className,\n )}\n >\n {showToolbar && <ComposerToolbar formats={formatList} />}\n\n {attachmentsCfg && (\n <AttachmentChips\n attachments={attachments}\n onRemove={(id) => {\n setAttachments((prev) => {\n const target = prev.find((a) => a.id === id);\n if (target) URL.revokeObjectURL(target.previewUrl);\n return prev.filter((a) => a.id !== id);\n });\n }}\n />\n )}\n\n <div className=\"relative\">\n <RichTextPlugin\n contentEditable={\n <ContentEditable\n data-gds-part=\"composer-editor\"\n className={cn(\n \"outline-none\",\n \"px-3 sm:px-4 py-3\",\n \"text-sm text-[var(--gds-composer-fg)]\",\n \"min-h-[44px] max-h-[300px] overflow-y-auto\",\n \"[&_p]:m-0 [&_p+p]:mt-2\",\n \"[&_h1]:text-xl [&_h1]:font-semibold [&_h1]:mt-2\",\n \"[&_h2]:text-lg [&_h2]:font-semibold [&_h2]:mt-2\",\n \"[&_h3]:text-base [&_h3]:font-semibold [&_h3]:mt-2\",\n \"[&_ul]:list-disc [&_ul]:pl-5 [&_ol]:list-decimal [&_ol]:pl-5\",\n \"[&_blockquote]:border-l-2 [&_blockquote]:border-[var(--gds-composer-border)] [&_blockquote]:pl-3 [&_blockquote]:italic\",\n \"[&_code]:bg-[var(--gds-composer-toolbar-active-bg)] [&_code]:px-1 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono\",\n isLoading && \"opacity-60 pointer-events-none\",\n )}\n aria-placeholder={placeholder ?? \"\"}\n placeholder={\n <div\n data-gds-part=\"composer-placeholder\"\n // Match the standard Input placeholder exactly.\n // (The old `text-[var(--gds-composer-muted-fg)]`\n // emitted a bare OKLCH triplet with no oklch()\n // wrapper — an invalid color — so the placeholder\n // fell back to the dark editor foreground and read\n // like already-typed text.)\n className=\"absolute top-3 left-3 sm:left-4 text-sm text-muted-foreground pointer-events-none select-none\"\n >\n {placeholder}\n </div>\n }\n spellCheck\n />\n }\n ErrorBoundary={LexicalErrorBoundary}\n />\n <HistoryPlugin />\n <ListPlugin />\n <LinkPlugin />\n <OnChangePlugin onChange={() => {}} />\n <AutoFocusPlugin enabled={Boolean(autoFocus)} />\n <SubmitPlugin onSubmit={handleSubmit} enabled={submitOnEnter} />\n {attachmentsCfg && (\n <PastePlugin onImageFiles={ingestImages} enabled={true} />\n )}\n {triggers.length > 0 && (\n <BeautifulMentionsPlugin\n items={triggers.reduce<Record<string, BeautifulMentionsItem[]>>(\n (acc, t) => {\n // Resolver functions are deferred to v2 — for now only\n // static arrays are wired into the plugin. The shape\n // here is intentionally minimal: just `value`. The\n // plugin spreads each item's extra props onto the DOM\n // (which is how it warns \"React does not recognize the\n // `foo` prop\"), so anything richer than primitives\n // needs the plugin's own custom-component slot to\n // render properly. Keep the surface narrow until we\n // need richer items.\n if (typeof t.items === \"function\") return acc;\n acc[t.char] = t.items.map((item) => ({\n value: item.value,\n })) as BeautifulMentionsItem[];\n return acc;\n },\n {},\n )}\n />\n )}\n </div>\n\n {/* Action row — paperclip on the left, send/stop on the right.\n Slots win when supplied; defaults render otherwise. Hidden\n entirely in readOnly mode. */}\n {showActionRow && (\n <div\n data-gds-part=\"composer-actions\"\n className=\"flex items-center justify-between gap-2 px-2 pb-2 pt-1\"\n >\n <div className=\"flex items-center gap-1\">\n {leftActions ?? (\n showDefaultAttach && (\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n disabled={isLoading}\n aria-label=\"Attach image\"\n title=\"Attach image\"\n className={cn(\n \"h-8 w-8 rounded-lg flex items-center justify-center\",\n \"text-[var(--gds-composer-action-fg)]\",\n \"hover:text-[var(--gds-composer-fg)]\",\n \"hover:bg-[var(--gds-composer-toolbar-hover-bg)]\",\n \"focus:outline-none focus:ring-2 focus:ring-primary\",\n \"transition-colors\",\n \"disabled:opacity-50 disabled:cursor-not-allowed\",\n )}\n >\n <Paperclip className=\"w-4 h-4\" />\n </button>\n )\n )}\n </div>\n\n {rightActions ??\n (showDefaultSend && (\n <button\n type=\"button\"\n onClick={isLoading ? onStop : handleSubmit}\n disabled={\n isLoading\n ? !onStop\n : !hasContent && attachments.length === 0\n }\n aria-label={isLoading ? \"Stop\" : \"Send\"}\n className={cn(\n \"h-8 w-8 rounded-lg flex items-center justify-center transition-colors flex-shrink-0\",\n \"focus:outline-none focus:ring-2 focus:ring-primary\",\n isLoading\n ? \"bg-red-500 hover:bg-red-600 text-white disabled:opacity-50\"\n : hasContent || attachments.length > 0\n ? \"bg-primary hover:bg-primary/90 text-primary-foreground\"\n : \"bg-[var(--gds-composer-toolbar-active-bg)] text-[var(--gds-composer-muted-fg)] cursor-not-allowed\",\n )}\n >\n {isLoading ? (\n <Square className=\"w-3.5 h-3.5\" />\n ) : (\n <Send className=\"w-3.5 h-3.5\" />\n )}\n </button>\n ))}\n\n {/* Hidden file input wired to the paperclip. */}\n {attachmentsCfg && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={attachmentsCfg.accept}\n multiple={attachmentsCfg.multiple}\n onChange={(e) => {\n if (e.target.files) ingestImages(Array.from(e.target.files));\n e.target.value = \"\";\n }}\n className=\"sr-only\"\n tabIndex={-1}\n aria-hidden=\"true\"\n />\n )}\n </div>\n )}\n </div>\n );\n}\n\n// ─── Outer component ────────────────────────────────────────────────\n\nexport const Composer = React.forwardRef<ComposerHandle, ComposerProps>(\n function Composer(props, forwardedRef) {\n const {\n initialText,\n initialJson,\n formats,\n toolbar,\n triggers,\n attachments: attachmentsProp,\n ...rest\n } = props;\n\n // Resolve formats — false means plain text, undefined means defaults.\n const formatList: ComposerFormat[] = React.useMemo(() => {\n if (formats === false) return [];\n return (\n formats ?? [\n \"bold\",\n \"italic\",\n \"underline\",\n \"strikethrough\",\n \"code\",\n \"h1\",\n \"h2\",\n \"blockquote\",\n \"ul\",\n \"ol\",\n ]\n );\n }, [formats]);\n\n const showToolbar = toolbar === true || toolbar === \"top\";\n\n // Resolve attachments config — true means defaults, object merges.\n const attachmentsCfg = React.useMemo<Required<ComposerAttachmentConfig> | null>(() => {\n if (!attachmentsProp) return null;\n const obj = attachmentsProp === true ? {} : attachmentsProp;\n if (obj.enabled === false) return null;\n return {\n enabled: true,\n accept: obj.accept ?? \"image/*\",\n maxItems: obj.maxItems ?? 10,\n multiple: obj.multiple ?? true,\n };\n }, [attachmentsProp]);\n\n const [attachments, setAttachments] = React.useState<ComposerAttachment[]>(\n [],\n );\n const attachmentsRef = React.useRef(attachments);\n attachmentsRef.current = attachments;\n\n // Revoke any outstanding object URLs on unmount.\n React.useEffect(() => {\n return () => {\n attachmentsRef.current.forEach((a) => URL.revokeObjectURL(a.previewUrl));\n };\n }, []);\n\n const ingestImages = React.useCallback(\n (files: File[]) => {\n if (!attachmentsCfg) return;\n const candidates = files.filter((f) => {\n if (!attachmentsCfg.accept) return true;\n if (attachmentsCfg.accept === \"image/*\") return f.type.startsWith(\"image/\");\n // Coarse check — full accept-attribute matching is more\n // permissive than we need for v1.\n return attachmentsCfg.accept.split(\",\").some((tok) => {\n const t = tok.trim();\n if (t.endsWith(\"/*\")) return f.type.startsWith(t.slice(0, -1));\n return f.type === t || f.name.toLowerCase().endsWith(t);\n });\n });\n if (candidates.length === 0) return;\n setAttachments((prev) => {\n const room = attachmentsCfg.maxItems - prev.length;\n if (room <= 0) return prev;\n const next = candidates.slice(0, room).map((file) => ({\n id: `${file.name}-${file.size}-${Date.now()}-${Math.random()\n .toString(36)\n .slice(2, 8)}`,\n file,\n previewUrl: URL.createObjectURL(file),\n name: file.name,\n }));\n return [...prev, ...next];\n });\n },\n [attachmentsCfg],\n );\n\n // Editor ref bridged via the inner plugin.\n const editorRef = React.useRef<LexicalEditor | null>(null);\n const submitRef = React.useRef<() => void>(() => {});\n // restart() is wired by the inner component (which owns the\n // useScriptedDemo state). Outer keeps a ref pointer it forwards\n // through ComposerHandle so callers can `ref.current.restart()`.\n const restartRef = React.useRef<(delayMs?: number) => void>(() => {});\n\n const handleEditorReady = React.useCallback((editor: LexicalEditor) => {\n editorRef.current = editor;\n }, []);\n\n // Expose imperative handle.\n React.useImperativeHandle(\n forwardedRef,\n (): ComposerHandle => ({\n play: (_steps) => {\n // For imperative play, we re-mount with a manual trigger.\n // V1: log + recommend using the `steps` prop with manual\n // trigger. The plumbing for hot-swapping a fresh script is\n // tracked as a follow-up.\n // eslint-disable-next-line no-console\n console.warn(\n \"[Composer] handle.play(steps) is not wired in v1 — pass `steps` + `trigger=\\\"manual\\\"` and toggle `play` instead.\",\n );\n },\n stop: () => {},\n restart: (delayMs) => restartRef.current(delayMs),\n focus: () => editorRef.current?.focus(),\n clear: () => {\n const editor = editorRef.current;\n if (editor) clearEditor(editor);\n },\n insert: (text) => {\n editorRef.current?.update(() => {\n const sel = $getSelection();\n if ($isRangeSelection(sel)) sel.insertText(text);\n });\n },\n getContent: () =>\n editorRef.current\n ? snapshotContent(editorRef.current)\n : { text: \"\", json: \"\", mentions: [] },\n getEditor: () => editorRef.current,\n }),\n [],\n );\n\n // Lexical theme classes — kept light so most of the styling\n // happens via Tailwind on the parent. The theme bridge is here\n // so consumers can override individual node classes via CSS\n // variables without forking the component.\n const lexicalTheme = React.useMemo(\n () => ({\n paragraph: \"gds-composer-paragraph\",\n quote: \"gds-composer-quote\",\n heading: {\n h1: \"gds-composer-h1\",\n h2: \"gds-composer-h2\",\n h3: \"gds-composer-h3\",\n },\n list: {\n ul: \"gds-composer-ul\",\n ol: \"gds-composer-ol\",\n listitem: \"gds-composer-li\",\n },\n text: {\n bold: \"font-semibold\",\n italic: \"italic\",\n underline: \"underline\",\n strikethrough: \"line-through\",\n code: \"gds-composer-code\",\n },\n beautifulMentions: {\n // Tailwind utilities so the pill styling works without\n // requiring consumers to load @gradeui/ui/styles.css. The\n // gds-composer-mention* tokens in globals.css are still\n // available for hosts that want to retheme without forking\n // — they layer over these defaults via class precedence.\n \"@\": \"gds-composer-mention px-1.5 py-0.5 mx-0.5 rounded bg-primary/10 text-primary font-medium\",\n \"/\": \"gds-composer-mention px-1.5 py-0.5 mx-0.5 rounded bg-violet-500/15 text-violet-600 dark:text-violet-400 font-medium\",\n },\n }),\n [],\n );\n\n // Initial config for LexicalRoot. Note nodes registration —\n // every custom node we use anywhere (BeautifulMentionNode for\n // mentions, HeadingNode/QuoteNode/etc for formatting) MUST be\n // declared here or Lexical throws at first paint.\n const initialConfig: InitialConfigType = React.useMemo(\n () => ({\n namespace: \"gds-composer\",\n theme: lexicalTheme,\n onError: (error: Error) => {\n // eslint-disable-next-line no-console\n console.error(\"[Composer]\", error);\n },\n nodes: [\n HeadingNode,\n QuoteNode,\n ListNode,\n ListItemNode,\n LinkNode,\n AutoLinkNode,\n CodeNode,\n CodeHighlightNode,\n BeautifulMentionNode,\n ],\n editorState: initialJson\n ? initialJson\n : initialText\n ? (editor: LexicalEditor) => {\n const root = $getRoot();\n const p = $createParagraphNode();\n p.append($createTextNode(initialText));\n root.append(p);\n }\n : undefined,\n }),\n [lexicalTheme, initialJson, initialText],\n );\n\n const richMode = formatList.length > 0;\n const { readOnly = false, ...innerRest } = rest;\n\n return (\n <LexicalRoot\n initialConfig={{\n ...initialConfig,\n editable: !readOnly,\n }}\n >\n <ComposerInner\n {...innerRest}\n readOnly={readOnly}\n triggers={triggers ?? []}\n attachmentsCfg={readOnly ? null : attachmentsCfg}\n formatList={formatList}\n showToolbar={showToolbar && richMode && !readOnly}\n handleEditorReady={handleEditorReady}\n submitRef={submitRef}\n restartRef={restartRef}\n attachments={attachments}\n setAttachments={setAttachments}\n ingestImages={ingestImages}\n />\n </LexicalRoot>\n );\n },\n);\n\n// ─── ComposerReply — preset for the reply use case ───────────────────\n//\n// Wraps Composer with sensible defaults for comment threads and\n// reply boxes: plain text only (no toolbar), no attachments, the\n// \"Write a reply…\" placeholder. Surfaced from playground use — three\n// scaffolds (comments, chat, hero preview) all reached for the same\n// shape and re-passed the same props.\n//\n// All defaults are overridable — pass `formats=[...]` to enable a\n// toolbar, `attachments` to allow uploads, etc. ComposerReply is\n// a starting point, not a lock-in.\n\nexport const ComposerReply = React.forwardRef<ComposerHandle, ComposerProps>(\n function ComposerReply(props, ref) {\n return (\n <Composer\n ref={ref}\n placeholder=\"Write a reply…\"\n formats={false}\n submitOnEnter={false}\n {...props}\n />\n );\n },\n);\n"]}
@@ -0,0 +1,3 @@
1
+ "use client";
2
+ import*as e from'react';import {LexicalComposer}from'@lexical/react/LexicalComposer';import {RichTextPlugin}from'@lexical/react/LexicalRichTextPlugin';import {ContentEditable}from'@lexical/react/LexicalContentEditable';import {LexicalErrorBoundary}from'@lexical/react/LexicalErrorBoundary';import {HistoryPlugin}from'@lexical/react/LexicalHistoryPlugin';import {OnChangePlugin}from'@lexical/react/LexicalOnChangePlugin';import {ListPlugin}from'@lexical/react/LexicalListPlugin';import {LinkPlugin}from'@lexical/react/LexicalLinkPlugin';import {useLexicalComposerContext}from'@lexical/react/LexicalComposerContext';import {HeadingNode,QuoteNode,$createHeadingNode,$createQuoteNode}from'@lexical/rich-text';import {ListNode,ListItemNode,INSERT_UNORDERED_LIST_COMMAND,INSERT_ORDERED_LIST_COMMAND}from'@lexical/list';import {LinkNode,AutoLinkNode}from'@lexical/link';import {CodeNode,CodeHighlightNode}from'@lexical/code';import {$setBlocksType}from'@lexical/selection';import {mergeRegister}from'@lexical/utils';import {$getSelection,$isRangeSelection,$getRoot,$createParagraphNode,$createTextNode,KEY_ENTER_COMMAND,COMMAND_PRIORITY_HIGH,FORMAT_TEXT_COMMAND}from'lexical';import {BeautifulMentionNode,BeautifulMentionsPlugin,$createBeautifulMentionNode}from'lexical-beautiful-mentions';import {useInView,AnimatePresence,motion}from'motion/react';import {Paperclip,Square,Send,Bold,Italic,Underline,Strikethrough,Code,Heading1,Heading2,Heading3,Quote,List,ListOrdered,X}from'lucide-react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';var pe={slow:{tokenStagger:70,lineStagger:200,preDelay:500,fadeMs:480},normal:{tokenStagger:22,lineStagger:55,preDelay:200,fadeMs:280},fast:{tokenStagger:8,lineStagger:18,preDelay:60,fadeMs:160}},ce=.55;function E(r,t){return r<=0?Promise.resolve():new Promise((o,s)=>{if(t?.aborted){s(new DOMException("Aborted","AbortError"));return}let n=window.setTimeout(()=>{t?.removeEventListener("abort",a),o();},r),a=()=>{window.clearTimeout(n),s(new DOMException("Aborted","AbortError"));};t?.addEventListener("abort",a,{once:true});})}async function ue(r,t,o=22,s){if(o<=0){t(r);return}for(let n=1;n<=r.length;n++)t(r.slice(0,n)),n<r.length&&await E(o,s);}function de(r){return r instanceof DOMException&&r.name==="AbortError"}var fe="data-motion",we="off",ge="(prefers-reduced-motion: reduce)";function Te(){if(typeof window>"u"||typeof document>"u")return false;let r=window.matchMedia(ge).matches,t=document.documentElement.getAttribute(fe)===we;return r||t}function be(){let[r,t]=e.useState(false);return e.useEffect(()=>{let o=()=>t(Te());o();let s=window.matchMedia(ge);s.addEventListener("change",o);let n=new MutationObserver(o);return n.observe(document.documentElement,{attributes:true,attributeFilter:[fe]}),()=>{s.removeEventListener("change",o),n.disconnect();}},[]),r}function he(){let[r,t]=e.useState(true);return e.useEffect(()=>{let o=window.self!==window.top,s=()=>document.visibilityState!=="hidden"&&(o||document.hasFocus()),n=()=>t(s());return n(),document.addEventListener("visibilitychange",n),window.addEventListener("focus",n),window.addEventListener("blur",n),window.addEventListener("pageshow",n),()=>{document.removeEventListener("visibilitychange",n),window.removeEventListener("focus",n),window.removeEventListener("blur",n),window.removeEventListener("pageshow",n);}},[]),r}var Se=2e3,De={tokenStagger:0,lineStagger:0,preDelay:0,fadeMs:0};function me(r){let{steps:t,interpret:o,speed:s="normal",trigger:n="mount",play:a,loop:d=false,loopDelay:h=Se,maxLoops:m=1/0,containerRef:R,onComplete:N,onLoopReset:L}=r,p=be(),y=p?De:pe[s],k=p?false:d,A=he(),[I,x]=e.useState(false),[X,V]=e.useState(false),[G,q]=e.useState(-1),$=e.useRef(null),W=useInView(R??$,{once:true,amount:ce}),M=useInView(R??$,{amount:ce}),K=A&&(R?M:true),[c,w]=e.useState(0),f=e.useMemo(()=>n==="mount"?true:n==="inView"?W:!!a||c>0,[n,W,a,c]),O=e.useRef(o);O.current=o;let _=e.useRef(N);_.current=N;let l=e.useRef(L);l.current=L;let P=e.useRef(null),T=e.useRef(null),te=e.useCallback(()=>{P.current?.abort(),P.current=null,T.current!==null&&(window.clearTimeout(T.current),T.current=null),x(false);},[]),se=e.useCallback(()=>{w(S=>S+1);},[]),oe=e.useCallback((S=0)=>{if(P.current?.abort(),P.current=null,T.current!==null&&(window.clearTimeout(T.current),T.current=null),S>0){T.current=window.setTimeout(()=>{T.current=null,w(C=>C+1);},S);return}w(C=>C+1);},[]);return e.useEffect(()=>()=>{T.current!==null&&(window.clearTimeout(T.current),T.current=null);},[]),e.useEffect(()=>{if(!t||t.length===0||!p&&(!f||!K))return;let S=new AbortController;P.current=S;let{signal:C}=S,re={speed:y,signal:C,cancelled:()=>C.aborted,reduced:p},ne=true,i=0;return (async()=>{do{x(true),V(false),q(-1);try{await E(n==="inView"?y.preDelay:0,C);for(let u=0;u<t.length;u++){if(C.aborted)return;q(u),await O.current(t[u],re);}if(C.aborted)return;if(q(-1),V(!0),_.current?.(),i+=1,!k||i>=m){x(!1);return}if(await E(h,C),C.aborted)return;l.current?.();}catch(u){if(de(u))return;process.env.NODE_ENV!=="production"&&console.error("[useScriptedDemo] step error:",u),x(false);return}}while(ne&&k&&!C.aborted)})(),()=>{ne=false,S.abort(),P.current===S&&(P.current=null);}},[t,f,K,k,h,y,n,c,p]),{isPlaying:I,isComplete:X,currentIndex:G,play:se,stop:te,restart:oe}}function j(...r){return twMerge(clsx(r))}function Rt({onSubmit:r,enabled:t}){let[o]=useLexicalComposerContext();return e.useEffect(()=>{if(t)return o.registerCommand(KEY_ENTER_COMMAND,s=>s&&s.shiftKey?false:(s?.preventDefault(),r(),true),COMMAND_PRIORITY_HIGH)},[o,t,r]),null}function vt({onImageFiles:r,enabled:t}){let[o]=useLexicalComposerContext();return e.useEffect(()=>{if(!t)return;let s=o.getRootElement();if(!s)return;let n=a=>{let h=Array.from(a.clipboardData?.items??[]).filter(m=>m.kind==="file"&&m.type.startsWith("image/")).map(m=>m.getAsFile()).filter(m=>m!==null);h.length>0&&(a.preventDefault(),r(h));};return s.addEventListener("paste",n),()=>s.removeEventListener("paste",n)},[o,t,r]),null}function Ct({enabled:r}){let[t]=useLexicalComposerContext();return e.useEffect(()=>{r&&t.focus();},[t,r]),null}var Re={bold:"bold",italic:"italic",underline:"underline",strikethrough:"strikethrough",code:"code"};function ve(r,t){let o=Re[t];if(o){r.dispatchCommand(FORMAT_TEXT_COMMAND,o);return}if(t==="ul"){r.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND,void 0);return}if(t==="ol"){r.dispatchCommand(INSERT_ORDERED_LIST_COMMAND,void 0);return}r.update(()=>{let s=$getSelection();if($isRangeSelection(s)){if(t==="h1"||t==="h2"||t==="h3"){let n=t;$setBlocksType(s,()=>$createHeadingNode(n));return}(t==="blockquote"||t==="pullquote")&&$setBlocksType(s,()=>{let n=$createQuoteNode();return t==="pullquote"&&(n.__pullquote=true),n});}});}function Et(r,t,o,s){r.update(()=>{let n=$getSelection();if(!$isRangeSelection(n))return;let a=$createBeautifulMentionNode(t,o,s);n.insertNodes([a]),n.insertText(" ");});}function wt(r,t){let o=false;return r.update(()=>{let s=$getRoot(),a=s.getTextContent().indexOf(t);if(a===-1)return;let d=0,h=null,m=0,R=null,N=0,L=p=>{if(!(h&&R)){if(p.getType()==="text"){let y=p,k=y.getTextContentSize(),A=d,I=d+k;!h&&a>=A&&a<I&&(h=y,m=a-A);let x=a+t.length;!R&&x>A&&x<=I&&(R=y,N=x-A),d=I;return}if("getChildren"in p)for(let y of p.getChildren())L(y);else d+=p.getTextContentSize();}};if(L(s),h&&R){let p=h,y=R;p.select(m,0).focus.set(y.getKey(),N,"text"),o=true;}}),o}function Z(r){r.update(()=>{let t=$getRoot();t.clear();let o=$createParagraphNode();t.append(o),o.select();});}function Ce(r){let t="",o="",s=[];return r.getEditorState().read(()=>{t=$getRoot().getTextContent(),o=JSON.stringify(r.getEditorState().toJSON());let n=a=>{if(a.getType()==="beautifulMention"){let d=a;s.push({trigger:d.getTrigger(),value:d.getValue(),data:d.getData()});}if("getChildren"in a)for(let d of a.getChildren())n(d);};n($getRoot());}),{text:t,json:o,mentions:s}}var Tt=[{format:"bold",icon:Bold,label:"Bold"},{format:"italic",icon:Italic,label:"Italic"},{format:"underline",icon:Underline,label:"Underline"},{format:"strikethrough",icon:Strikethrough,label:"Strikethrough"},{format:"code",icon:Code,label:"Inline code"},{format:"h1",icon:Heading1,label:"Heading 1"},{format:"h2",icon:Heading2,label:"Heading 2"},{format:"h3",icon:Heading3,label:"Heading 3"},{format:"blockquote",icon:Quote,label:"Blockquote"},{format:"ul",icon:List,label:"Bulleted list"},{format:"ol",icon:ListOrdered,label:"Numbered list"}];function St({formats:r}){let[t]=useLexicalComposerContext(),[o,s]=e.useState(()=>new Set);e.useEffect(()=>mergeRegister(t.registerUpdateListener(({editorState:a})=>{a.read(()=>{let d=$getSelection();if(!$isRangeSelection(d))return;let h=new Set;for(let m of ["bold","italic","underline","strikethrough","code"])d.hasFormat(m)&&h.add(m);s(h);});})),[t]);let n=Tt.filter(a=>r.includes(a.format));return e.createElement("div",{"data-gds-part":"composer-toolbar",className:j("flex flex-wrap items-center gap-0.5","px-2 py-1")},n.map(({format:a,icon:d,label:h})=>{let m=Re[a],R=m?o.has(m):false;return e.createElement("button",{key:a,type:"button","aria-label":h,title:h,"data-gds-part":"composer-toolbar-button","data-gds-active":R?"true":"false",onClick:()=>ve(t,a),className:j("h-7 w-7 inline-flex items-center justify-center rounded","text-[var(--gds-composer-toolbar-fg)]","hover:bg-[var(--gds-composer-toolbar-hover-bg)]","focus:outline-none focus:ring-2 focus:ring-primary",R&&"bg-[var(--gds-composer-toolbar-active-bg)] text-[var(--gds-composer-toolbar-active-fg)]")},e.createElement(d,{className:"h-3.5 w-3.5"}))}))}function Dt({attachments:r,onRemove:t}){return e.createElement(AnimatePresence,{initial:false},r.length>0&&e.createElement(motion.div,{initial:{opacity:0,height:0},animate:{opacity:1,height:"auto"},exit:{opacity:0,height:0},transition:{duration:.18},className:"overflow-hidden"},e.createElement("div",{"data-gds-part":"composer-attachments",className:"flex flex-wrap gap-2 px-2 py-2"},r.map(o=>e.createElement("div",{key:o.id,className:"relative group"},o.file.type.startsWith("image/")?e.createElement("img",{src:o.previewUrl,alt:o.name,className:"h-14 w-14 rounded-md object-cover border border-[var(--gds-composer-border)]"}):e.createElement("div",{className:"h-14 w-14 rounded-md border border-[var(--gds-composer-border)] flex items-center justify-center text-xs px-1 text-center text-[var(--gds-composer-muted-fg)]"},o.name.slice(0,18)),e.createElement("button",{type:"button",onClick:()=>t(o.id),"aria-label":`Remove ${o.name}`,className:j("absolute -top-1.5 -right-1.5 h-5 w-5 rounded-full","bg-[var(--gds-composer-chip-remove-bg)]","text-[var(--gds-composer-chip-remove-fg)]","flex items-center justify-center","opacity-0 group-hover:opacity-100 focus:opacity-100","focus:outline-none focus:ring-2 focus:ring-primary","transition-opacity")},e.createElement(X,{className:"w-3 h-3"})))))))}function Nt({placeholder:r,triggers:t,attachmentsCfg:o,formatList:s,showToolbar:n,isLoading:a,onStop:d,maxLength:h,autoFocus:m,submitOnEnter:R=true,leftActions:N,rightActions:L,hideSend:p,steps:y,trigger:k="mount",play:A,speed:I="normal",loop:x=false,loopDelay:X,onLoopReset:V,bare:G,className:q,onSubmit:$,onChange:W,readOnly:M,handleEditorReady:K,submitRef:c,restartRef:w,attachments:f,setAttachments:O,ingestImages:_}){let[l]=useLexicalComposerContext(),P=e.useRef(null),T=e.useRef(null),[te,se]=e.useState(false);e.useEffect(()=>{K(l);},[l,K]),e.useEffect(()=>{l.setEditable(!M);},[l,M]);let oe=e.useRef(W);oe.current=W,e.useEffect(()=>l.registerUpdateListener(({editorState:i})=>{i.read(()=>{let v=$getRoot().getTextContent();se(v.trim().length>0),oe.current?.(v);});}),[l]);let S=e.useCallback(()=>{if(a)return;let i=Ce(l),v=i.text.trim().length>0,u=f.length>0;!v&&!u||($?.(i,u?f:void 0),Z(l),f.forEach(J=>URL.revokeObjectURL(J.previewUrl)),O([]));},[l,a,f,$,O]);c.current=S;let{restart:C}=me({steps:y,speed:I,trigger:k,play:A,loop:x,loopDelay:X,containerRef:P,onLoopReset:()=>{Z(l),V?.();},interpret:async(i,v)=>{let u=v.signal;if(i.type==="wait")return E(i.ms,u);if(i.type==="clear")return Z(l),E(120,u);if(i.type==="newline")return l.update(()=>{let g=$getSelection();$isRangeSelection(g)&&g.insertParagraph();}),E(60,u);if(i.type==="submit")return S(),E(120,u);if(i.type==="format")return ve(l,i.format),l.update(()=>{let g=$getSelection();if(!$isRangeSelection(g)||g.isCollapsed())return;let D=g.focus;g.anchor.set(D.key,D.offset,D.type);}),E(80,u);if(i.type==="select")return wt(l,i.text),E(120,u);if(i.type==="mention")return i.query&&(l.update(()=>{let g=$getSelection();$isRangeSelection(g)&&g.insertText(i.trigger);}),await ue(i.query,g=>{l.update(()=>{let D=$getRoot(),Y=D.getTextContent(),B=Y.slice(0,Y.length-i.trigger.length-(g.length-1));D.clear();let Q=$createParagraphNode();B&&Q.append($createTextNode(B)),Q.append($createTextNode(i.trigger+g)),D.append(Q);});},v.speed.tokenStagger,u),await E(180,u),l.update(()=>{let g=$getRoot(),D=g.getTextContent(),Y=i.trigger.length+i.query.length,B=D.slice(0,D.length-Y);g.clear();let Q=$createParagraphNode();B&&Q.append($createTextNode(B)),g.append(Q),Q.select();})),Et(l,i.trigger,i.value),E(120,u);let J=i.speed?{slow:70,normal:22,fast:8}[i.speed]:v.speed.tokenStagger;for(let g=0;g<i.text.length;g++){if(u.aborted)return;let D=i.text[g];l.update(()=>{let Y=$getSelection();if(!$isRangeSelection(Y)){$getRoot().selectEnd();let B=$getSelection();$isRangeSelection(B)&&B.insertText(D);return}Y.insertText(D);}),g<i.text.length-1&&await E(J,u);}}});e.useEffect(()=>{w.current=i=>{Z(l),C(i);};},[l,C,w]);let le=!M&&!L&&!p,re=!M&&!N&&o!==null,ne=!M&&(re||N||le||L);return e.createElement("div",{ref:P,"data-gds-part":"composer","data-gds-loading":a?"true":"false",className:j("w-full",!G&&["rounded-md","bg-transparent","border border-input","shadow-sm","focus-within:outline-none focus-within:ring-1 focus-within:ring-ring","transition-colors"],q)},n&&e.createElement(St,{formats:s}),o&&e.createElement(Dt,{attachments:f,onRemove:i=>{O(v=>{let u=v.find(J=>J.id===i);return u&&URL.revokeObjectURL(u.previewUrl),v.filter(J=>J.id!==i)});}}),e.createElement("div",{className:"relative"},e.createElement(RichTextPlugin,{contentEditable:e.createElement(ContentEditable,{"data-gds-part":"composer-editor",className:j("outline-none","px-3 sm:px-4 py-3","text-sm text-[var(--gds-composer-fg)]","min-h-[44px] max-h-[300px] overflow-y-auto","[&_p]:m-0 [&_p+p]:mt-2","[&_h1]:text-xl [&_h1]:font-semibold [&_h1]:mt-2","[&_h2]:text-lg [&_h2]:font-semibold [&_h2]:mt-2","[&_h3]:text-base [&_h3]:font-semibold [&_h3]:mt-2","[&_ul]:list-disc [&_ul]:pl-5 [&_ol]:list-decimal [&_ol]:pl-5","[&_blockquote]:border-l-2 [&_blockquote]:border-[var(--gds-composer-border)] [&_blockquote]:pl-3 [&_blockquote]:italic","[&_code]:bg-[var(--gds-composer-toolbar-active-bg)] [&_code]:px-1 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono",a&&"opacity-60 pointer-events-none"),"aria-placeholder":r??"",placeholder:e.createElement("div",{"data-gds-part":"composer-placeholder",className:"absolute top-3 left-3 sm:left-4 text-sm text-muted-foreground pointer-events-none select-none"},r),spellCheck:true}),ErrorBoundary:LexicalErrorBoundary}),e.createElement(HistoryPlugin,null),e.createElement(ListPlugin,null),e.createElement(LinkPlugin,null),e.createElement(OnChangePlugin,{onChange:()=>{}}),e.createElement(Ct,{enabled:!!m}),e.createElement(Rt,{onSubmit:S,enabled:R}),o&&e.createElement(vt,{onImageFiles:_,enabled:true}),t.length>0&&e.createElement(BeautifulMentionsPlugin,{items:t.reduce((i,v)=>(typeof v.items=="function"||(i[v.char]=v.items.map(u=>({value:u.value}))),i),{})})),ne&&e.createElement("div",{"data-gds-part":"composer-actions",className:"flex items-center justify-between gap-2 px-2 pb-2 pt-1"},e.createElement("div",{className:"flex items-center gap-1"},N??(re&&e.createElement("button",{type:"button",onClick:()=>T.current?.click(),disabled:a,"aria-label":"Attach image",title:"Attach image",className:j("h-8 w-8 rounded-lg flex items-center justify-center","text-[var(--gds-composer-action-fg)]","hover:text-[var(--gds-composer-fg)]","hover:bg-[var(--gds-composer-toolbar-hover-bg)]","focus:outline-none focus:ring-2 focus:ring-primary","transition-colors","disabled:opacity-50 disabled:cursor-not-allowed")},e.createElement(Paperclip,{className:"w-4 h-4"})))),L??(le&&e.createElement("button",{type:"button",onClick:a?d:S,disabled:a?!d:!te&&f.length===0,"aria-label":a?"Stop":"Send",className:j("h-8 w-8 rounded-lg flex items-center justify-center transition-colors flex-shrink-0","focus:outline-none focus:ring-2 focus:ring-primary",a?"bg-red-500 hover:bg-red-600 text-white disabled:opacity-50":te||f.length>0?"bg-primary hover:bg-primary/90 text-primary-foreground":"bg-[var(--gds-composer-toolbar-active-bg)] text-[var(--gds-composer-muted-fg)] cursor-not-allowed")},a?e.createElement(Square,{className:"w-3.5 h-3.5"}):e.createElement(Send,{className:"w-3.5 h-3.5"}))),o&&e.createElement("input",{ref:T,type:"file",accept:o.accept,multiple:o.multiple,onChange:i=>{i.target.files&&_(Array.from(i.target.files)),i.target.value="";},className:"sr-only",tabIndex:-1,"aria-hidden":"true"})))}var Ee=e.forwardRef(function(t,o){let{initialText:s,initialJson:n,formats:a,toolbar:d,triggers:h,attachments:m,...R}=t,N=e.useMemo(()=>a===false?[]:a??["bold","italic","underline","strikethrough","code","h1","h2","blockquote","ul","ol"],[a]),L=d===true||d==="top",p=e.useMemo(()=>{if(!m)return null;let c=m===true?{}:m;return c.enabled===false?null:{enabled:true,accept:c.accept??"image/*",maxItems:c.maxItems??10,multiple:c.multiple??true}},[m]),[y,k]=e.useState([]),A=e.useRef(y);A.current=y,e.useEffect(()=>()=>{A.current.forEach(c=>URL.revokeObjectURL(c.previewUrl));},[]);let I=e.useCallback(c=>{if(!p)return;let w=c.filter(f=>p.accept?p.accept==="image/*"?f.type.startsWith("image/"):p.accept.split(",").some(O=>{let _=O.trim();return _.endsWith("/*")?f.type.startsWith(_.slice(0,-1)):f.type===_||f.name.toLowerCase().endsWith(_)}):true);w.length!==0&&k(f=>{let O=p.maxItems-f.length;if(O<=0)return f;let _=w.slice(0,O).map(l=>({id:`${l.name}-${l.size}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,file:l,previewUrl:URL.createObjectURL(l),name:l.name}));return [...f,..._]});},[p]),x=e.useRef(null),X=e.useRef(()=>{}),V=e.useRef(()=>{}),G=e.useCallback(c=>{x.current=c;},[]);e.useImperativeHandle(o,()=>({play:c=>{console.warn('[Composer] handle.play(steps) is not wired in v1 \u2014 pass `steps` + `trigger="manual"` and toggle `play` instead.');},stop:()=>{},restart:c=>V.current(c),focus:()=>x.current?.focus(),clear:()=>{let c=x.current;c&&Z(c);},insert:c=>{x.current?.update(()=>{let w=$getSelection();$isRangeSelection(w)&&w.insertText(c);});},getContent:()=>x.current?Ce(x.current):{text:"",json:"",mentions:[]},getEditor:()=>x.current}),[]);let q=e.useMemo(()=>({paragraph:"gds-composer-paragraph",quote:"gds-composer-quote",heading:{h1:"gds-composer-h1",h2:"gds-composer-h2",h3:"gds-composer-h3"},list:{ul:"gds-composer-ul",ol:"gds-composer-ol",listitem:"gds-composer-li"},text:{bold:"font-semibold",italic:"italic",underline:"underline",strikethrough:"line-through",code:"gds-composer-code"},beautifulMentions:{"@":"gds-composer-mention px-1.5 py-0.5 mx-0.5 rounded bg-primary/10 text-primary font-medium","/":"gds-composer-mention px-1.5 py-0.5 mx-0.5 rounded bg-violet-500/15 text-violet-600 dark:text-violet-400 font-medium"}}),[]),$=e.useMemo(()=>({namespace:"gds-composer",theme:q,onError:c=>{console.error("[Composer]",c);},nodes:[HeadingNode,QuoteNode,ListNode,ListItemNode,LinkNode,AutoLinkNode,CodeNode,CodeHighlightNode,BeautifulMentionNode],editorState:n||(s?c=>{let w=$getRoot(),f=$createParagraphNode();f.append($createTextNode(s)),w.append(f);}:void 0)}),[q,n,s]),W=N.length>0,{readOnly:M=false,...K}=R;return e.createElement(LexicalComposer,{initialConfig:{...$,editable:!M}},e.createElement(Nt,{...K,readOnly:M,triggers:h??[],attachmentsCfg:M?null:p,formatList:N,showToolbar:L&&W&&!M,handleEditorReady:G,submitRef:X,restartRef:V,attachments:y,setAttachments:k,ingestImages:I}))}),Mt=e.forwardRef(function(t,o){return e.createElement(Ee,{ref:o,placeholder:"Write a reply\u2026",formats:false,submitOnEnter:false,...t})});export{Ee as Composer,Mt as ComposerReply};//# sourceMappingURL=composer.mjs.map
3
+ //# sourceMappingURL=composer.mjs.map