@devalok/shilp-sutra 0.49.0 → 0.49.1

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.
Files changed (133) hide show
  1. package/dist/_chunks/badge-group.js +4 -4
  2. package/dist/_chunks/block-shell.js +1 -1
  3. package/dist/_chunks/chart-container.js +1 -1
  4. package/dist/_chunks/chat.js +3 -3
  5. package/dist/_chunks/colors.js +2 -2
  6. package/dist/_chunks/document-preview.js +4 -4
  7. package/dist/_chunks/emoji-suggestion.js +5 -5
  8. package/dist/_chunks/emoji-suggestion.js.map +1 -1
  9. package/dist/_chunks/emoji.js +1 -1
  10. package/dist/_chunks/field-state.js +1 -1
  11. package/dist/_chunks/grid-lines.js +1 -1
  12. package/dist/_chunks/image-preview.js +7 -7
  13. package/dist/_chunks/keybinding.js +1 -1
  14. package/dist/_chunks/link-context.js +1 -1
  15. package/dist/_chunks/mention-suggestion.js +2 -2
  16. package/dist/_chunks/mention.js +1 -1
  17. package/dist/_chunks/motion-provider.js +1 -1
  18. package/dist/_chunks/normalize-icon.js +1 -1
  19. package/dist/_chunks/oauth-button.js +2 -2
  20. package/dist/_chunks/popover.js +17 -17
  21. package/dist/_chunks/primitives.js +1 -1
  22. package/dist/_chunks/shared.js +5 -5
  23. package/dist/_chunks/success.js +4 -4
  24. package/dist/_chunks/tiptap.js +11 -11
  25. package/dist/_chunks/tooltip.js +1 -1
  26. package/dist/_chunks/tree-view.js +2 -2
  27. package/dist/_chunks/use-calendar.js +1 -1
  28. package/dist/_chunks/use-controllable-open.js +1 -1
  29. package/dist/_chunks/vendor-client.js +1 -1
  30. package/dist/_chunks/vendor-utils.js +1 -1
  31. package/dist/ai/block-renderer.js +7 -7
  32. package/dist/ai/blocks/error.js +1 -1
  33. package/dist/ai/blocks/index.js +2 -2
  34. package/dist/ai/blocks/text.js +1 -1
  35. package/dist/ai/command-bar.js +6 -6
  36. package/dist/ai/conversation.js +2 -2
  37. package/dist/ai/index.js +3 -3
  38. package/dist/composed/avatar-group.js +1 -1
  39. package/dist/composed/bulk-action-bar.js +1 -1
  40. package/dist/composed/command-palette.js +6 -6
  41. package/dist/composed/content-card.js +1 -1
  42. package/dist/composed/date-picker/index.js +10 -10
  43. package/dist/composed/emoji-picker.js +4 -4
  44. package/dist/composed/empty-state.js +1 -1
  45. package/dist/composed/extensions/emoji-node.js +1 -1
  46. package/dist/composed/extensions/emoji-suggestion.js +1 -1
  47. package/dist/composed/file-preview.js +14 -14
  48. package/dist/composed/filter-bar.js +1 -1
  49. package/dist/composed/multi-select-popover.js +3 -3
  50. package/dist/composed/priority-indicator.js +1 -1
  51. package/dist/composed/responsive-modal.js +21 -21
  52. package/dist/composed/rich-chat-input.js +445 -445
  53. package/dist/composed/rich-chat-input.js.map +1 -1
  54. package/dist/composed/rich-text-editor.js +28 -28
  55. package/dist/composed/status-badge.js +1 -1
  56. package/dist/motion/index.js +2 -2
  57. package/dist/shell/bottom-navbar.js +2 -2
  58. package/dist/shell/index.js +2 -2
  59. package/dist/shell/link-context.js +2 -2
  60. package/dist/shell/notification-center.js +3 -3
  61. package/dist/shell/sidebar.js +2 -2
  62. package/dist/shell/top-bar.js +1 -1
  63. package/dist/ui/accordion.js +14 -14
  64. package/dist/ui/alert-dialog.js +31 -31
  65. package/dist/ui/alert.js +1 -1
  66. package/dist/ui/aspect-ratio.js +1 -1
  67. package/dist/ui/autocomplete.js +7 -7
  68. package/dist/ui/avatar.js +15 -15
  69. package/dist/ui/badge-group.js +1 -1
  70. package/dist/ui/badge.js +1 -1
  71. package/dist/ui/banner.js +1 -1
  72. package/dist/ui/breadcrumb.js +1 -1
  73. package/dist/ui/button.js +5 -5
  74. package/dist/ui/card.js +1 -1
  75. package/dist/ui/charts/area-chart.js +6 -6
  76. package/dist/ui/charts/bar-chart.js +6 -6
  77. package/dist/ui/charts/chart-container.js +1 -1
  78. package/dist/ui/charts/gauge-chart.js +2 -2
  79. package/dist/ui/charts/index.js +2 -2
  80. package/dist/ui/charts/line-chart.js +6 -6
  81. package/dist/ui/charts/pie-chart.js +5 -5
  82. package/dist/ui/charts/radar-chart.js +5 -5
  83. package/dist/ui/charts/sparkline.js +2 -2
  84. package/dist/ui/chat/index.js +2 -2
  85. package/dist/ui/checkbox.js +5 -5
  86. package/dist/ui/collapsible.js +4 -4
  87. package/dist/ui/color-input.js +4 -4
  88. package/dist/ui/combobox.js +7 -7
  89. package/dist/ui/context-menu.js +41 -41
  90. package/dist/ui/dialog.js +25 -25
  91. package/dist/ui/dot.js +1 -1
  92. package/dist/ui/dropdown-menu.js +51 -51
  93. package/dist/ui/hover-card.js +9 -9
  94. package/dist/ui/icon-button.js +1 -1
  95. package/dist/ui/index.js +6 -6
  96. package/dist/ui/input.js +2 -2
  97. package/dist/ui/label.js +1 -1
  98. package/dist/ui/lib/utils.js +4 -4
  99. package/dist/ui/link.js +1 -1
  100. package/dist/ui/menubar.js +53 -53
  101. package/dist/ui/navigation-menu.js +27 -27
  102. package/dist/ui/number-input.js +2 -2
  103. package/dist/ui/oauth-button/index.js +2 -2
  104. package/dist/ui/pagination.js +1 -1
  105. package/dist/ui/popover.js +2 -2
  106. package/dist/ui/progress.js +2 -2
  107. package/dist/ui/radio.js +2 -2
  108. package/dist/ui/segmented-control.js +1 -1
  109. package/dist/ui/select.js +35 -35
  110. package/dist/ui/separator.js +1 -1
  111. package/dist/ui/sheet.js +22 -22
  112. package/dist/ui/sidebar.js +2 -2
  113. package/dist/ui/skeleton.js +1 -1
  114. package/dist/ui/slider.js +7 -7
  115. package/dist/ui/split-button.js +3 -3
  116. package/dist/ui/stat-card.js +2 -2
  117. package/dist/ui/stat-flash.js +1 -1
  118. package/dist/ui/stepper.js +1 -1
  119. package/dist/ui/surface.js +2 -2
  120. package/dist/ui/switch.js +2 -2
  121. package/dist/ui/table-row-link.js +1 -1
  122. package/dist/ui/tabs.js +13 -13
  123. package/dist/ui/text.js +1 -1
  124. package/dist/ui/textarea.js +2 -2
  125. package/dist/ui/toggle-group.js +1 -1
  126. package/dist/ui/toggle.js +2 -2
  127. package/dist/ui/tooltip.js +16 -16
  128. package/dist/ui/tree-view/index.js +2 -2
  129. package/llms.txt +1 -1
  130. package/mcp-manifest.json +1 -1
  131. package/package.json +1 -1
  132. package/skill/SKILL.md +1 -1
  133. package/skill/references/components.md +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"rich-chat-input.js","names":[],"sources":["../../src/composed/extensions/slash-command.tsx","../../src/composed/rich-chat-input/attachment-strip.tsx","../../src/composed/rich-chat-input/audio-waveform.tsx","../../src/composed/rich-chat-input/audio-player.tsx","../../src/composed/rich-chat-input/chat-toolbar.tsx","../../src/composed/rich-chat-input/recording-overlay.tsx","../../src/composed/rich-chat-input/reply-banner.tsx","../../src/composed/rich-chat-input/schedule-send.tsx","../../src/composed/rich-chat-input/use-voice-recorder.ts","../../src/composed/rich-chat-input.tsx"],"sourcesContent":["'use client'\n\nimport type { Editor } from '@tiptap/core'\nimport { Extension } from '@tiptap/core'\nimport Suggestion, { type SuggestionKeyDownProps,type SuggestionProps } from '@tiptap/suggestion'\nimport { PluginKey } from 'prosemirror-state'\nimport * as React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\n\nimport { cn } from '../../ui/lib/utils'\n\nexport interface SlashCommand {\n id: string\n label: string\n description?: string\n icon?: React.ComponentType<{ className?: string }>\n action: (editor: Editor) => void\n}\n\nexport interface SlashCommandGroup {\n label: string\n commands: SlashCommand[]\n}\n\n// ── Flat item used for keyboard navigation index ────────────────────\ninterface FlatItem {\n command: SlashCommand\n groupIndex: number\n}\n\ninterface SlashCommandListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface SlashCommandListProps {\n groups: SlashCommandGroup[]\n query: string\n command: (item: SlashCommand) => void\n}\n\nconst SlashCommandList = React.forwardRef<SlashCommandListRef, SlashCommandListProps>(\n ({ groups, query, command }, ref) => {\n const [selectedIndex, setSelectedIndex] = React.useState(0)\n\n // Flatten filtered groups into a single list for keyboard navigation\n const filtered = React.useMemo(() => {\n const q = query.toLowerCase()\n const flat: FlatItem[] = []\n groups.forEach((group, gi) => {\n group.commands.forEach((cmd) => {\n if (\n !q ||\n cmd.label.toLowerCase().includes(q) ||\n cmd.description?.toLowerCase().includes(q)\n ) {\n flat.push({ command: cmd, groupIndex: gi })\n }\n })\n })\n return flat\n }, [groups, query])\n\n React.useEffect(() => setSelectedIndex(0), [filtered])\n\n React.useImperativeHandle(ref, () => ({\n onKeyDown: ({ event }: SuggestionKeyDownProps) => {\n if (event.key === 'ArrowUp') {\n setSelectedIndex((i) => (i + filtered.length - 1) % filtered.length)\n return true\n }\n if (event.key === 'ArrowDown') {\n setSelectedIndex((i) => (i + 1) % filtered.length)\n return true\n }\n if (event.key === 'Enter') {\n if (filtered[selectedIndex]) command(filtered[selectedIndex].command)\n return true\n }\n return false\n },\n }))\n\n if (!filtered.length) return null\n\n // Re-group filtered items for rendering with group headers\n const renderedGroups: { label: string; items: { command: SlashCommand; flatIndex: number }[] }[] = []\n let flatIndex = 0\n for (const item of filtered) {\n const groupLabel = groups[item.groupIndex].label\n let last = renderedGroups[renderedGroups.length - 1]\n if (!last || last.label !== groupLabel) {\n last = { label: groupLabel, items: [] }\n renderedGroups.push(last)\n }\n last.items.push({ command: item.command, flatIndex })\n flatIndex++\n }\n\n return (\n <div\n role=\"listbox\"\n aria-label=\"Slash commands\"\n className=\"z-popover max-h-[320px] min-w-[220px] overflow-x-hidden overflow-y-auto rounded-surface bg-surface-overlay p-ds-02 shadow-floating\"\n >\n {renderedGroups.map((group, gi) => (\n <div key={group.label} role=\"group\" aria-label={group.label}>\n {gi > 0 && <div className=\"my-ds-01 border-t border-surface-border\" />}\n <div className=\"px-ds-03 py-ds-01 text-ds-xs font-medium text-surface-fg-subtle\">\n {group.label}\n </div>\n {group.items.map(({ command: cmd, flatIndex: fi }) => {\n const IconComp = cmd.icon\n return (\n <button\n key={cmd.id}\n type=\"button\"\n role=\"option\"\n aria-selected={fi === selectedIndex}\n onClick={() => command(cmd)}\n className={cn(\n 'flex w-full items-center gap-ds-03 rounded-control px-ds-03 py-ds-02 text-left cursor-pointer',\n fi === selectedIndex\n ? 'bg-surface-raised-hover'\n : 'hover:bg-surface-raised-hover',\n )}\n >\n {IconComp && (\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center text-surface-fg-muted\">\n <IconComp className=\"h-4 w-4\" />\n </span>\n )}\n <div className=\"flex flex-col\">\n <span className=\"text-ds-sm text-surface-fg\">{cmd.label}</span>\n {cmd.description && (\n <span className=\"text-ds-xs text-surface-fg-subtle\">{cmd.description}</span>\n )}\n </div>\n </button>\n )\n })}\n </div>\n ))}\n </div>\n )\n },\n)\nSlashCommandList.displayName = 'SlashCommandList'\n\nfunction createSlashCommandRenderer(groups: SlashCommandGroup[]) {\n return () => {\n let root: Root | null = null\n let container: HTMLDivElement | null = null\n let componentRef: SlashCommandListRef | null = null\n\n return {\n onStart: (props: SuggestionProps<SlashCommand>) => {\n container = document.createElement('div')\n container.style.position = 'absolute'\n container.style.zIndex = '1400' // z-popover\n\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n document.body.appendChild(container)\n\n root = createRoot(container)\n root.render(\n <SlashCommandList\n ref={(r) => { componentRef = r }}\n groups={groups}\n query={props.query}\n command={(cmd) => props.command(cmd as any)}\n />,\n )\n },\n\n onUpdate: (props: SuggestionProps<SlashCommand>) => {\n if (!root || !container) return\n\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n\n root.render(\n <SlashCommandList\n ref={(r) => { componentRef = r }}\n groups={groups}\n query={props.query}\n command={(cmd) => props.command(cmd as any)}\n />,\n )\n },\n\n onKeyDown: (props: SuggestionKeyDownProps) => {\n if (props.event.key === 'Escape') {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n return true\n }\n return componentRef?.onKeyDown(props) ?? false\n },\n\n onExit: () => {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n },\n }\n }\n}\n\n/**\n * Creates a configured TipTap Extension for slash commands.\n *\n * Triggers on `/` at the start of a line, shows a grouped command palette,\n * and executes the selected command's action on the editor.\n *\n * @example\n * const slashExt = createSlashCommandExtension([\n * {\n * label: 'Format',\n * commands: [\n * { id: 'h1', label: 'Heading 1', action: (editor) => editor.chain().focus().toggleHeading({ level: 1 }).run() },\n * { id: 'bullet', label: 'Bullet List', action: (editor) => editor.chain().focus().toggleBulletList().run() },\n * ],\n * },\n * ])\n */\nexport function createSlashCommandExtension(groups: SlashCommandGroup[]) {\n // Flatten all commands for the items callback\n const allCommands = groups.flatMap((g) => g.commands)\n\n return Extension.create({\n name: 'slashCommand',\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n pluginKey: new PluginKey('slashCommand'),\n editor: this.editor,\n char: '/',\n startOfLine: true,\n allowSpaces: false,\n items: ({ query }) => {\n if (!query) return allCommands.slice(0, 8)\n const q = query.toLowerCase()\n return allCommands\n .filter(\n (cmd) =>\n cmd.label.toLowerCase().includes(q) ||\n cmd.description?.toLowerCase().includes(q),\n )\n .slice(0, 8)\n },\n command: ({ editor, range, props: item }) => {\n // Delete the /query text, then execute the command action\n editor.chain().focus().deleteRange(range).run()\n ;(item as unknown as SlashCommand).action(editor)\n },\n render: createSlashCommandRenderer(groups),\n }),\n ]\n },\n })\n}\n","'use client'\n\nimport { IconFile,IconX } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { durations } from '../../ui/lib/motion'\nimport { Spinner } from '../../ui/spinner'\nimport { TruncatedText } from '../../ui/truncated-text'\n\nexport interface Attachment {\n id: string\n url?: string\n name: string\n size: number\n type: 'image' | 'file'\n uploading: boolean\n}\n\nexport interface AttachmentStripProps {\n attachments: Attachment[]\n onRemoveAttachment: (id: string) => void\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nexport function AttachmentStrip({\n attachments,\n onRemoveAttachment,\n}: AttachmentStripProps) {\n return (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: durations.moderate02, ease: [0.2, 0, 0.38, 0.9] }}\n className=\"overflow-hidden\"\n >\n <div\n role=\"list\"\n aria-label=\"Attachments\"\n className=\"flex gap-ds-02 overflow-x-auto px-ds-04 py-ds-02b border-b border-surface-border\"\n >\n <AnimatePresence initial={false}>\n {attachments.map((att) =>\n att.type === 'image' ? (\n <motion.div\n key={att.id}\n role=\"listitem\"\n aria-label={`Image: ${att.name}`}\n layout\n initial={{ scale: 0, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.95, opacity: 0 }}\n transition={{\n /* Near springs.snappy (500/30/0.5) — intentionally softer for thumbnail pop-in */\n layout: { type: 'spring', stiffness: 400, damping: 30 },\n scale: { type: 'spring', stiffness: 400, damping: 30 },\n opacity: { duration: durations.fast02 },\n }}\n /* h-12 w-12 (48px): component-specific thumbnail size — no design token equivalent */\n className=\"relative h-12 w-12 shrink-0 group\"\n >\n <img\n src={att.url}\n alt={att.name}\n className=\"h-full w-full rounded-control object-cover\"\n />\n <button\n onClick={() => onRemoveAttachment(att.id)}\n className=\"absolute -top-1 -right-1 h-ico-sm w-ico-sm rounded-pill bg-error-9 text-error-fg flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-fast-02\"\n aria-label={`Remove ${att.name}`}\n title=\"Remove\"\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n {att.uploading && (\n <div className=\"absolute inset-0 rounded-control bg-surface-overlay/50 flex items-center justify-center\">\n <Spinner size=\"sm\" />\n </div>\n )}\n </motion.div>\n ) : (\n <motion.div\n key={att.id}\n role=\"listitem\"\n aria-label={`File: ${att.name}, ${formatSize(att.size)}`}\n layout\n initial={{ scale: 0, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.95, opacity: 0 }}\n transition={{\n /* Near springs.snappy (500/30/0.5) — intentionally softer for file chip pop-in */\n layout: { type: 'spring', stiffness: 400, damping: 30 },\n scale: { type: 'spring', stiffness: 400, damping: 30 },\n opacity: { duration: durations.fast02 },\n }}\n className=\"flex items-center gap-ds-02 shrink-0 rounded-control bg-surface-raised px-ds-03 py-ds-01 group\"\n >\n <Icon\n icon={IconFile}\n size=\"xs\"\n className=\"text-surface-fg-muted\"\n />\n {/* max-w-[120px]: component-specific truncation width for file names */}\n <TruncatedText mode=\"middle\" className=\"max-w-[120px] text-ds-xs text-surface-fg-muted\">\n {att.name}\n </TruncatedText>\n <span className=\"text-ds-xs text-surface-fg-subtle\">\n {formatSize(att.size)}\n </span>\n <button\n onClick={() => onRemoveAttachment(att.id)}\n className=\"text-surface-fg-subtle hover:text-error-11 opacity-0 group-hover:opacity-100 transition-opacity duration-fast-02\"\n aria-label={`Remove ${att.name}`}\n title=\"Remove\"\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n </motion.div>\n )\n )}\n </AnimatePresence>\n </div>\n </motion.div>\n )\n}\n","'use client'\n\nimport * as React from 'react'\n\nimport { cn } from '../../ui/lib/utils'\n\ninterface AudioWaveformProps extends React.SVGAttributes<SVGSVGElement> {\n /** 'live' reads from AnalyserNode in real-time. 'static' renders pre-computed data. */\n mode: 'live' | 'static'\n /** Web Audio API analyser node — required for live mode */\n analyserNode?: AnalyserNode | null\n /** Pre-computed amplitude data (0-1 normalized) — required for static mode */\n data?: number[]\n /** Playback progress 0-1 — static mode only, controls fill coloring */\n progress?: number\n /** Bar width in pixels @default 3 */\n barWidth?: number\n /** Gap between bars in pixels @default 2 */\n barGap?: number\n /** Number of bars to render @default 40 */\n barCount?: number\n /** Height in pixels @default 32 */\n height?: number\n}\n\nconst AudioWaveform = React.forwardRef<SVGSVGElement, AudioWaveformProps>(\n function AudioWaveform(\n {\n mode,\n analyserNode,\n data,\n progress = 0,\n barWidth = 3,\n barGap = 2,\n barCount = 40,\n height = 32,\n className,\n ...props\n },\n ref\n ) {\n const [bars, setBars] = React.useState<number[]>(() =>\n new Array(barCount).fill(0.05)\n )\n const animFrameRef = React.useRef<number>(0)\n const prevBarsRef = React.useRef<number[]>(bars)\n\n // Live mode — read from AnalyserNode on each animation frame\n React.useEffect(() => {\n if (mode !== 'live' || !analyserNode) return\n\n const dataArray = new Uint8Array(analyserNode.frequencyBinCount)\n const smoothingFactor = 0.3\n\n const tick = () => {\n analyserNode.getByteFrequencyData(dataArray)\n\n const barsPerBin = Math.floor(dataArray.length / barCount)\n const newBars = new Array(barCount)\n\n for (let i = 0; i < barCount; i++) {\n let sum = 0\n for (let j = 0; j < barsPerBin; j++) {\n sum += dataArray[i * barsPerBin + j]\n }\n const target = sum / (barsPerBin * 255)\n newBars[i] =\n prevBarsRef.current[i] +\n (target - prevBarsRef.current[i]) * smoothingFactor\n }\n\n prevBarsRef.current = newBars\n setBars(newBars)\n animFrameRef.current = requestAnimationFrame(tick)\n }\n\n animFrameRef.current = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(animFrameRef.current)\n }, [mode, analyserNode, barCount])\n\n // Static mode — resample pre-computed data to barCount bars\n React.useEffect(() => {\n if (mode !== 'static' || !data) return\n\n if (data.length === barCount) {\n setBars(data)\n } else {\n const resampled = new Array(barCount)\n const ratio = data.length / barCount\n for (let i = 0; i < barCount; i++) {\n const index = Math.floor(i * ratio)\n resampled[i] = data[Math.min(index, data.length - 1)]\n }\n setBars(resampled)\n }\n }, [mode, data, barCount])\n\n const svgWidth = barCount * (barWidth + barGap) - barGap\n\n const renderedBars = React.useMemo(\n () =>\n bars.map((amplitude, i) => {\n const barHeight = Math.max(2, amplitude * height)\n const x = i * (barWidth + barGap)\n const y = (height - barHeight) / 2\n const isFilled =\n mode === 'static' && progress > 0 && i / barCount <= progress\n\n return (\n <rect\n key={i}\n x={x}\n y={y}\n width={barWidth}\n height={barHeight}\n rx={barWidth / 2}\n fill={\n isFilled\n ? 'var(--color-accent-9)'\n : 'var(--color-surface-border)'\n }\n />\n )\n }),\n [bars, progress, mode, barWidth, barGap, barCount, height]\n )\n\n return (\n <svg\n ref={ref}\n height={height}\n viewBox={`0 0 ${svgWidth} ${height}`}\n preserveAspectRatio=\"none\"\n aria-hidden=\"true\"\n className={cn('shrink-0', className)}\n {...props}\n >\n {renderedBars}\n </svg>\n )\n }\n)\nAudioWaveform.displayName = 'AudioWaveform'\n\nexport { AudioWaveform }\nexport type { AudioWaveformProps }\n","'use client'\n\nimport { IconPlayerPause,IconPlayerPlay } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Button } from '../../ui/button'\nimport { cn } from '../../ui/lib/utils'\nimport { AudioWaveform } from './audio-waveform'\n\ninterface AudioPlayerProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n src: string | Blob\n duration: number\n waveformData?: number[]\n}\n\nconst SPEEDS = [1, 1.5, 2] as const\n\nfunction formatTime(seconds: number): string {\n const m = Math.floor(seconds / 60)\n const s = Math.floor(seconds % 60)\n return `${m}:${s.toString().padStart(2, '0')}`\n}\n\nconst AudioPlayer = React.forwardRef<HTMLDivElement, AudioPlayerProps>(\n function AudioPlayer({ src, duration, waveformData, className, ...props }, ref) {\n const audioRef = React.useRef<HTMLAudioElement>(null)\n const waveformRef = React.useRef<SVGSVGElement>(null)\n const [playing, setPlaying] = React.useState(false)\n const [currentTime, setCurrentTime] = React.useState(0)\n const [speedIndex, setSpeedIndex] = React.useState(0)\n const [objectUrl, setObjectUrl] = React.useState<string | null>(null)\n\n // Resolve src to a URL string, managing Blob object URLs\n const audioSrc = React.useMemo(() => {\n if (typeof src === 'string') return src\n const url = URL.createObjectURL(src)\n setObjectUrl(url)\n return url\n }, [src])\n\n // Revoke object URL on src change or unmount\n React.useEffect(() => {\n return () => {\n if (objectUrl) {\n URL.revokeObjectURL(objectUrl)\n }\n }\n }, [objectUrl])\n\n // Sync audio timeupdate to state\n React.useEffect(() => {\n const audio = audioRef.current\n if (!audio) return\n\n const onTimeUpdate = () => setCurrentTime(audio.currentTime)\n const onEnded = () => {\n setPlaying(false)\n setCurrentTime(0)\n }\n\n audio.addEventListener('timeupdate', onTimeUpdate)\n audio.addEventListener('ended', onEnded)\n return () => {\n audio.removeEventListener('timeupdate', onTimeUpdate)\n audio.removeEventListener('ended', onEnded)\n }\n }, [])\n\n const togglePlay = React.useCallback(() => {\n const audio = audioRef.current\n if (!audio) return\n\n if (playing) {\n audio.pause()\n setPlaying(false)\n } else {\n audio.play()\n setPlaying(true)\n }\n }, [playing])\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault()\n togglePlay()\n }\n },\n [togglePlay]\n )\n\n const handleSeek = React.useCallback(\n (e: React.MouseEvent<SVGSVGElement>) => {\n const audio = audioRef.current\n const svg = waveformRef.current\n if (!audio || !svg || duration <= 0) return\n\n const rect = svg.getBoundingClientRect()\n const x = e.clientX - rect.left\n const ratio = Math.max(0, Math.min(1, x / rect.width))\n audio.currentTime = ratio * duration\n setCurrentTime(audio.currentTime)\n },\n [duration]\n )\n\n const cycleSpeed = React.useCallback(() => {\n const next = (speedIndex + 1) % SPEEDS.length\n setSpeedIndex(next)\n if (audioRef.current) {\n audioRef.current.playbackRate = SPEEDS[next]\n }\n }, [speedIndex])\n\n const progress = duration > 0 ? currentTime / duration : 0\n const speed = SPEEDS[speedIndex]\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label=\"Voice message player\"\n className={cn('flex items-center gap-ds-03', className)}\n {...props}\n >\n {/* Hidden audio element — captions not applicable for voice messages */}\n {/* eslint-disable-next-line jsx-a11y/media-has-caption */}\n <audio ref={audioRef} src={audioSrc} preload=\"metadata\" />\n\n {/* Play/Pause button */}\n <Button\n type=\"button\"\n variant=\"solid\"\n shape=\"pill\"\n size=\"icon-sm\"\n onClick={togglePlay}\n onKeyDown={handleKeyDown}\n aria-label={playing ? 'Pause voice message' : 'Play voice message'}\n className=\"shrink-0 active:scale-95\"\n >\n {playing ? (\n <IconPlayerPause size={16} stroke={2} aria-hidden=\"true\" />\n ) : (\n <IconPlayerPlay size={16} stroke={2} aria-hidden=\"true\" />\n )}\n </Button>\n\n {/* Waveform with seek */}\n <AudioWaveform\n ref={waveformRef}\n mode=\"static\"\n data={waveformData}\n progress={progress}\n className=\"cursor-pointer\"\n onClick={handleSeek}\n />\n\n {/* Duration display */}\n <span className=\"text-ds-xs tabular-nums text-surface-fg-subtle whitespace-nowrap\">\n {formatTime(currentTime)} / {formatTime(duration)}\n </span>\n\n {/* Speed control */}\n <button\n type=\"button\"\n onClick={cycleSpeed}\n aria-label={`Playback speed ${speed}x`}\n className=\"shrink-0 text-ds-xs bg-surface-raised rounded-pill px-ds-02 py-[1px] hover:bg-surface-raised-hover tabular-nums transition-colors duration-fast-01 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2\"\n >\n {speed}x\n </button>\n </div>\n )\n }\n)\nAudioPlayer.displayName = 'AudioPlayer'\n\nexport { AudioPlayer }\nexport type { AudioPlayerProps }\n","'use client'\n\nimport {\n IconAt,\n IconBlockquote,\n IconBold,\n IconCode,\n IconHighlight,\n IconItalic,\n IconLink,\n IconList,\n IconListNumbers,\n IconMoodSmile,\n IconSlash,\n IconStrikethrough,\n IconUnderline,\n} from '@tabler/icons-react'\n// motion removed — CSS transitions handle show/hide from parent\nimport type { Editor } from '@tiptap/core'\nimport { useEditorState } from '@tiptap/react'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { cn } from '../../ui/lib/utils'\n\n// ── Toolbar Context ─────────────────────────────────────────────\n// Shares the TipTap editor instance with all toolbar primitives\n\nconst ToolbarContext = React.createContext<{ editor: Editor; disabled: boolean } | null>(null)\n\nfunction useToolbarEditor() {\n const ctx = React.useContext(ToolbarContext)\n if (!ctx) throw new Error('Toolbar primitives must be used inside <ChatToolbar>')\n return ctx\n}\n\n// ── Toolbar Primitives (exported for custom toolbars) ───────────\n\n/**\n * A single toolbar button. Use for built-in or custom actions.\n *\n * @example\n * <ToolbarButton onClick={() => editor.chain().focus().toggleBold().run()} isActive={editor.isActive('bold')} title=\"Bold\">\n * <Icon icon={IconBold} size=\"xs\" />\n * </ToolbarButton>\n */\nexport function ToolbarButton({\n onClick,\n isActive,\n disabled: disabledProp,\n title,\n children,\n className: classNameProp,\n}: {\n onClick: () => void\n isActive?: boolean\n disabled?: boolean\n title: string\n children: React.ReactNode\n className?: string\n}) {\n const { disabled: ctxDisabled } = useToolbarEditor()\n const isDisabled = disabledProp ?? ctxDisabled\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={isDisabled}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n className={cn(\n 'inline-flex h-ds-xs-plus items-center justify-center rounded-control touch-target',\n !classNameProp?.includes('w-') && 'w-ds-xs-plus',\n 'transition-[color,background-color,transform] duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover hover:text-surface-fg',\n 'active:scale-95',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n isActive ? 'bg-surface-raised-hover text-accent-11' : 'text-surface-fg-subtle',\n classNameProp,\n )}\n >\n {children}\n </button>\n )\n}\n\n/** Visual separator between toolbar button groups. */\nexport function ToolbarDivider() {\n return <div className=\"h-4 w-px bg-surface-border-subtle mx-ds-01\" />\n}\n\n/** Group wrapper — applies consistent spacing to a set of buttons. */\nexport function ToolbarGroup({ children, className }: { children: React.ReactNode; className?: string }) {\n return <div className={cn('flex items-center gap-ds-01', className)}>{children}</div>\n}\n\n// ── Pre-built Formatting Buttons (convenience exports) ──────────\n// Each reads the editor from context and wires the correct command.\n\nexport function BoldButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('bold') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBold().run()} isActive={isActive} title=\"Bold\">\n <Icon icon={IconBold} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function ItalicButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('italic') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleItalic().run()} isActive={isActive} title=\"Italic\">\n <Icon icon={IconItalic} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function UnderlineButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('underline') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleUnderline().run()} isActive={isActive} title=\"Underline\">\n <Icon icon={IconUnderline} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function StrikeButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('strike') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleStrike().run()} isActive={isActive} title=\"Strikethrough\">\n <Icon icon={IconStrikethrough} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function HighlightButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('highlight') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHighlight().run()} isActive={isActive} title=\"Highlight\">\n <Icon icon={IconHighlight} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function CodeButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('code') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleCode().run()} isActive={isActive} title=\"Inline code\">\n <Icon icon={IconCode} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function BulletListButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('bulletList') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBulletList().run()} isActive={isActive} title=\"Bullet list\">\n <Icon icon={IconList} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function OrderedListButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('orderedList') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleOrderedList().run()} isActive={isActive} title=\"Ordered list\">\n <Icon icon={IconListNumbers} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function BlockquoteButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('blockquote') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBlockquote().run()} isActive={isActive} title=\"Quote\">\n <Icon icon={IconBlockquote} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function LinkButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('link') }),\n })\n return (\n <ToolbarButton\n onClick={() => {\n const url = window.prompt('URL')\n if (url) editor.chain().focus().setLink({ href: url }).run()\n }}\n isActive={isActive}\n title=\"Link\"\n >\n <Icon icon={IconLink} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function MentionButton() {\n const { editor } = useToolbarEditor()\n return (\n <ToolbarButton onClick={() => editor.chain().focus().insertContent('@').run()} title=\"Mention\">\n <Icon icon={IconAt} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function EmojiButton() {\n const { editor } = useToolbarEditor()\n return (\n <ToolbarButton onClick={() => editor.chain().focus().insertContent(':').run()} title=\"Emoji\">\n <Icon icon={IconMoodSmile} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function SlashCommandButton() {\n const { editor } = useToolbarEditor()\n return (\n <ToolbarButton onClick={() => editor.chain().focus().insertContent('/').run()} title=\"Slash command\">\n <Icon icon={IconSlash} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\n// ── Default Toolbar Presets ─────────────────────────────────────\n\nexport type ChatToolbarItem =\n | 'bold' | 'italic' | 'underline' | 'strike' | 'highlight' | 'code'\n | 'bulletList' | 'orderedList'\n | 'blockquote' | 'link'\n | 'mention' | 'emoji' | 'slash'\n\n/** The default toolbar layout — used when `toolbar={true}` or `toolbar={[...items]}` */\nfunction DefaultToolbar({ items, isMobile, hasMentions, hasSlashCommands }: {\n items: ChatToolbarItem[] | null\n isMobile: boolean\n hasMentions: boolean\n hasSlashCommands: boolean\n}) {\n const show = (item: ChatToolbarItem) => !items || items.includes(item)\n\n return (\n <>\n {/* Inline formatting — desktop only */}\n {!isMobile && (\n <ToolbarGroup>\n {show('bold') && <BoldButton />}\n {show('italic') && <ItalicButton />}\n {show('underline') && <UnderlineButton />}\n {show('strike') && <StrikeButton />}\n {show('highlight') && <HighlightButton />}\n </ToolbarGroup>\n )}\n\n {!isMobile && <ToolbarDivider />}\n\n {/* Lists — desktop only */}\n {!isMobile && (\n <ToolbarGroup>\n {show('bulletList') && <BulletListButton />}\n {show('orderedList') && <OrderedListButton />}\n </ToolbarGroup>\n )}\n\n {!isMobile && (show('blockquote') || show('link') || show('code')) && <ToolbarDivider />}\n\n {/* Block insert — desktop only */}\n {!isMobile && (\n <ToolbarGroup>\n {show('blockquote') && <BlockquoteButton />}\n {show('link') && <LinkButton />}\n {show('code') && <CodeButton />}\n </ToolbarGroup>\n )}\n\n {!isMobile && (hasMentions || hasSlashCommands) && <ToolbarDivider />}\n\n {/* Insert group — always visible */}\n <ToolbarGroup>\n {hasMentions && show('mention') && <MentionButton />}\n {show('emoji') && <EmojiButton />}\n {hasSlashCommands && show('slash') && <SlashCommandButton />}\n </ToolbarGroup>\n </>\n )\n}\n\n// ── ChatToolbar (main component) ────────────────────────────────\n\nexport interface ChatToolbarProps {\n editor: Editor\n /** true = default layout, ChatToolbarItem[] = whitelist, false = hidden, ReactNode = custom */\n toolbar: boolean | ChatToolbarItem[] | React.ReactNode\n isMobile: boolean\n hasMentions: boolean\n hasSlashCommands: boolean\n disabled: boolean\n}\n\nexport function ChatToolbar({\n editor,\n toolbar,\n isMobile,\n hasMentions,\n hasSlashCommands,\n disabled,\n}: ChatToolbarProps) {\n // toolbar={false} → don't render\n if (toolbar === false) return null\n\n const isCustom = typeof toolbar !== 'boolean' && !Array.isArray(toolbar)\n const items = Array.isArray(toolbar) ? toolbar : null\n\n return (\n <ToolbarContext.Provider value={{ editor, disabled }}>\n <div\n role=\"toolbar\"\n aria-label=\"Text formatting\"\n className=\"flex flex-wrap items-center gap-ds-01 border-t border-surface-border px-ds-04 py-ds-02b\"\n >\n {isCustom ? (\n // Consumer provides their own toolbar content\n toolbar\n ) : (\n // Default layout (full or whitelist)\n <DefaultToolbar items={items} isMobile={isMobile} hasMentions={hasMentions} hasSlashCommands={hasSlashCommands} />\n )}\n </div>\n </ToolbarContext.Provider>\n )\n}\n","'use client'\n\nimport { useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { cn } from '../../ui/lib/utils'\nimport { AudioWaveform } from './audio-waveform'\n\ninterface RecordingOverlayProps {\n duration: number\n analyserNode: AnalyserNode | null\n maxDuration?: number\n /** Escape key handler — cancel recording. Stop/cancel buttons are external. */\n onCancel: () => void\n}\n\nfunction formatTimer(seconds: number): { minutes: string; separator: string; secs: string } {\n const m = Math.floor(seconds / 60)\n const s = Math.floor(seconds % 60)\n return {\n minutes: String(m),\n separator: ':',\n secs: s.toString().padStart(2, '0'),\n }\n}\n\nfunction RecordingOverlay({\n duration,\n analyserNode,\n maxDuration,\n onCancel,\n}: RecordingOverlayProps) {\n const prefersReduced = useReducedMotion()\n\n // Escape key cancels recording\n React.useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onCancel()\n }\n }\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [onCancel])\n\n // Timing states\n const isWarning = maxDuration != null && maxDuration > 0 && duration >= maxDuration - 10\n const isCritical = maxDuration != null && maxDuration > 0 && duration >= maxDuration - 5\n\n // Pulse speed: faster when critical\n const pulseAnimation = isCritical\n ? 'animate-[pulse_500ms_ease-in-out_infinite]'\n : 'animate-[pulse_1s_ease-in-out_infinite]'\n\n const timer = formatTimer(duration)\n\n const timerColorClass = isCritical\n ? 'text-error-11'\n : isWarning\n ? 'text-warning-11'\n : 'text-surface-fg'\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Recording voice message\"\n className=\"absolute inset-0 flex items-center gap-ds-03 px-ds-04 py-ds-03 bg-surface-raised-hover rounded-surface z-10\"\n >\n {/* Red pulsing dot */}\n <span\n className={cn(\n 'w-ds-02b h-ds-02b shrink-0 rounded-pill bg-error-9',\n prefersReduced ? 'opacity-100' : pulseAnimation\n )}\n aria-hidden=\"true\"\n />\n\n {/* Timer */}\n <span\n className={cn(\n 'text-ds-sm font-mono tabular-nums whitespace-nowrap',\n timerColorClass\n )}\n aria-label={`${timer.minutes} minutes ${timer.secs} seconds`}\n >\n {timer.minutes}\n <span\n className={prefersReduced ? undefined : 'animate-[blink_1s_step-end_infinite]'}\n aria-hidden=\"true\"\n >\n {timer.separator}\n </span>\n {timer.secs}\n </span>\n\n {/* Live waveform — stop/cancel buttons are external (right-side button area) */}\n <div className=\"flex-1 min-w-0 overflow-hidden\">\n <AudioWaveform\n mode=\"live\"\n analyserNode={analyserNode}\n height={24}\n barCount={60}\n className=\"w-full\"\n />\n </div>\n </div>\n )\n}\nRecordingOverlay.displayName = 'RecordingOverlay'\n\nexport { RecordingOverlay }\nexport type { RecordingOverlayProps }\n","'use client'\n\nimport { IconX } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { durations } from '../../ui/lib/motion'\nimport { cn } from '../../ui/lib/utils'\n\nexport interface ReplyBannerProps {\n author: string\n preview: string\n onDismiss: () => void\n}\n\nexport function ReplyBanner({ author, preview, onDismiss }: ReplyBannerProps) {\n return (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: durations.moderate02, ease: [0.2, 0, 0.38, 0.9] }}\n className=\"overflow-hidden\"\n >\n <div\n role=\"status\"\n aria-label={`Replying to ${author}`}\n className=\"flex items-center gap-ds-03 border-b border-surface-border px-ds-04 py-ds-02b\"\n >\n <div className=\"flex-1 min-w-0\">\n <span className=\"text-ds-sm font-semibold text-surface-fg\">\n Replying to {author}\n </span>\n <span className=\"mx-ds-02 text-surface-fg-subtle\">&middot;</span>\n <span className=\"text-ds-sm text-surface-fg-muted truncate\">\n {preview}\n </span>\n </div>\n <button\n type=\"button\"\n onClick={onDismiss}\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control touch-target',\n 'text-surface-fg-subtle hover:text-surface-fg hover:bg-surface-raised-hover',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'active:scale-95',\n )}\n aria-label=\"Cancel reply\"\n title=\"Cancel reply\"\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n </div>\n </motion.div>\n )\n}\n","'use client'\n\nimport { IconCalendarEvent, IconClock, IconPencil,IconX } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../../ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/dialog'\nimport { Icon } from '../../ui/icon'\nimport { durations } from '../../ui/lib/motion'\nimport { ToggleGroup, ToggleGroupItem } from '../../ui/toggle-group'\nimport { CalendarGrid } from '../date-picker/calendar-grid'\nimport { useCalendar } from '../date-picker/use-calendar'\n\n// ── Smart Presets ──────────────────────────────────────────────\n\ninterface PresetOption {\n label: string\n date: Date\n}\n\nfunction getSmartPresets(): PresetOption[] {\n const now = new Date()\n const hour = now.getHours()\n const presets: PresetOption[] = []\n\n const nextTime = (targetHour: number, daysAhead = 0) => {\n const d = new Date(now)\n d.setDate(d.getDate() + daysAhead)\n d.setHours(targetHour, 0, 0, 0)\n return d\n }\n\n const nextMonday = (targetHour: number) => {\n const d = new Date(now)\n const dayOfWeek = d.getDay()\n const daysUntilMonday = dayOfWeek === 0 ? 1 : dayOfWeek === 1 ? 7 : 8 - dayOfWeek\n d.setDate(d.getDate() + daysUntilMonday)\n d.setHours(targetHour, 0, 0, 0)\n return d\n }\n\n if (hour < 9) {\n presets.push({ label: 'Later this morning · 9:00 AM', date: nextTime(9) })\n presets.push({ label: 'This afternoon · 1:00 PM', date: nextTime(13) })\n presets.push({ label: 'This evening · 6:00 PM', date: nextTime(18) })\n } else if (hour < 13) {\n presets.push({ label: 'This afternoon · 1:00 PM', date: nextTime(13) })\n presets.push({ label: 'This evening · 6:00 PM', date: nextTime(18) })\n presets.push({ label: 'Tomorrow morning · 9:00 AM', date: nextTime(9, 1) })\n } else if (hour < 18) {\n presets.push({ label: 'This evening · 6:00 PM', date: nextTime(18) })\n presets.push({ label: 'Tomorrow morning · 9:00 AM', date: nextTime(9, 1) })\n presets.push({ label: 'Tomorrow afternoon · 1:00 PM', date: nextTime(13, 1) })\n } else {\n presets.push({ label: 'Tomorrow morning · 9:00 AM', date: nextTime(9, 1) })\n presets.push({ label: 'Tomorrow afternoon · 1:00 PM', date: nextTime(13, 1) })\n }\n\n const monday = nextMonday(9)\n if (monday.getTime() - now.getTime() > 2 * 24 * 60 * 60 * 1000) {\n presets.push({ label: 'Next Monday · 9:00 AM', date: monday })\n }\n\n return presets\n}\n\n// ── Inline Time Selector (hour, minute, AM/PM) ────────────────\n\nfunction InlineTimePicker({ value, onChange }: { value: Date; onChange: (d: Date) => void }) {\n const hours12 = value.getHours() % 12 || 12\n const minutes = value.getMinutes()\n const isPM = value.getHours() >= 12\n\n const setHour = (h: number) => {\n const d = new Date(value)\n d.setHours(isPM ? (h % 12) + 12 : h % 12)\n onChange(d)\n }\n\n const setMinute = (m: number) => {\n const d = new Date(value)\n d.setMinutes(m)\n onChange(d)\n }\n\n const togglePeriod = (pm: boolean) => {\n const d = new Date(value)\n const h = d.getHours()\n if (pm && h < 12) d.setHours(h + 12)\n else if (!pm && h >= 12) d.setHours(h - 12)\n onChange(d)\n }\n\n return (\n <div className=\"flex items-center gap-ds-02\">\n {/* Hour */}\n <select\n value={hours12}\n onChange={(e) => setHour(Number(e.target.value))}\n className=\"h-ds-sm rounded-control border border-surface-border-strong bg-surface-raised px-ds-02 text-ds-sm text-surface-fg focus:outline-hidden focus:ring-2 focus:ring-accent-9\"\n aria-label=\"Hour\"\n >\n {Array.from({ length: 12 }, (_, i) => i + 1).map((h) => (\n <option key={h} value={h}>{h}</option>\n ))}\n </select>\n\n <span className=\"text-ds-sm text-surface-fg-subtle font-medium\">:</span>\n\n {/* Minute — 5-min steps */}\n <select\n value={minutes - (minutes % 5)}\n onChange={(e) => setMinute(Number(e.target.value))}\n className=\"h-ds-sm rounded-control border border-surface-border-strong bg-surface-raised px-ds-02 text-ds-sm text-surface-fg focus:outline-hidden focus:ring-2 focus:ring-accent-9\"\n aria-label=\"Minute\"\n >\n {Array.from({ length: 12 }, (_, i) => i * 5).map((m) => (\n <option key={m} value={m}>{String(m).padStart(2, '0')}</option>\n ))}\n </select>\n\n {/* AM/PM toggle */}\n <ToggleGroup\n type=\"single\"\n value={isPM ? 'PM' : 'AM'}\n onValueChange={(v) => {\n if (v === 'AM') togglePeriod(false)\n else if (v === 'PM') togglePeriod(true)\n }}\n size=\"sm\"\n >\n <ToggleGroupItem value=\"AM\">AM</ToggleGroupItem>\n <ToggleGroupItem value=\"PM\">PM</ToggleGroupItem>\n </ToggleGroup>\n </div>\n )\n}\n\n// ── Compact Date + Time Entry (for dropdown) ──────────────────\n\nfunction CompactDateTimeEntry({\n value,\n onChange,\n minDate,\n}: {\n value: Date | null\n onChange: (d: Date) => void\n minDate?: Date\n}) {\n const now = new Date()\n const selected = value ?? (() => { const d = new Date(now); d.setHours(d.getHours() + 1, 0, 0, 0); return d })()\n\n // Format date as YYYY-MM-DD for the native input\n const dateStr = `${selected.getFullYear()}-${String(selected.getMonth() + 1).padStart(2, '0')}-${String(selected.getDate()).padStart(2, '0')}`\n\n const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const parts = e.target.value.split('-')\n if (parts.length !== 3) return\n const d = new Date(selected)\n d.setFullYear(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]))\n onChange(d)\n }\n\n const minDateStr = minDate\n ? `${minDate.getFullYear()}-${String(minDate.getMonth() + 1).padStart(2, '0')}-${String(minDate.getDate()).padStart(2, '0')}`\n : undefined\n\n return (\n <div className=\"space-y-ds-03\">\n {/* Date input */}\n <div className=\"flex items-center justify-between\">\n <span className=\"text-ds-xs font-medium text-surface-fg-subtle\">Date</span>\n <input\n type=\"date\"\n value={dateStr}\n min={minDateStr}\n onChange={handleDateChange}\n className=\"h-ds-sm rounded-control border border-surface-border-strong bg-surface-raised px-ds-03 text-ds-sm text-surface-fg focus:outline-hidden focus:ring-2 focus:ring-accent-9\"\n />\n </div>\n\n {/* Time row */}\n <div className=\"flex items-center justify-between\">\n <span className=\"text-ds-xs font-medium text-surface-fg-subtle\">Time</span>\n <InlineTimePicker value={selected} onChange={onChange} />\n </div>\n </div>\n )\n}\n\n// ── Full Calendar + Time Picker (for dialog) ──────────────────\n\nfunction FullDateTimePicker({\n value,\n onChange,\n minDate,\n}: {\n value: Date | null\n onChange: (d: Date) => void\n minDate?: Date\n}) {\n const now = new Date()\n const selected = value ?? (() => { const d = new Date(now); d.setHours(d.getHours() + 1, 0, 0, 0); return d })()\n\n const { currentMonth, goToPreviousMonth, goToNextMonth } = useCalendar(selected)\n\n const handleDateSelect = (date: Date) => {\n const d = new Date(date)\n d.setHours(selected.getHours(), selected.getMinutes(), 0, 0)\n onChange(d)\n }\n\n return (\n <div className=\"space-y-ds-03\">\n <CalendarGrid\n currentMonth={currentMonth}\n selected={selected}\n onSelect={handleDateSelect}\n onMonthChange={(d) => {\n if (d < currentMonth) goToPreviousMonth()\n else goToNextMonth()\n }}\n minDate={minDate}\n className=\"w-full\"\n />\n <div className=\"flex items-center justify-between border-t border-surface-border pt-ds-03\">\n <span className=\"text-ds-xs font-medium text-surface-fg-subtle\">Time</span>\n <InlineTimePicker value={selected} onChange={onChange} />\n </div>\n </div>\n )\n}\n\n// ── Schedule Dropdown Content (presets + inline picker) ─────────\n\nexport interface ScheduleDropdownContentProps {\n onSchedule: (date: Date) => void\n onClose: () => void\n /** Open a full dialog instead of inline picker. Consumer provides the dialog. */\n onOpenDialog?: () => void\n}\n\nexport function ScheduleDropdownContent({ onSchedule, onClose, onOpenDialog }: ScheduleDropdownContentProps) {\n const [showPicker, setShowPicker] = React.useState(false)\n const [customDate, setCustomDate] = React.useState<Date | null>(null)\n\n const presets = React.useMemo(() => getSmartPresets(), [])\n\n const handlePreset = (date: Date) => {\n onSchedule(date)\n onClose()\n }\n\n const handleCustomConfirm = () => {\n if (customDate && customDate > new Date()) {\n onSchedule(customDate)\n onClose()\n setCustomDate(null)\n setShowPicker(false)\n }\n }\n\n if (showPicker) {\n return (\n <div className=\"p-ds-04\" style={{ minWidth: 270 }}>\n <div className=\"mb-ds-03 flex items-center justify-between\">\n <p className=\"text-ds-sm font-medium text-surface-fg\">Pick date & time</p>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n onClick={() => setShowPicker(false)}\n aria-label=\"Back to presets\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </Button>\n </div>\n\n <CompactDateTimeEntry\n value={customDate}\n onChange={setCustomDate}\n minDate={new Date()}\n />\n\n <div className=\"mt-ds-03 flex justify-end\">\n <Button\n variant=\"solid\"\n size=\"sm\"\n onClick={handleCustomConfirm}\n disabled={!customDate || customDate <= new Date()}\n >\n Confirm\n </Button>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"p-ds-02\" style={{ minWidth: 260 }}>\n <p className=\"px-ds-03 py-ds-01 text-ds-xs font-medium text-surface-fg-subtle\">\n Schedule send\n </p>\n {presets.map((preset, i) => (\n <Button\n key={i}\n variant=\"ghost\"\n fullWidth\n onClick={() => handlePreset(preset.date)}\n >\n <Icon icon={IconClock} size=\"sm\" className=\"shrink-0 text-surface-fg-muted\" />\n {preset.label}\n </Button>\n ))}\n <div className=\"mx-ds-02 my-ds-02 h-px bg-surface-border\" />\n <Button\n variant=\"ghost\"\n fullWidth\n onClick={() => setShowPicker(true)}\n >\n <Icon icon={IconCalendarEvent} size=\"sm\" className=\"shrink-0 text-accent-11\" />\n Pick date & time...\n </Button>\n {onOpenDialog && (\n <Button\n variant=\"ghost\"\n fullWidth\n onClick={() => { onOpenDialog(); onClose() }}\n >\n <Icon icon={IconCalendarEvent} size=\"sm\" className=\"shrink-0 text-surface-fg-muted\" />\n Open full picker...\n </Button>\n )}\n </div>\n )\n}\n\n// ── Schedule Dialog (full-screen on mobile) ────────────────────\n\nexport interface ScheduleDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onSchedule: (date: Date) => void\n /** Pre-fill with existing scheduled date (edit mode). */\n initialDate?: Date | null\n}\n\nexport function ScheduleDialog({ open, onOpenChange, onSchedule, initialDate }: ScheduleDialogProps) {\n const [date, setDate] = React.useState<Date | null>(initialDate ?? null)\n\n // Reset when opened with new initialDate\n React.useEffect(() => {\n if (open) setDate(initialDate ?? null)\n }, [open, initialDate])\n\n const handleConfirm = () => {\n if (date && date > new Date()) {\n onSchedule(date)\n onOpenChange(false)\n }\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-[380px]\">\n <DialogHeader>\n <DialogTitle>{initialDate ? 'Reschedule message' : 'Schedule send'}</DialogTitle>\n </DialogHeader>\n\n <FullDateTimePicker\n value={date}\n onChange={setDate}\n minDate={new Date()}\n />\n\n <DialogFooter className=\"gap-ds-02\">\n <Button variant=\"soft\" onClick={() => onOpenChange(false)}>Cancel</Button>\n <Button\n variant=\"solid\"\n onClick={handleConfirm}\n disabled={!date || date <= new Date()}\n >\n {initialDate ? 'Reschedule' : 'Schedule'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n\n// ── Schedule Banner ────────────────────────────────────────────\n\nfunction formatScheduleTime(date: Date): string {\n const now = new Date()\n const tomorrow = new Date(now)\n tomorrow.setDate(tomorrow.getDate() + 1)\n\n const isToday = date.toDateString() === now.toDateString()\n const isTomorrow = date.toDateString() === tomorrow.toDateString()\n\n const time = date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' })\n\n if (isToday) return `Today at ${time}`\n if (isTomorrow) return `Tomorrow at ${time}`\n return `${date.toLocaleDateString(undefined, { weekday: 'short', month: 'short', day: 'numeric' })} at ${time}`\n}\n\nexport function ScheduleBanner({ date, onClear, onEdit }: { date: Date; onClear: () => void; onEdit?: () => void }) {\n return (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n className=\"overflow-hidden\"\n >\n <div className=\"flex items-center gap-ds-03 px-ds-04 py-ds-02b text-ds-xs text-accent-11 bg-accent-2 border-b border-accent-4\">\n <Icon icon={IconClock} size=\"xs\" className=\"shrink-0\" />\n <span className=\"min-w-0 flex-1 truncate\">\n Scheduled for {formatScheduleTime(date)}\n </span>\n {onEdit && (\n <Button\n variant=\"soft\"\n size=\"icon-xs\"\n className=\"shrink-0\"\n onClick={onEdit}\n aria-label=\"Edit schedule\"\n >\n <Icon icon={IconPencil} size=\"xs\" />\n </Button>\n )}\n <Button\n variant=\"soft\"\n size=\"icon-xs\"\n className=\"shrink-0\"\n onClick={onClear}\n aria-label=\"Cancel schedule\"\n >\n <Icon icon={IconX} size=\"xs\" />\n </Button>\n </div>\n </motion.div>\n )\n}\n","'use client'\n\nimport { useCallback, useEffect,useRef, useState } from 'react'\n\nexport interface UseVoiceRecorderOptions {\n maxDuration?: number\n onComplete: (blob: Blob, duration: number, waveformData: number[]) => void\n}\n\nexport interface UseVoiceRecorderReturn {\n state: 'idle' | 'recording' | 'paused'\n duration: number\n analyserNode: AnalyserNode | null\n waveformData: number[]\n start: () => Promise<void>\n stop: () => void\n cancel: () => void\n pause: () => void\n resume: () => void\n}\n\nfunction getSupportedMimeType(): string {\n if (\n typeof MediaRecorder !== 'undefined' &&\n MediaRecorder.isTypeSupported('audio/webm;codecs=opus')\n ) {\n return 'audio/webm;codecs=opus'\n }\n if (\n typeof MediaRecorder !== 'undefined' &&\n MediaRecorder.isTypeSupported('audio/mp4')\n ) {\n return 'audio/mp4'\n }\n return ''\n}\n\nexport function useVoiceRecorder(\n options: UseVoiceRecorderOptions\n): UseVoiceRecorderReturn {\n const { maxDuration, onComplete } = options\n\n const [state, setState] = useState<'idle' | 'recording' | 'paused'>('idle')\n const [duration, setDuration] = useState(0)\n const [analyserNode, setAnalyserNode] = useState<AnalyserNode | null>(null)\n const [waveformData, setWaveformData] = useState<number[]>([])\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null)\n const audioContextRef = useRef<AudioContext | null>(null)\n const streamRef = useRef<MediaStream | null>(null)\n const chunksRef = useRef<Blob[]>([])\n const durationTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const waveformTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const maxDurationTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const analyserRef = useRef<AnalyserNode | null>(null)\n const durationRef = useRef(0)\n const waveformRef = useRef<number[]>([])\n const cancelledRef = useRef(false)\n const onCompleteRef = useRef(onComplete)\n\n // Keep onComplete ref fresh without causing re-renders of callbacks\n onCompleteRef.current = onComplete\n\n const cleanup = useCallback(() => {\n if (durationTimerRef.current !== null) {\n clearInterval(durationTimerRef.current)\n durationTimerRef.current = null\n }\n if (waveformTimerRef.current !== null) {\n clearInterval(waveformTimerRef.current)\n waveformTimerRef.current = null\n }\n if (maxDurationTimerRef.current !== null) {\n clearTimeout(maxDurationTimerRef.current)\n maxDurationTimerRef.current = null\n }\n if (streamRef.current) {\n streamRef.current.getTracks().forEach((track) => track.stop())\n streamRef.current = null\n }\n if (audioContextRef.current) {\n audioContextRef.current.close().catch(() => {})\n audioContextRef.current = null\n }\n analyserRef.current = null\n setAnalyserNode(null)\n mediaRecorderRef.current = null\n chunksRef.current = []\n }, [])\n\n const start = useCallback(async () => {\n if (typeof MediaRecorder === 'undefined') {\n throw new Error(\n 'MediaRecorder is not supported in this browser. Voice recording requires a modern browser with MediaRecorder support.'\n )\n }\n\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true })\n streamRef.current = stream\n\n const mimeType = getSupportedMimeType()\n const recorder = mimeType\n ? new MediaRecorder(stream, { mimeType })\n : new MediaRecorder(stream)\n mediaRecorderRef.current = recorder\n chunksRef.current = []\n cancelledRef.current = false\n\n // Set up Web Audio API for analyser\n const audioContext = new AudioContext()\n audioContextRef.current = audioContext\n const source = audioContext.createMediaStreamSource(stream)\n const analyser = audioContext.createAnalyser()\n analyser.fftSize = 256\n analyser.smoothingTimeConstant = 0.7\n source.connect(analyser)\n analyserRef.current = analyser\n setAnalyserNode(analyser)\n\n // Collect chunks\n recorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n chunksRef.current.push(event.data)\n }\n }\n\n // Handle stop\n recorder.onstop = () => {\n if (!cancelledRef.current) {\n const blob = new Blob(chunksRef.current, {\n type: recorder.mimeType || 'audio/webm',\n })\n // Capture current values before cleanup resets them\n const finalDuration = durationRef.current\n const finalWaveform = waveformRef.current\n cleanup()\n setState('idle')\n setDuration(0)\n setWaveformData([])\n onCompleteRef.current(blob, finalDuration, finalWaveform)\n } else {\n cleanup()\n setState('idle')\n setDuration(0)\n setWaveformData([])\n }\n }\n\n // Start recording\n recorder.start()\n\n // Duration timer\n setDuration(0)\n durationRef.current = 0\n durationTimerRef.current = setInterval(() => {\n durationRef.current += 1\n setDuration((prev) => prev + 1)\n }, 1000)\n\n // Waveform capture\n const frequencyData = new Uint8Array(analyser.frequencyBinCount)\n setWaveformData([])\n waveformRef.current = []\n waveformTimerRef.current = setInterval(() => {\n if (analyserRef.current) {\n analyserRef.current.getByteFrequencyData(frequencyData)\n let sum = 0\n for (let i = 0; i < frequencyData.length; i++) {\n sum += frequencyData[i]\n }\n const average = sum / frequencyData.length / 255\n waveformRef.current = [...waveformRef.current, average]\n setWaveformData((prev) => [...prev, average])\n }\n }, 100)\n\n // Max duration auto-stop\n if (maxDuration !== undefined && maxDuration > 0) {\n maxDurationTimerRef.current = setTimeout(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state !== 'inactive'\n ) {\n mediaRecorderRef.current.stop()\n }\n }, maxDuration * 1000)\n }\n\n setState('recording')\n }, [maxDuration, cleanup])\n\n const stop = useCallback(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state !== 'inactive'\n ) {\n cancelledRef.current = false\n mediaRecorderRef.current.stop()\n }\n }, [])\n\n const cancel = useCallback(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state !== 'inactive'\n ) {\n cancelledRef.current = true\n mediaRecorderRef.current.stop()\n } else {\n // Already inactive, just reset\n cleanup()\n setState('idle')\n setDuration(0)\n setWaveformData([])\n }\n }, [cleanup])\n\n const pause = useCallback(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state === 'recording'\n ) {\n mediaRecorderRef.current.pause()\n if (durationTimerRef.current !== null) {\n clearInterval(durationTimerRef.current)\n durationTimerRef.current = null\n }\n if (waveformTimerRef.current !== null) {\n clearInterval(waveformTimerRef.current)\n waveformTimerRef.current = null\n }\n setState('paused')\n }\n }, [])\n\n const resume = useCallback(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state === 'paused'\n ) {\n mediaRecorderRef.current.resume()\n\n // Resume duration timer\n durationTimerRef.current = setInterval(() => {\n durationRef.current += 1\n setDuration((prev) => prev + 1)\n }, 1000)\n\n // Resume waveform capture\n const frequencyData = new Uint8Array(\n analyserRef.current?.frequencyBinCount ?? 128\n )\n waveformTimerRef.current = setInterval(() => {\n if (analyserRef.current) {\n analyserRef.current.getByteFrequencyData(frequencyData)\n let sum = 0\n for (let i = 0; i < frequencyData.length; i++) {\n sum += frequencyData[i]\n }\n const average = sum / frequencyData.length / 255\n waveformRef.current = [...waveformRef.current, average]\n setWaveformData((prev) => [...prev, average])\n }\n }, 100)\n\n setState('recording')\n }\n }, [])\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (durationTimerRef.current !== null) {\n clearInterval(durationTimerRef.current)\n }\n if (waveformTimerRef.current !== null) {\n clearInterval(waveformTimerRef.current)\n }\n if (maxDurationTimerRef.current !== null) {\n clearTimeout(maxDurationTimerRef.current)\n }\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state !== 'inactive'\n ) {\n mediaRecorderRef.current.stop()\n }\n if (streamRef.current) {\n streamRef.current.getTracks().forEach((track) => track.stop())\n }\n if (audioContextRef.current) {\n audioContextRef.current.close().catch(() => {})\n }\n }\n }, [])\n\n return {\n state,\n duration,\n analyserNode,\n waveformData,\n start,\n stop,\n cancel,\n pause,\n resume,\n }\n}\n","'use client'\n\nimport { computePosition, flip, offset, shift } from '@floating-ui/dom'\nimport {\n IconBold,\n IconChevronDown,\n IconClock,\n IconCode,\n IconHighlight,\n IconItalic,\n IconMicrophone,\n IconMoodSmile,\n IconPlus,\n IconSend,\n IconSquare,\n IconStrikethrough,\n IconTextSize,\n IconTrash,\n IconUnderline,\n} from '@tabler/icons-react'\nimport Highlight from '@tiptap/extension-highlight'\nimport Image from '@tiptap/extension-image'\nimport Mention from '@tiptap/extension-mention'\nimport { CharacterCount,Placeholder } from '@tiptap/extensions'\nimport { type Editor,EditorContent, Extension, useEditor, useEditorState } from '@tiptap/react'\nimport { BubbleMenu } from '@tiptap/react/menus'\nimport StarterKit from '@tiptap/starter-kit'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { MENTION_TOKEN_CLASS } from '../ui/lib/mention'\nimport { durations } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport { SplitButton } from '../ui/split-button'\nimport type { EmojiData, EmojiSet } from './emoji-picker'\nimport { EmojiNode } from './extensions/emoji-node'\nimport { createEmojiSuggestion } from './extensions/emoji-suggestion'\nimport { FileAttachment } from './extensions/file-attachment'\nimport { createSuggestionRenderer } from './extensions/mention-suggestion'\nimport type { SlashCommandGroup } from './extensions/slash-command'\nimport { createSlashCommandExtension } from './extensions/slash-command'\nimport type { Attachment } from './rich-chat-input/attachment-strip'\nimport { AttachmentStrip } from './rich-chat-input/attachment-strip'\nimport type { AudioPlayerProps } from './rich-chat-input/audio-player'\nimport { AudioPlayer } from './rich-chat-input/audio-player'\nimport type { AudioWaveformProps } from './rich-chat-input/audio-waveform'\nimport { AudioWaveform } from './rich-chat-input/audio-waveform'\nimport type { ChatToolbarItem } from './rich-chat-input/chat-toolbar'\nimport { ChatToolbar } from './rich-chat-input/chat-toolbar'\nimport { RecordingOverlay } from './rich-chat-input/recording-overlay'\nimport { ReplyBanner } from './rich-chat-input/reply-banner'\nimport { ScheduleBanner, ScheduleDialog,ScheduleDropdownContent } from './rich-chat-input/schedule-send'\nimport type { UseVoiceRecorderOptions, UseVoiceRecorderReturn } from './rich-chat-input/use-voice-recorder'\nimport { useVoiceRecorder } from './rich-chat-input/use-voice-recorder'\nimport type { MentionItem } from './rich-text-editor'\n\n// ── Re-exports ──────────────────────────────────────────────────\n\nexport type { MentionItem }\nexport type { SlashCommand, SlashCommandGroup } from './extensions/slash-command'\n\nexport { AudioWaveform }\nexport type { AudioWaveformProps }\nexport { AudioPlayer }\nexport type { AudioPlayerProps }\nexport { useVoiceRecorder }\nexport type { UseVoiceRecorderOptions, UseVoiceRecorderReturn }\n\n// ── Types ───────────────────────────────────────────────────────\n\n// Only track states that are USER-TRIGGERED (not editor-triggered).\n// idle/focused/composing are derived from editor.isEmpty at render time.\ntype InputState = 'idle' | 'recording' | 'review'\n\nexport interface RichChatInputMessage {\n html: string\n plainText: string\n attachments?: Array<{ url: string; name: string; size: number; type: string }>\n voiceNote?: { blob: Blob; duration: number }\n}\n\nexport interface RichChatInputProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSubmit' | 'content'> {\n onSubmit: (message: RichChatInputMessage) => void\n placeholder?: string\n disabled?: boolean\n /** Initial HTML content (not reactive — use for message editing). */\n content?: string\n variant?: 'compact' | 'expanded' | 'minimal' | 'inline'\n enterBehavior?: 'send' | 'newline'\n maxLength?: number\n /** When to show the character counter. @default 'near-limit' */\n charCountDisplay?: 'always' | 'focus' | 'near-limit' | 'hidden'\n mentions?: MentionItem[]\n onMentionSearch?: (query: string) => Promise<MentionItem[]>\n onMentionSelect?: (item: MentionItem) => void\n onFileUpload?: (file: File) => Promise<{ url: string; name: string; size: number }>\n onImageUpload?: (file: File) => Promise<string>\n slashCommands?: SlashCommandGroup[]\n onVoiceRecord?: (audio: Blob, duration: number) => void\n /** Called after recording stops. Consumer can transcribe and return text to insert into the editor. If null is returned, the audio is attached as a voice note. */\n onTranscribe?: (blob: Blob, duration: number) => Promise<string | null>\n maxDuration?: number\n replyTo?: { id: string; author: string; preview: string; onDismiss: () => void }\n onTyping?: (isTyping: boolean) => void\n onEmpty?: (isEmpty: boolean) => void\n isStreaming?: boolean\n onCancel?: () => void\n leadingSlot?: React.ReactNode\n trailingSlot?: React.ReactNode\n disclaimer?: string\n /** true = default toolbar, ChatToolbarItem[] = whitelist, ReactNode = custom toolbar, false = hidden */\n toolbar?: boolean | ChatToolbarItem[] | React.ReactNode\n /** Custom action button rendered to the left of the input (replaces the default attach button). Pass `false` to hide. */\n actionButton?: React.ReactNode | false\n /** Emoji art style in the picker. @default 'native' (system emoji) */\n emojiSet?: EmojiSet\n /** Called when user schedules a message. If provided, a schedule button appears next to send. */\n onSchedule?: (message: RichChatInputMessage, scheduledAt: Date) => void\n /** Split send button — dropdown options next to send (e.g. custom actions). */\n sendOptions?: Array<{\n label: string\n icon?: React.ComponentType<{ className?: string }>\n onSelect: () => void\n }>\n}\n\n// ── Variant config ──────────────────────────────────────────────\n\nconst variantConfig = {\n compact: { minHeight: 44, maxHeight: 256, showToolbar: true, toolbarPosition: 'bottom' as const },\n expanded: { minHeight: 96, maxHeight: 384, showToolbar: true, toolbarPosition: 'bottom' as const },\n minimal: { minHeight: 44, maxHeight: 128, showToolbar: false, toolbarPosition: 'bottom' as const },\n inline: { minHeight: 40, maxHeight: 160, showToolbar: false, toolbarPosition: 'top' as const },\n}\n\n// ── Chat prose (tighter than RTE, text-ds-md to match Input) ────\n\nconst CHAT_PROSE = [\n 'prose prose-sm max-w-none focus:outline-hidden',\n 'font-body text-ds-md leading-relaxed text-surface-fg',\n '[&_p.is-editor-empty:first-child]:relative',\n '[&_p.is-editor-empty:first-child::before]:text-surface-fg-subtle [&_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)] [&_p.is-editor-empty:first-child::before]:pointer-events-none [&_p.is-editor-empty:first-child::before]:absolute [&_p.is-editor-empty:first-child::before]:left-0 [&_p.is-editor-empty:first-child::before]:top-0 [&_p.is-editor-empty:first-child::before]:w-full [&_p.is-editor-empty:first-child::before]:truncate',\n '[&_p]:mb-ds-01 [&_p]:text-surface-fg',\n '[&_p:last-child]:mb-0',\n '[&_ul]:ml-ds-04 [&_ul]:list-disc [&_ol]:ml-ds-04 [&_ol]:list-decimal',\n '[&_li]:text-surface-fg',\n '[&_code]:rounded [&_code]:bg-surface-raised [&_code]:px-ds-02 [&_code]:py-[1px] [&_code]:text-ds-md [&_code]:text-accent-11',\n '[&_strong]:font-semibold [&_strong]:text-surface-fg',\n '[&_mark]:rounded-xs [&_mark]:bg-warning-3 [&_mark]:px-[2px]',\n '[&_a]:text-accent-11 [&_a]:underline',\n MENTION_TOKEN_CLASS,\n].join(' ')\n\n// ── Split Send Dropdown (chevron next to send — schedule send, etc.) ──\n\nfunction SplitSendDropdown({ options }: { options: Array<{ label: string; icon?: React.ComponentType<{ className?: string }>; onSelect: () => void }> }) {\n const [open, setOpen] = React.useState(false)\n const dropdownRef = React.useRef<HTMLDivElement>(null)\n\n // Close on outside click\n React.useEffect(() => {\n if (!open) return\n const handleClick = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) setOpen(false)\n }\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [open])\n\n return (\n <div ref={dropdownRef} className=\"relative\">\n <button\n type=\"button\"\n onClick={() => setOpen(prev => !prev)}\n title=\"More send options\"\n aria-label=\"More send options\"\n aria-expanded={open}\n className={cn(\n 'inline-flex h-ds-xs-plus w-5 items-center justify-center rounded-control touch-target',\n 'text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg',\n 'transition-colors duration-fast-01 ease-productive-standard',\n open && 'bg-surface-raised-hover text-surface-fg',\n )}\n >\n <Icon icon={IconChevronDown} size=\"xs\" />\n </button>\n {/* min-w-[200px]: component-specific dropdown width — no design token equivalent */}\n {open && (\n <div className=\"absolute bottom-full right-0 mb-ds-02 min-w-[200px] rounded-surface bg-surface-overlay p-ds-02 shadow-floating z-popover\">\n <p className=\"px-ds-03 py-ds-01 text-ds-xs font-medium text-surface-fg-subtle\">Send options</p>\n {options.map((opt, i) => (\n <button\n key={i}\n type=\"button\"\n onClick={() => { opt.onSelect(); setOpen(false) }}\n className=\"flex w-full items-center gap-ds-03 rounded-control px-ds-03 py-ds-02 text-ds-sm text-surface-fg hover:bg-surface-raised-hover transition-colors duration-fast-01\"\n >\n {opt.icon && <opt.icon className=\"h-ico-sm w-ico-sm text-surface-fg-muted\" />}\n {opt.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ── Emoji Picker Popover (lazy-loaded) ──────────────────────────\n\nconst LazyEmojiPicker = React.lazy(() =>\n import('./emoji-picker').then((m) => ({ default: m.EmojiPicker })),\n)\n\nfunction EmojiPickerPopover({ onSelect, onClose }: { onSelect: (emoji: EmojiData) => void; onClose: () => void }) {\n const ref = React.useRef<HTMLDivElement>(null)\n\n // Close on click outside\n React.useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) onClose()\n }\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [onClose])\n\n // Close on Escape\n React.useEffect(() => {\n const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }\n document.addEventListener('keydown', handleKey)\n return () => document.removeEventListener('keydown', handleKey)\n }, [onClose])\n\n const fallback = (\n <div className=\"flex h-[435px] w-[352px] items-center justify-center rounded-surface bg-surface-overlay shadow-floating\">\n <span className=\"text-ds-sm text-surface-fg-subtle\">Loading…</span>\n </div>\n )\n\n return (\n <div ref={ref}>\n <React.Suspense fallback={fallback}>\n <LazyEmojiPicker onSelect={onSelect} />\n </React.Suspense>\n </div>\n )\n}\n\n// ── Toolbar Button (for BubbleMenu only — ChatToolbar has its own) ──\n\nfunction BubbleBtn({\n onClick,\n isActive = false,\n title,\n children,\n}: {\n onClick: () => void\n isActive?: boolean\n title: string\n children: React.ReactNode\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control touch-target',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n isActive ? 'bg-surface-raised-hover text-accent-11' : 'text-surface-fg-subtle',\n )}\n >\n {children}\n </button>\n )\n}\n\n// ── BubbleMenu with useEditorState (v3) ────────────────────────\n\nfunction ChatBubbleMenu({ editor }: { editor: Editor }) {\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n isBold: e.isActive('bold'),\n isItalic: e.isActive('italic'),\n isUnderline: e.isActive('underline'),\n isStrike: e.isActive('strike'),\n isHighlight: e.isActive('highlight'),\n isCode: e.isActive('code'),\n }),\n })\n\n return (\n <BubbleMenu\n editor={editor}\n className=\"flex gap-ds-01 rounded-surface bg-surface-overlay p-ds-02 shadow-floating\"\n >\n <BubbleBtn onClick={() => editor.chain().focus().toggleBold().run()} isActive={state.isBold} title=\"Bold\">\n <Icon icon={IconBold} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleItalic().run()} isActive={state.isItalic} title=\"Italic\">\n <Icon icon={IconItalic} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleUnderline().run()} isActive={state.isUnderline} title=\"Underline\">\n <Icon icon={IconUnderline} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleStrike().run()} isActive={state.isStrike} title=\"Strikethrough\">\n <Icon icon={IconStrikethrough} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleHighlight().run()} isActive={state.isHighlight} title=\"Highlight\">\n <Icon icon={IconHighlight} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleCode().run()} isActive={state.isCode} title=\"Code\">\n <Icon icon={IconCode} size=\"xs\" />\n </BubbleBtn>\n </BubbleMenu>\n )\n}\n\n// ── Component ───────────────────────────────────────────────────\n\nconst RichChatInput = React.forwardRef<HTMLDivElement, RichChatInputProps>(\n function RichChatInput(\n {\n onSubmit,\n placeholder = 'Type a message...',\n disabled = false,\n content = '',\n variant = 'compact',\n enterBehavior = 'send',\n maxLength,\n charCountDisplay = 'near-limit',\n mentions,\n onMentionSearch,\n onMentionSelect,\n onFileUpload,\n onImageUpload,\n slashCommands,\n onVoiceRecord,\n onTranscribe,\n maxDuration,\n replyTo,\n onTyping,\n onEmpty,\n isStreaming = false,\n onCancel,\n leadingSlot,\n trailingSlot,\n disclaimer,\n toolbar: toolbarProp = true,\n sendOptions,\n onSchedule,\n actionButton,\n emojiSet = 'native',\n className,\n ...props\n },\n ref,\n ) {\n // ── State ──────────────────────────────────────────────────\n const [state, setState] = React.useState<InputState>('idle')\n const [toolbarExpanded, setToolbarExpanded] = React.useState(false)\n const [showEmojiPicker, setShowEmojiPicker] = React.useState(false)\n const [scheduledDate, setScheduledDate] = React.useState<Date | null>(null)\n const [scheduleDialogOpen, setScheduleDialogOpen] = React.useState(false)\n const [editorFocused, setEditorFocused] = React.useState(false)\n const [charCount, setCharCount] = React.useState(0)\n const emojiAnchorRef = React.useRef<HTMLButtonElement>(null)\n const emojiFloatingRef = React.useRef<HTMLDivElement>(null)\n\n // Position emoji picker with Floating UI (auto-flips top/bottom based on space)\n React.useEffect(() => {\n if (!showEmojiPicker || !emojiAnchorRef.current || !emojiFloatingRef.current) return\n const anchor = emojiAnchorRef.current\n const floating = emojiFloatingRef.current\n\n const update = () => {\n computePosition(anchor, floating, {\n placement: 'top-end',\n middleware: [offset(8), flip(), shift({ padding: 8 })],\n }).then(({ x, y }) => {\n Object.assign(floating.style, { left: `${x}px`, top: `${y}px` })\n })\n }\n\n update()\n // Update on scroll/resize\n window.addEventListener('scroll', update, true)\n window.addEventListener('resize', update)\n return () => {\n window.removeEventListener('scroll', update, true)\n window.removeEventListener('resize', update)\n }\n }, [showEmojiPicker])\n const [attachments, setAttachments] = React.useState<Attachment[]>([])\n const [voiceNote, setVoiceNote] = React.useState<{ blob: Blob; duration: number; waveformData: number[] } | null>(null)\n const [isDragging, setIsDragging] = React.useState(false)\n // editorHeight state removed — was causing re-renders during ProseMirror DOM changes\n\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n const editorWrapperRef = React.useRef<HTMLDivElement>(null)\n const typingTimeoutRef = React.useRef<ReturnType<typeof setTimeout>>(undefined)\n const submitRef = React.useRef<(() => void) | undefined>(undefined)\n const enterBehaviorRef = React.useRef(enterBehavior)\n enterBehaviorRef.current = enterBehavior\n // Same live-ref pattern for the mention-select callback: the extensions memo\n // only rebuilds on presence changes (`!!mentions` etc.), so passing\n // onMentionSelect directly would freeze the mount-time closure. See #92.\n const onMentionSelectRef = React.useRef(onMentionSelect)\n onMentionSelectRef.current = onMentionSelect\n // Same reasoning for the mention data sources read inside the memoized\n // `items` resolver — the memo only rebuilds on presence, so a consumer\n // swapping the list or the search fn would otherwise keep the mount-time\n // value. See #92.\n const mentionsRef = React.useRef(mentions)\n mentionsRef.current = mentions\n const onMentionSearchRef = React.useRef(onMentionSearch)\n onMentionSearchRef.current = onMentionSearch\n\n const isMobile = useIsMobile()\n const config = variantConfig[variant]\n const maxHeightPx = config.maxHeight\n\n // ── Voice Recorder ────────────────────────────────────────\n const voiceRecorder = useVoiceRecorder({\n maxDuration,\n onComplete: async (blob, duration, waveformData) => {\n onVoiceRecord?.(blob, duration)\n\n // If consumer provides a transcription handler, try to transcribe\n if (onTranscribe) {\n const text = await onTranscribe(blob, duration)\n if (text != null) {\n // Insert transcribed text into the editor instead of attaching voice note\n editor?.chain().focus().insertContent(text).run()\n setState('idle') // back to idle — hasContent will be derived from editor\n return\n }\n }\n\n // Fall back to voice note attachment\n setVoiceNote({ blob, duration, waveformData })\n setState('review')\n },\n })\n\n const handleStartRecording = React.useCallback(() => {\n voiceRecorder.start()\n setState('recording')\n }, [voiceRecorder])\n\n const handleStopRecording = React.useCallback(() => {\n voiceRecorder.stop() // triggers onComplete → setState('review')\n }, [voiceRecorder])\n\n const handleCancelRecording = React.useCallback(() => {\n voiceRecorder.cancel()\n setState('idle')\n }, [voiceRecorder])\n\n // ── TipTap Extensions ─────────────────────────────────────\n const extensions = React.useMemo(() => {\n const exts = [\n StarterKit.configure({\n heading: false,\n horizontalRule: false,\n codeBlock: false,\n blockquote: false,\n // v3: Underline + Link included in StarterKit\n link: {\n openOnClick: false,\n HTMLAttributes: { class: 'text-accent-11 underline' },\n },\n }),\n Placeholder.configure({ placeholder }),\n Highlight.configure({ multicolor: false }),\n Image,\n CharacterCount.configure({ limit: maxLength || undefined }),\n FileAttachment,\n EmojiNode,\n createEmojiSuggestion(),\n // Enter-to-send\n Extension.create({\n name: 'enterToSend',\n addKeyboardShortcuts() {\n return {\n 'Enter': () => {\n if (enterBehaviorRef.current === 'send') {\n submitRef.current?.()\n return true\n }\n return false\n },\n 'Shift-Enter': () => {\n if (enterBehaviorRef.current === 'send') {\n this.editor.commands.splitBlock()\n return true\n }\n return false\n },\n 'Mod-Enter': () => {\n submitRef.current?.()\n return true\n },\n }\n },\n }),\n ]\n\n // Mentions\n if (mentions || onMentionSearch) {\n exts.push(\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n suggestion: {\n items: async ({ query }: { query: string }) => {\n if (onMentionSearchRef.current) return await onMentionSearchRef.current(query)\n const list = mentionsRef.current\n if (list) return list.filter(m => m.label.toLowerCase().includes(query.toLowerCase())).slice(0, 8)\n return []\n },\n render: createSuggestionRenderer((item: MentionItem) => onMentionSelectRef.current?.(item)),\n },\n }),\n )\n }\n\n // Slash commands\n if (slashCommands) {\n exts.push(createSlashCommandExtension(slashCommands))\n }\n\n return exts\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [placeholder, maxLength, emojiSet, !!mentions, !!onMentionSearch, !!slashCommands])\n\n // ── Editor ────────────────────────────────────────────────\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions,\n content: content || undefined,\n editable: !disabled,\n editorProps: {\n attributes: {\n class: CHAT_PROSE,\n },\n handlePaste: (_view, event) => {\n const files = Array.from(event.clipboardData?.files ?? [])\n if (files.length > 0) {\n files.forEach(processFile)\n return true\n }\n return false\n },\n },\n })\n\n // ── Submit Handler (structured output) ────────────────────\n const handleSubmit = React.useCallback(() => {\n if (!editor) return\n\n const hasText = !editor.isEmpty\n const hasAttachments = attachments.length > 0\n const hasVoice = !!voiceNote\n\n if (!hasText && !hasAttachments && !hasVoice) return\n if (isStreaming) return\n\n const message: RichChatInputMessage = {\n html: hasText ? editor.getHTML() : '',\n plainText: hasText ? editor.getText() : '',\n }\n\n if (hasAttachments) {\n message.attachments = attachments\n .filter(a => !a.uploading && a.url)\n .map(a => ({ url: a.url!, name: a.name, size: a.size, type: a.type }))\n }\n\n if (hasVoice) {\n message.voiceNote = { blob: voiceNote.blob, duration: voiceNote.duration }\n }\n\n if (scheduledDate && onSchedule) {\n onSchedule(message, scheduledDate)\n } else {\n onSubmit(message)\n }\n\n // Reset everything\n editor.commands.clearContent()\n setAttachments([])\n setVoiceNote(null)\n setScheduledDate(null)\n setState('idle')\n }, [editor, attachments, voiceNote, isStreaming, onSubmit, onSchedule, scheduledDate])\n\n // Wire submit ref (for enter-to-send extension)\n submitRef.current = handleSubmit\n\n // ── NO state tracking from editor events ──────────────────\n // Previous approach tracked idle/focused/composing via setState from TipTap\n // events. This caused React re-renders during ProseMirror DOM modifications →\n // \"removeChild\" crashes. Instead, we derive hasContent/editorIsEmpty at render\n // time, and use CSS :focus-within for focus styling. Only recording/review\n // states are tracked (user-triggered, not editor-triggered).\n\n // ── Editor height: pure CSS (no ResizeObserver/setState) ───\n // ResizeObserver was calling setEditorHeight during ProseMirror DOM changes,\n // triggering React re-renders → removeChild crashes. CSS min/max-height\n // + overflow-y: auto handles this natively without any state.\n\n // ── Typing Indicator ──────────────────────────────────────\n React.useEffect(() => {\n if (!editor || !onTyping) return\n const handleUpdate = () => {\n onTyping(true)\n clearTimeout(typingTimeoutRef.current)\n typingTimeoutRef.current = setTimeout(() => onTyping(false), 2000)\n }\n editor.on('update', handleUpdate)\n return () => {\n editor.off('update', handleUpdate)\n clearTimeout(typingTimeoutRef.current)\n }\n }, [editor, onTyping])\n\n // ── Empty State Callback ──────────────────────────────────\n React.useEffect(() => {\n if (!editor || !onEmpty) return\n const handleUpdate = () => { onEmpty(editor.isEmpty) }\n editor.on('update', handleUpdate)\n handleUpdate()\n return () => { editor.off('update', handleUpdate) }\n }, [editor, onEmpty])\n\n // ── File Handling ─────────────────────────────────────────\n const processFile = React.useCallback(async (file: File) => {\n const id = Math.random().toString(36).slice(2)\n const isImage = file.type.startsWith('image/')\n\n setAttachments(prev => [...prev, {\n id,\n name: file.name,\n size: file.size,\n type: isImage ? 'image' : 'file',\n uploading: true,\n }])\n\n try {\n if (isImage && onImageUpload) {\n const url = await onImageUpload(file)\n setAttachments(prev => prev.map(a => a.id === id ? { ...a, url, uploading: false } : a))\n } else if (onFileUpload) {\n const result = await onFileUpload(file)\n setAttachments(prev => prev.map(a => a.id === id ? { ...a, url: result.url, name: result.name, size: result.size, uploading: false } : a))\n } else {\n // No handler — create local URL for images\n if (isImage) {\n const url = URL.createObjectURL(file)\n setAttachments(prev => prev.map(a => a.id === id ? { ...a, url, uploading: false } : a))\n } else {\n setAttachments(prev => prev.filter(a => a.id !== id))\n }\n }\n } catch {\n setAttachments(prev => prev.filter(a => a.id !== id))\n }\n }, [onFileUpload, onImageUpload])\n\n const removeAttachment = React.useCallback((id: string) => {\n setAttachments(prev => prev.filter(a => a.id !== id))\n }, [])\n\n const handleDrop = React.useCallback((e: React.DragEvent) => {\n e.preventDefault()\n setIsDragging(false)\n const files = Array.from(e.dataTransfer.files)\n files.forEach(processFile)\n }, [processFile])\n\n const handleFileInput = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files || [])\n files.forEach(processFile)\n e.target.value = '' // reset so same file can be re-selected\n }, [processFile])\n\n // ── Voice Note Review Discard ─────────────────────────────\n const handleDiscardVoice = React.useCallback(() => {\n setVoiceNote(null)\n setState('idle')\n }, [])\n\n // ── Derived Values ────────────────────────────────────────\n // v3: useEditorState subscribes to editor changes so charCount/isEmpty\n // update without full parent re-renders on every transaction.\n const editorDerived = useEditorState({\n editor,\n selector: ({ editor: e }) => {\n if (!e) return null\n return { editorIsEmpty: e.isEmpty }\n },\n })\n const editorIsEmpty = editorDerived?.editorIsEmpty ?? true\n\n // Track character count via editor event (useEditorState's deep-equal comparison\n // swallows storage.characterCount changes since the function reference is stable)\n React.useEffect(() => {\n if (!editor) return\n const updateCount = () => {\n // Compute directly from document — CharacterCount storage.characters() returns 0 in TipTap v3\n const text = editor.state.doc.textBetween(0, editor.state.doc.content.size, undefined, ' ')\n setCharCount(text.length)\n }\n updateCount()\n editor.on('update', updateCount)\n return () => { editor.off('update', updateCount) }\n }, [editor])\n const hasContent = !editorIsEmpty || attachments.length > 0 || !!voiceNote\n const isInline = variant === 'inline'\n const showToolbar = toolbarExpanded || state === 'review' || variant === 'expanded'\n const btnSize = 'icon-md' as const\n const iconSize = 'md' as const\n\n return (\n <div\n ref={ref}\n className={cn(\n 'border-t border-surface-border-subtle px-ds-05 py-ds-04',\n 'flex items-center gap-ds-03',\n className,\n )}\n {...props}\n >\n {/* Action button outside the input on the left */}\n {actionButton !== false && (\n actionButton ?? (\n (onFileUpload || onImageUpload) ? (\n <Button\n variant=\"solid\"\n size=\"icon-md\"\n onClick={() => fileInputRef.current?.click()}\n title=\"Attach\"\n aria-label=\"Attach file\"\n className=\"shrink-0\"\n >\n <Icon icon={IconPlus} size=\"md\" />\n </Button>\n ) : null\n )\n )}\n\n {/* Container */}\n <div\n role=\"region\"\n aria-label=\"Message composer\"\n className={cn(\n 'flex-1 min-w-0 overflow-hidden rounded-surface border border-surface-border-strong bg-surface-raised-hover',\n 'transition-[color,background-color,border-color,box-shadow] duration-fast-02 ease-productive-standard',\n 'hover:bg-surface-raised-active',\n 'focus-within:ring-2 focus-within:ring-accent-9 focus-within:ring-offset-2 focus-within:border-accent-9',\n state === 'recording' && 'border-error-7/30',\n isDragging && 'border-dashed border-accent-7 bg-accent-2',\n disabled && 'opacity-action-disabled cursor-not-allowed',\n )}\n onFocus={() => setEditorFocused(true)}\n onBlur={(e) => { if (!e.currentTarget.contains(e.relatedTarget)) setEditorFocused(false) }}\n onDragOver={(e) => { e.preventDefault(); setIsDragging(true) }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={handleDrop}\n >\n {/* Leading slot */}\n {leadingSlot}\n\n {/* Zone 1: Reply Banner */}\n <AnimatePresence>\n {replyTo && (\n <ReplyBanner\n key=\"reply\"\n author={replyTo.author}\n preview={replyTo.preview}\n onDismiss={replyTo.onDismiss}\n />\n )}\n </AnimatePresence>\n\n {/* Schedule Banner */}\n <AnimatePresence>\n {scheduledDate && (\n <ScheduleBanner\n key=\"schedule\"\n date={scheduledDate}\n onEdit={() => setScheduleDialogOpen(true)}\n onClear={() => setScheduledDate(null)}\n />\n )}\n </AnimatePresence>\n\n {/* Zone 2: Attachment Strip */}\n <AnimatePresence>\n {attachments.length > 0 && (\n <AttachmentStrip\n key=\"attachments\"\n attachments={attachments}\n onRemoveAttachment={removeAttachment}\n />\n )}\n </AnimatePresence>\n\n {/* Toolbar above input (inline variant) — CSS transition */}\n {config.toolbarPosition === 'top' && editor && (\n <div\n className={cn(\n 'grid transition-[grid-template-rows,opacity] duration-moderate-01 ease-productive-standard',\n toolbarExpanded ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0 pointer-events-none',\n )}\n >\n <div className=\"overflow-hidden\">\n <ChatToolbar\n editor={editor}\n toolbar={toolbarProp}\n isMobile={false}\n hasMentions={!!(mentions || onMentionSearch)}\n hasSlashCommands={!!slashCommands}\n disabled={disabled}\n />\n </div>\n </div>\n )}\n\n {/* Zone 3: Editor (always mounted — never unmount TipTap) */}\n <div className=\"relative\">\n {/* Recording overlay — positioned over the editor, no AnimatePresence */}\n {state === 'recording' && (\n <RecordingOverlay\n duration={voiceRecorder.duration}\n analyserNode={voiceRecorder.analyserNode}\n maxDuration={maxDuration}\n onCancel={handleCancelRecording}\n />\n )}\n\n {/* Editor + inline action icons in one flex row */}\n <div\n ref={editorWrapperRef}\n className={cn(\n 'flex items-center px-ds-04 py-ds-03 cursor-text [&_.tiptap]:w-full [&_.tiptap]:outline-hidden',\n state === 'recording' && 'invisible',\n )}\n style={{\n minHeight: config.minHeight,\n maxHeight: maxHeightPx,\n overflowY: 'auto',\n }}\n onClick={() => editor?.commands.focus()}\n >\n {/* Editor takes all available space */}\n <div className=\"flex-1 min-w-0\">\n <EditorContent editor={editor} />\n </div>\n\n {/* Action icons — right-aligned inside input */}\n {editor && state !== 'recording' && (\n <div className=\"flex items-center gap-ds-01 shrink-0 ml-ds-03\">\n {/* Formatting toggle (A button) */}\n <button\n type=\"button\"\n onClick={() => setToolbarExpanded(prev => !prev)}\n title={toolbarExpanded ? 'Hide formatting' : 'Show formatting'}\n aria-label={toolbarExpanded ? 'Hide formatting' : 'Show formatting'}\n aria-pressed={toolbarExpanded}\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control touch-target',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n toolbarExpanded ? 'bg-surface-raised-hover text-accent-11' : 'text-surface-fg-subtle',\n )}\n >\n <Icon icon={IconTextSize} size=\"xs\" />\n </button>\n\n {/* Emoji picker */}\n <div className=\"relative\">\n <button\n ref={emojiAnchorRef}\n type=\"button\"\n onClick={() => setShowEmojiPicker(prev => !prev)}\n title=\"Emoji\"\n aria-label=\"Emoji\"\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control touch-target transition-colors duration-fast-01',\n showEmojiPicker ? 'bg-surface-raised-hover text-accent-11' : 'text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg',\n )}\n >\n <Icon icon={IconMoodSmile} size=\"xs\" />\n </button>\n {showEmojiPicker && ReactDOM.createPortal(\n <div ref={emojiFloatingRef} className=\"absolute z-popover\" style={{ top: 0, left: 0 }}>\n <EmojiPickerPopover\n onSelect={({ id, native }) => {\n editor.chain().focus().insertContent({\n type: 'emojiNode',\n attrs: { id, native },\n }).run()\n setShowEmojiPicker(false)\n }}\n onClose={() => setShowEmojiPicker(false)}\n />\n </div>,\n document.body,\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Voice Note Review — shown in 'review' state */}\n {state === 'review' && voiceNote && (\n <div className=\"flex items-center gap-ds-03 px-ds-04 py-ds-02b border-b border-surface-border\">\n <AudioPlayer\n src={voiceNote.blob}\n duration={voiceNote.duration}\n waveformData={voiceNote.waveformData}\n className=\"flex-1\"\n />\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={handleDiscardVoice}\n aria-label=\"Discard voice note\"\n title=\"Discard voice note\"\n className=\"text-surface-fg-subtle hover:text-error-11\"\n >\n <Icon icon={IconTrash} size=\"sm\" />\n </Button>\n </div>\n )}\n\n {/* Mobile BubbleMenu — shows on text selection */}\n {isMobile && editor && !editorIsEmpty && (\n <ChatBubbleMenu editor={editor} />\n )}\n\n {/* Zone 4: Toolbar below — CSS transition instead of AnimatePresence */}\n {config.toolbarPosition === 'bottom' && editor && (\n <div\n className={cn(\n 'grid transition-[grid-template-rows,opacity] duration-moderate-01 ease-productive-standard',\n showToolbar ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0 pointer-events-none',\n )}\n >\n <div className=\"overflow-hidden\">\n <ChatToolbar\n editor={editor}\n toolbar={toolbarProp}\n isMobile={isMobile}\n hasMentions={!!(mentions || onMentionSearch)}\n hasSlashCommands={!!slashCommands}\n disabled={disabled}\n />\n </div>\n </div>\n )}\n\n {/* Character counter */}\n {maxLength && charCountDisplay !== 'hidden' && (() => {\n const ratio = charCount / maxLength\n const showAlways = charCountDisplay === 'always'\n const showFocus = charCountDisplay === 'focus' && editorFocused\n const showNearLimit = (charCountDisplay === 'near-limit' || !charCountDisplay) && ratio >= 0.8\n const visible = showAlways || showFocus || showNearLimit || ratio >= 1\n\n if (!visible) return null\n\n return (\n <div className={cn(\n 'flex justify-end px-ds-04 pb-ds-02 text-ds-xs tabular-nums transition-opacity duration-fast-01',\n ratio >= 1 ? 'text-error-11 font-medium' : ratio >= 0.9 ? 'text-warning-11' : 'text-surface-fg-subtle',\n )}>\n {charCount}/{maxLength}\n </div>\n )\n })()}\n\n {/* Trailing slot */}\n {trailingSlot}\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n onChange={handleFileInput}\n />\n </div>\n\n {/* Send/mic/recording buttons — animated transitions between states */}\n <div className=\"flex items-center gap-ds-02 shrink-0\">\n {sendOptions && sendOptions.length > 0 && state !== 'recording' && (\n <SplitSendDropdown options={sendOptions} />\n )}\n <AnimatePresence mode=\"popLayout\" initial={false}>\n {state === 'recording' && (\n <motion.div\n key=\"recording\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n className=\"flex items-center gap-ds-02\"\n >\n <Button variant=\"soft\" size={btnSize} onClick={handleCancelRecording} aria-label=\"Cancel recording\" title=\"Cancel recording\" className=\"text-surface-fg-subtle hover:text-error-11\">\n <Icon icon={IconTrash} size={iconSize} />\n </Button>\n <Button variant=\"solid\" size={btnSize} color=\"error\" onClick={handleStopRecording} aria-label=\"Stop recording\" title=\"Stop recording\">\n <Icon icon={IconSquare} size={iconSize} />\n </Button>\n </motion.div>\n )}\n {isStreaming && state !== 'recording' && (\n <motion.div\n key=\"streaming\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <Button variant=\"solid\" size={btnSize} color=\"error\" onClick={onCancel} aria-label=\"Stop\" title=\"Stop\">\n <Icon icon={IconSquare} size={iconSize} />\n </Button>\n </motion.div>\n )}\n {!isStreaming && state !== 'recording' && hasContent && onSchedule && (\n <motion.div\n key=\"split-send\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <SplitButton\n onClick={handleSubmit}\n disabled={disabled}\n aria-label={scheduledDate ? 'Schedule send' : 'Send'}\n size={btnSize}\n dropdownContent={\n <ScheduleDropdownContent\n onSchedule={(date) => setScheduledDate(date)}\n onClose={() => {}}\n onOpenDialog={() => setScheduleDialogOpen(true)}\n />\n }\n >\n <Icon icon={scheduledDate ? IconClock : IconSend} size={iconSize} />\n </SplitButton>\n </motion.div>\n )}\n {!isStreaming && state !== 'recording' && hasContent && !onSchedule && (\n <motion.div\n key=\"send\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <Button variant=\"solid\" size={btnSize} onClick={handleSubmit} disabled={disabled} aria-label=\"Send\" title=\"Send\">\n <Icon icon={IconSend} size={iconSize} />\n </Button>\n </motion.div>\n )}\n {!isStreaming && state !== 'recording' && !hasContent && onVoiceRecord && (\n <motion.div\n key=\"mic\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <Button variant=\"soft\" size={btnSize} onClick={handleStartRecording} aria-label=\"Record voice message\" title=\"Record voice message\">\n <Icon icon={IconMicrophone} size={iconSize} />\n </Button>\n </motion.div>\n )}\n {!isStreaming && state !== 'recording' && !hasContent && !onVoiceRecord && (\n <motion.div\n key=\"send-disabled\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <Button variant=\"solid\" size={btnSize} disabled aria-label=\"Send\" title=\"Send\">\n <Icon icon={IconSend} size={iconSize} />\n </Button>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n\n {/* Disclaimer */}\n {disclaimer && (\n <p className=\"mt-ds-02 text-center text-ds-xs text-surface-fg-subtle/50\">\n {disclaimer}\n </p>\n )}\n\n {/* Schedule Dialog (full picker) */}\n {onSchedule && (\n <ScheduleDialog\n open={scheduleDialogOpen}\n onOpenChange={setScheduleDialogOpen}\n onSchedule={(date) => setScheduledDate(date)}\n initialDate={scheduledDate}\n />\n )}\n </div>\n )\n },\n)\nRichChatInput.displayName = 'RichChatInput'\n\nexport { RichChatInput }\nexport type { ChatToolbarItem }\n\n// Re-export toolbar primitives for custom toolbar composition\nexport {\n BlockquoteButton,\n BoldButton,\n BulletListButton,\n CodeButton,\n EmojiButton,\n HighlightButton,\n ItalicButton,\n LinkButton,\n MentionButton,\n OrderedListButton,\n SlashCommandButton,\n StrikeButton,\n ToolbarButton,\n ToolbarDivider,\n ToolbarGroup,\n UnderlineButton,\n} from './rich-chat-input/chat-toolbar'\n"],"mappings":"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"}
1
+ {"version":3,"file":"rich-chat-input.js","names":[],"sources":["../../src/composed/extensions/slash-command.tsx","../../src/composed/rich-chat-input/attachment-strip.tsx","../../src/composed/rich-chat-input/audio-waveform.tsx","../../src/composed/rich-chat-input/audio-player.tsx","../../src/composed/rich-chat-input/chat-toolbar.tsx","../../src/composed/rich-chat-input/recording-overlay.tsx","../../src/composed/rich-chat-input/reply-banner.tsx","../../src/composed/rich-chat-input/schedule-send.tsx","../../src/composed/rich-chat-input/use-voice-recorder.ts","../../src/composed/rich-chat-input.tsx"],"sourcesContent":["'use client'\n\nimport type { Editor } from '@tiptap/core'\nimport { Extension } from '@tiptap/core'\nimport Suggestion, { type SuggestionKeyDownProps,type SuggestionProps } from '@tiptap/suggestion'\nimport { PluginKey } from 'prosemirror-state'\nimport * as React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\n\nimport { cn } from '../../ui/lib/utils'\n\nexport interface SlashCommand {\n id: string\n label: string\n description?: string\n icon?: React.ComponentType<{ className?: string }>\n action: (editor: Editor) => void\n}\n\nexport interface SlashCommandGroup {\n label: string\n commands: SlashCommand[]\n}\n\n// ── Flat item used for keyboard navigation index ────────────────────\ninterface FlatItem {\n command: SlashCommand\n groupIndex: number\n}\n\ninterface SlashCommandListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface SlashCommandListProps {\n groups: SlashCommandGroup[]\n query: string\n command: (item: SlashCommand) => void\n}\n\nconst SlashCommandList = React.forwardRef<SlashCommandListRef, SlashCommandListProps>(\n ({ groups, query, command }, ref) => {\n const [selectedIndex, setSelectedIndex] = React.useState(0)\n\n // Flatten filtered groups into a single list for keyboard navigation\n const filtered = React.useMemo(() => {\n const q = query.toLowerCase()\n const flat: FlatItem[] = []\n groups.forEach((group, gi) => {\n group.commands.forEach((cmd) => {\n if (\n !q ||\n cmd.label.toLowerCase().includes(q) ||\n cmd.description?.toLowerCase().includes(q)\n ) {\n flat.push({ command: cmd, groupIndex: gi })\n }\n })\n })\n return flat\n }, [groups, query])\n\n React.useEffect(() => setSelectedIndex(0), [filtered])\n\n React.useImperativeHandle(ref, () => ({\n onKeyDown: ({ event }: SuggestionKeyDownProps) => {\n if (event.key === 'ArrowUp') {\n setSelectedIndex((i) => (i + filtered.length - 1) % filtered.length)\n return true\n }\n if (event.key === 'ArrowDown') {\n setSelectedIndex((i) => (i + 1) % filtered.length)\n return true\n }\n if (event.key === 'Enter') {\n if (filtered[selectedIndex]) command(filtered[selectedIndex].command)\n return true\n }\n return false\n },\n }))\n\n if (!filtered.length) return null\n\n // Re-group filtered items for rendering with group headers\n const renderedGroups: { label: string; items: { command: SlashCommand; flatIndex: number }[] }[] = []\n let flatIndex = 0\n for (const item of filtered) {\n const groupLabel = groups[item.groupIndex].label\n let last = renderedGroups[renderedGroups.length - 1]\n if (!last || last.label !== groupLabel) {\n last = { label: groupLabel, items: [] }\n renderedGroups.push(last)\n }\n last.items.push({ command: item.command, flatIndex })\n flatIndex++\n }\n\n return (\n <div\n role=\"listbox\"\n aria-label=\"Slash commands\"\n className=\"z-popover max-h-[320px] min-w-[220px] overflow-x-hidden overflow-y-auto rounded-surface bg-surface-overlay p-ds-02 shadow-floating\"\n >\n {renderedGroups.map((group, gi) => (\n <div key={group.label} role=\"group\" aria-label={group.label}>\n {gi > 0 && <div className=\"my-ds-01 border-t border-surface-border\" />}\n <div className=\"px-ds-03 py-ds-01 text-ds-xs font-medium text-surface-fg-subtle\">\n {group.label}\n </div>\n {group.items.map(({ command: cmd, flatIndex: fi }) => {\n const IconComp = cmd.icon\n return (\n <button\n key={cmd.id}\n type=\"button\"\n role=\"option\"\n aria-selected={fi === selectedIndex}\n onClick={() => command(cmd)}\n className={cn(\n 'flex w-full items-center gap-ds-03 rounded-control px-ds-03 py-ds-02 text-left cursor-pointer',\n fi === selectedIndex\n ? 'bg-surface-raised-hover'\n : 'hover:bg-surface-raised-hover',\n )}\n >\n {IconComp && (\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center text-surface-fg-muted\">\n <IconComp className=\"h-4 w-4\" />\n </span>\n )}\n <div className=\"flex flex-col\">\n <span className=\"text-ds-sm text-surface-fg\">{cmd.label}</span>\n {cmd.description && (\n <span className=\"text-ds-xs text-surface-fg-subtle\">{cmd.description}</span>\n )}\n </div>\n </button>\n )\n })}\n </div>\n ))}\n </div>\n )\n },\n)\nSlashCommandList.displayName = 'SlashCommandList'\n\nfunction createSlashCommandRenderer(groups: SlashCommandGroup[]) {\n return () => {\n let root: Root | null = null\n let container: HTMLDivElement | null = null\n let componentRef: SlashCommandListRef | null = null\n\n return {\n onStart: (props: SuggestionProps<SlashCommand>) => {\n container = document.createElement('div')\n container.style.position = 'absolute'\n container.style.zIndex = '1400' // z-popover\n\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n document.body.appendChild(container)\n\n root = createRoot(container)\n root.render(\n <SlashCommandList\n ref={(r) => { componentRef = r }}\n groups={groups}\n query={props.query}\n command={(cmd) => props.command(cmd as any)}\n />,\n )\n },\n\n onUpdate: (props: SuggestionProps<SlashCommand>) => {\n if (!root || !container) return\n\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n\n root.render(\n <SlashCommandList\n ref={(r) => { componentRef = r }}\n groups={groups}\n query={props.query}\n command={(cmd) => props.command(cmd as any)}\n />,\n )\n },\n\n onKeyDown: (props: SuggestionKeyDownProps) => {\n if (props.event.key === 'Escape') {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n return true\n }\n return componentRef?.onKeyDown(props) ?? false\n },\n\n onExit: () => {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n },\n }\n }\n}\n\n/**\n * Creates a configured TipTap Extension for slash commands.\n *\n * Triggers on `/` at the start of a line, shows a grouped command palette,\n * and executes the selected command's action on the editor.\n *\n * @example\n * const slashExt = createSlashCommandExtension([\n * {\n * label: 'Format',\n * commands: [\n * { id: 'h1', label: 'Heading 1', action: (editor) => editor.chain().focus().toggleHeading({ level: 1 }).run() },\n * { id: 'bullet', label: 'Bullet List', action: (editor) => editor.chain().focus().toggleBulletList().run() },\n * ],\n * },\n * ])\n */\nexport function createSlashCommandExtension(groups: SlashCommandGroup[]) {\n // Flatten all commands for the items callback\n const allCommands = groups.flatMap((g) => g.commands)\n\n return Extension.create({\n name: 'slashCommand',\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n pluginKey: new PluginKey('slashCommand'),\n editor: this.editor,\n char: '/',\n startOfLine: true,\n allowSpaces: false,\n items: ({ query }) => {\n if (!query) return allCommands.slice(0, 8)\n const q = query.toLowerCase()\n return allCommands\n .filter(\n (cmd) =>\n cmd.label.toLowerCase().includes(q) ||\n cmd.description?.toLowerCase().includes(q),\n )\n .slice(0, 8)\n },\n command: ({ editor, range, props: item }) => {\n // Delete the /query text, then execute the command action\n editor.chain().focus().deleteRange(range).run()\n ;(item as unknown as SlashCommand).action(editor)\n },\n render: createSlashCommandRenderer(groups),\n }),\n ]\n },\n })\n}\n","'use client'\n\nimport { IconFile,IconX } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { durations } from '../../ui/lib/motion'\nimport { Spinner } from '../../ui/spinner'\nimport { TruncatedText } from '../../ui/truncated-text'\n\nexport interface Attachment {\n id: string\n url?: string\n name: string\n size: number\n type: 'image' | 'file'\n uploading: boolean\n}\n\nexport interface AttachmentStripProps {\n attachments: Attachment[]\n onRemoveAttachment: (id: string) => void\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nexport function AttachmentStrip({\n attachments,\n onRemoveAttachment,\n}: AttachmentStripProps) {\n return (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: durations.moderate02, ease: [0.2, 0, 0.38, 0.9] }}\n className=\"overflow-hidden\"\n >\n <div\n role=\"list\"\n aria-label=\"Attachments\"\n className=\"flex gap-ds-02 overflow-x-auto px-ds-04 py-ds-02b border-b border-surface-border\"\n >\n <AnimatePresence initial={false}>\n {attachments.map((att) =>\n att.type === 'image' ? (\n <motion.div\n key={att.id}\n role=\"listitem\"\n aria-label={`Image: ${att.name}`}\n layout\n initial={{ scale: 0, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.95, opacity: 0 }}\n transition={{\n /* Near springs.snappy (500/30/0.5) — intentionally softer for thumbnail pop-in */\n layout: { type: 'spring', stiffness: 400, damping: 30 },\n scale: { type: 'spring', stiffness: 400, damping: 30 },\n opacity: { duration: durations.fast02 },\n }}\n /* h-12 w-12 (48px): component-specific thumbnail size — no design token equivalent */\n className=\"relative h-12 w-12 shrink-0 group\"\n >\n <img\n src={att.url}\n alt={att.name}\n className=\"h-full w-full rounded-control object-cover\"\n />\n <button\n onClick={() => onRemoveAttachment(att.id)}\n className=\"absolute -top-1 -right-1 h-ico-sm w-ico-sm rounded-pill bg-error-9 text-error-fg flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-fast-02\"\n aria-label={`Remove ${att.name}`}\n title=\"Remove\"\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n {att.uploading && (\n <div className=\"absolute inset-0 rounded-control bg-surface-overlay/50 flex items-center justify-center\">\n <Spinner size=\"sm\" />\n </div>\n )}\n </motion.div>\n ) : (\n <motion.div\n key={att.id}\n role=\"listitem\"\n aria-label={`File: ${att.name}, ${formatSize(att.size)}`}\n layout\n initial={{ scale: 0, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.95, opacity: 0 }}\n transition={{\n /* Near springs.snappy (500/30/0.5) — intentionally softer for file chip pop-in */\n layout: { type: 'spring', stiffness: 400, damping: 30 },\n scale: { type: 'spring', stiffness: 400, damping: 30 },\n opacity: { duration: durations.fast02 },\n }}\n className=\"flex items-center gap-ds-02 shrink-0 rounded-control bg-surface-raised px-ds-03 py-ds-01 group\"\n >\n <Icon\n icon={IconFile}\n size=\"xs\"\n className=\"text-surface-fg-muted\"\n />\n {/* max-w-[120px]: component-specific truncation width for file names */}\n <TruncatedText mode=\"middle\" className=\"max-w-[120px] text-ds-xs text-surface-fg-muted\">\n {att.name}\n </TruncatedText>\n <span className=\"text-ds-xs text-surface-fg-subtle\">\n {formatSize(att.size)}\n </span>\n <button\n onClick={() => onRemoveAttachment(att.id)}\n className=\"text-surface-fg-subtle hover:text-error-11 opacity-0 group-hover:opacity-100 transition-opacity duration-fast-02\"\n aria-label={`Remove ${att.name}`}\n title=\"Remove\"\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n </motion.div>\n )\n )}\n </AnimatePresence>\n </div>\n </motion.div>\n )\n}\n","'use client'\n\nimport * as React from 'react'\n\nimport { cn } from '../../ui/lib/utils'\n\ninterface AudioWaveformProps extends React.SVGAttributes<SVGSVGElement> {\n /** 'live' reads from AnalyserNode in real-time. 'static' renders pre-computed data. */\n mode: 'live' | 'static'\n /** Web Audio API analyser node — required for live mode */\n analyserNode?: AnalyserNode | null\n /** Pre-computed amplitude data (0-1 normalized) — required for static mode */\n data?: number[]\n /** Playback progress 0-1 — static mode only, controls fill coloring */\n progress?: number\n /** Bar width in pixels @default 3 */\n barWidth?: number\n /** Gap between bars in pixels @default 2 */\n barGap?: number\n /** Number of bars to render @default 40 */\n barCount?: number\n /** Height in pixels @default 32 */\n height?: number\n}\n\nconst AudioWaveform = React.forwardRef<SVGSVGElement, AudioWaveformProps>(\n function AudioWaveform(\n {\n mode,\n analyserNode,\n data,\n progress = 0,\n barWidth = 3,\n barGap = 2,\n barCount = 40,\n height = 32,\n className,\n ...props\n },\n ref\n ) {\n const [bars, setBars] = React.useState<number[]>(() =>\n new Array(barCount).fill(0.05)\n )\n const animFrameRef = React.useRef<number>(0)\n const prevBarsRef = React.useRef<number[]>(bars)\n\n // Live mode — read from AnalyserNode on each animation frame\n React.useEffect(() => {\n if (mode !== 'live' || !analyserNode) return\n\n const dataArray = new Uint8Array(analyserNode.frequencyBinCount)\n const smoothingFactor = 0.3\n\n const tick = () => {\n analyserNode.getByteFrequencyData(dataArray)\n\n const barsPerBin = Math.floor(dataArray.length / barCount)\n const newBars = new Array(barCount)\n\n for (let i = 0; i < barCount; i++) {\n let sum = 0\n for (let j = 0; j < barsPerBin; j++) {\n sum += dataArray[i * barsPerBin + j]\n }\n const target = sum / (barsPerBin * 255)\n newBars[i] =\n prevBarsRef.current[i] +\n (target - prevBarsRef.current[i]) * smoothingFactor\n }\n\n prevBarsRef.current = newBars\n setBars(newBars)\n animFrameRef.current = requestAnimationFrame(tick)\n }\n\n animFrameRef.current = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(animFrameRef.current)\n }, [mode, analyserNode, barCount])\n\n // Static mode — resample pre-computed data to barCount bars\n React.useEffect(() => {\n if (mode !== 'static' || !data) return\n\n if (data.length === barCount) {\n setBars(data)\n } else {\n const resampled = new Array(barCount)\n const ratio = data.length / barCount\n for (let i = 0; i < barCount; i++) {\n const index = Math.floor(i * ratio)\n resampled[i] = data[Math.min(index, data.length - 1)]\n }\n setBars(resampled)\n }\n }, [mode, data, barCount])\n\n const svgWidth = barCount * (barWidth + barGap) - barGap\n\n const renderedBars = React.useMemo(\n () =>\n bars.map((amplitude, i) => {\n const barHeight = Math.max(2, amplitude * height)\n const x = i * (barWidth + barGap)\n const y = (height - barHeight) / 2\n const isFilled =\n mode === 'static' && progress > 0 && i / barCount <= progress\n\n return (\n <rect\n key={i}\n x={x}\n y={y}\n width={barWidth}\n height={barHeight}\n rx={barWidth / 2}\n fill={\n isFilled\n ? 'var(--color-accent-9)'\n : 'var(--color-surface-border)'\n }\n />\n )\n }),\n [bars, progress, mode, barWidth, barGap, barCount, height]\n )\n\n return (\n <svg\n ref={ref}\n height={height}\n viewBox={`0 0 ${svgWidth} ${height}`}\n preserveAspectRatio=\"none\"\n aria-hidden=\"true\"\n className={cn('shrink-0', className)}\n {...props}\n >\n {renderedBars}\n </svg>\n )\n }\n)\nAudioWaveform.displayName = 'AudioWaveform'\n\nexport { AudioWaveform }\nexport type { AudioWaveformProps }\n","'use client'\n\nimport { IconPlayerPause,IconPlayerPlay } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Button } from '../../ui/button'\nimport { cn } from '../../ui/lib/utils'\nimport { AudioWaveform } from './audio-waveform'\n\ninterface AudioPlayerProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n src: string | Blob\n duration: number\n waveformData?: number[]\n}\n\nconst SPEEDS = [1, 1.5, 2] as const\n\nfunction formatTime(seconds: number): string {\n const m = Math.floor(seconds / 60)\n const s = Math.floor(seconds % 60)\n return `${m}:${s.toString().padStart(2, '0')}`\n}\n\nconst AudioPlayer = React.forwardRef<HTMLDivElement, AudioPlayerProps>(\n function AudioPlayer({ src, duration, waveformData, className, ...props }, ref) {\n const audioRef = React.useRef<HTMLAudioElement>(null)\n const waveformRef = React.useRef<SVGSVGElement>(null)\n const [playing, setPlaying] = React.useState(false)\n const [currentTime, setCurrentTime] = React.useState(0)\n const [speedIndex, setSpeedIndex] = React.useState(0)\n const [objectUrl, setObjectUrl] = React.useState<string | null>(null)\n\n // Resolve src to a URL string, managing Blob object URLs\n const audioSrc = React.useMemo(() => {\n if (typeof src === 'string') return src\n const url = URL.createObjectURL(src)\n setObjectUrl(url)\n return url\n }, [src])\n\n // Revoke object URL on src change or unmount\n React.useEffect(() => {\n return () => {\n if (objectUrl) {\n URL.revokeObjectURL(objectUrl)\n }\n }\n }, [objectUrl])\n\n // Sync audio timeupdate to state\n React.useEffect(() => {\n const audio = audioRef.current\n if (!audio) return\n\n const onTimeUpdate = () => setCurrentTime(audio.currentTime)\n const onEnded = () => {\n setPlaying(false)\n setCurrentTime(0)\n }\n\n audio.addEventListener('timeupdate', onTimeUpdate)\n audio.addEventListener('ended', onEnded)\n return () => {\n audio.removeEventListener('timeupdate', onTimeUpdate)\n audio.removeEventListener('ended', onEnded)\n }\n }, [])\n\n const togglePlay = React.useCallback(() => {\n const audio = audioRef.current\n if (!audio) return\n\n if (playing) {\n audio.pause()\n setPlaying(false)\n } else {\n audio.play()\n setPlaying(true)\n }\n }, [playing])\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault()\n togglePlay()\n }\n },\n [togglePlay]\n )\n\n const handleSeek = React.useCallback(\n (e: React.MouseEvent<SVGSVGElement>) => {\n const audio = audioRef.current\n const svg = waveformRef.current\n if (!audio || !svg || duration <= 0) return\n\n const rect = svg.getBoundingClientRect()\n const x = e.clientX - rect.left\n const ratio = Math.max(0, Math.min(1, x / rect.width))\n audio.currentTime = ratio * duration\n setCurrentTime(audio.currentTime)\n },\n [duration]\n )\n\n const cycleSpeed = React.useCallback(() => {\n const next = (speedIndex + 1) % SPEEDS.length\n setSpeedIndex(next)\n if (audioRef.current) {\n audioRef.current.playbackRate = SPEEDS[next]\n }\n }, [speedIndex])\n\n const progress = duration > 0 ? currentTime / duration : 0\n const speed = SPEEDS[speedIndex]\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label=\"Voice message player\"\n className={cn('flex items-center gap-ds-03', className)}\n {...props}\n >\n {/* Hidden audio element — captions not applicable for voice messages */}\n {/* eslint-disable-next-line jsx-a11y/media-has-caption */}\n <audio ref={audioRef} src={audioSrc} preload=\"metadata\" />\n\n {/* Play/Pause button */}\n <Button\n type=\"button\"\n variant=\"solid\"\n shape=\"pill\"\n size=\"icon-sm\"\n onClick={togglePlay}\n onKeyDown={handleKeyDown}\n aria-label={playing ? 'Pause voice message' : 'Play voice message'}\n className=\"shrink-0 active:scale-95\"\n >\n {playing ? (\n <IconPlayerPause size={16} stroke={2} aria-hidden=\"true\" />\n ) : (\n <IconPlayerPlay size={16} stroke={2} aria-hidden=\"true\" />\n )}\n </Button>\n\n {/* Waveform with seek */}\n <AudioWaveform\n ref={waveformRef}\n mode=\"static\"\n data={waveformData}\n progress={progress}\n className=\"cursor-pointer\"\n onClick={handleSeek}\n />\n\n {/* Duration display */}\n <span className=\"text-ds-xs tabular-nums text-surface-fg-subtle whitespace-nowrap\">\n {formatTime(currentTime)} / {formatTime(duration)}\n </span>\n\n {/* Speed control */}\n <button\n type=\"button\"\n onClick={cycleSpeed}\n aria-label={`Playback speed ${speed}x`}\n className=\"shrink-0 text-ds-xs bg-surface-raised rounded-pill px-ds-02 py-[1px] hover:bg-surface-raised-hover tabular-nums transition-colors duration-fast-01 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2\"\n >\n {speed}x\n </button>\n </div>\n )\n }\n)\nAudioPlayer.displayName = 'AudioPlayer'\n\nexport { AudioPlayer }\nexport type { AudioPlayerProps }\n","'use client'\n\nimport {\n IconAt,\n IconBlockquote,\n IconBold,\n IconCode,\n IconHighlight,\n IconItalic,\n IconLink,\n IconList,\n IconListNumbers,\n IconMoodSmile,\n IconSlash,\n IconStrikethrough,\n IconUnderline,\n} from '@tabler/icons-react'\n// motion removed — CSS transitions handle show/hide from parent\nimport type { Editor } from '@tiptap/core'\nimport { useEditorState } from '@tiptap/react'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { cn } from '../../ui/lib/utils'\n\n// ── Toolbar Context ─────────────────────────────────────────────\n// Shares the TipTap editor instance with all toolbar primitives\n\nconst ToolbarContext = React.createContext<{ editor: Editor; disabled: boolean } | null>(null)\n\nfunction useToolbarEditor() {\n const ctx = React.useContext(ToolbarContext)\n if (!ctx) throw new Error('Toolbar primitives must be used inside <ChatToolbar>')\n return ctx\n}\n\n// ── Toolbar Primitives (exported for custom toolbars) ───────────\n\n/**\n * A single toolbar button. Use for built-in or custom actions.\n *\n * @example\n * <ToolbarButton onClick={() => editor.chain().focus().toggleBold().run()} isActive={editor.isActive('bold')} title=\"Bold\">\n * <Icon icon={IconBold} size=\"xs\" />\n * </ToolbarButton>\n */\nexport function ToolbarButton({\n onClick,\n isActive,\n disabled: disabledProp,\n title,\n children,\n className: classNameProp,\n}: {\n onClick: () => void\n isActive?: boolean\n disabled?: boolean\n title: string\n children: React.ReactNode\n className?: string\n}) {\n const { disabled: ctxDisabled } = useToolbarEditor()\n const isDisabled = disabledProp ?? ctxDisabled\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={isDisabled}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n className={cn(\n 'inline-flex h-ds-xs-plus items-center justify-center rounded-control touch-target',\n !classNameProp?.includes('w-') && 'w-ds-xs-plus',\n 'transition-[color,background-color,transform] duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover hover:text-surface-fg',\n 'active:scale-95',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n isActive ? 'bg-surface-raised-hover text-accent-11' : 'text-surface-fg-subtle',\n classNameProp,\n )}\n >\n {children}\n </button>\n )\n}\n\n/** Visual separator between toolbar button groups. */\nexport function ToolbarDivider() {\n return <div className=\"h-4 w-px bg-surface-border-subtle mx-ds-01\" />\n}\n\n/** Group wrapper — applies consistent spacing to a set of buttons. */\nexport function ToolbarGroup({ children, className }: { children: React.ReactNode; className?: string }) {\n return <div className={cn('flex items-center gap-ds-01', className)}>{children}</div>\n}\n\n// ── Pre-built Formatting Buttons (convenience exports) ──────────\n// Each reads the editor from context and wires the correct command.\n\nexport function BoldButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('bold') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBold().run()} isActive={isActive} title=\"Bold\">\n <Icon icon={IconBold} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function ItalicButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('italic') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleItalic().run()} isActive={isActive} title=\"Italic\">\n <Icon icon={IconItalic} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function UnderlineButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('underline') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleUnderline().run()} isActive={isActive} title=\"Underline\">\n <Icon icon={IconUnderline} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function StrikeButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('strike') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleStrike().run()} isActive={isActive} title=\"Strikethrough\">\n <Icon icon={IconStrikethrough} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function HighlightButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('highlight') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHighlight().run()} isActive={isActive} title=\"Highlight\">\n <Icon icon={IconHighlight} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function CodeButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('code') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleCode().run()} isActive={isActive} title=\"Inline code\">\n <Icon icon={IconCode} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function BulletListButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('bulletList') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBulletList().run()} isActive={isActive} title=\"Bullet list\">\n <Icon icon={IconList} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function OrderedListButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('orderedList') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleOrderedList().run()} isActive={isActive} title=\"Ordered list\">\n <Icon icon={IconListNumbers} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function BlockquoteButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('blockquote') }),\n })\n return (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBlockquote().run()} isActive={isActive} title=\"Quote\">\n <Icon icon={IconBlockquote} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function LinkButton() {\n const { editor } = useToolbarEditor()\n const { isActive } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isActive: e.isActive('link') }),\n })\n return (\n <ToolbarButton\n onClick={() => {\n const url = window.prompt('URL')\n if (url) editor.chain().focus().setLink({ href: url }).run()\n }}\n isActive={isActive}\n title=\"Link\"\n >\n <Icon icon={IconLink} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function MentionButton() {\n const { editor } = useToolbarEditor()\n return (\n <ToolbarButton onClick={() => editor.chain().focus().insertContent('@').run()} title=\"Mention\">\n <Icon icon={IconAt} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function EmojiButton() {\n const { editor } = useToolbarEditor()\n return (\n <ToolbarButton onClick={() => editor.chain().focus().insertContent(':').run()} title=\"Emoji\">\n <Icon icon={IconMoodSmile} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\nexport function SlashCommandButton() {\n const { editor } = useToolbarEditor()\n return (\n <ToolbarButton onClick={() => editor.chain().focus().insertContent('/').run()} title=\"Slash command\">\n <Icon icon={IconSlash} size=\"xs\" />\n </ToolbarButton>\n )\n}\n\n// ── Default Toolbar Presets ─────────────────────────────────────\n\nexport type ChatToolbarItem =\n | 'bold' | 'italic' | 'underline' | 'strike' | 'highlight' | 'code'\n | 'bulletList' | 'orderedList'\n | 'blockquote' | 'link'\n | 'mention' | 'emoji' | 'slash'\n\n/** The default toolbar layout — used when `toolbar={true}` or `toolbar={[...items]}` */\nfunction DefaultToolbar({ items, isMobile, hasMentions, hasSlashCommands }: {\n items: ChatToolbarItem[] | null\n isMobile: boolean\n hasMentions: boolean\n hasSlashCommands: boolean\n}) {\n const show = (item: ChatToolbarItem) => !items || items.includes(item)\n\n return (\n <>\n {/* Inline formatting — desktop only */}\n {!isMobile && (\n <ToolbarGroup>\n {show('bold') && <BoldButton />}\n {show('italic') && <ItalicButton />}\n {show('underline') && <UnderlineButton />}\n {show('strike') && <StrikeButton />}\n {show('highlight') && <HighlightButton />}\n </ToolbarGroup>\n )}\n\n {!isMobile && <ToolbarDivider />}\n\n {/* Lists — desktop only */}\n {!isMobile && (\n <ToolbarGroup>\n {show('bulletList') && <BulletListButton />}\n {show('orderedList') && <OrderedListButton />}\n </ToolbarGroup>\n )}\n\n {!isMobile && (show('blockquote') || show('link') || show('code')) && <ToolbarDivider />}\n\n {/* Block insert — desktop only */}\n {!isMobile && (\n <ToolbarGroup>\n {show('blockquote') && <BlockquoteButton />}\n {show('link') && <LinkButton />}\n {show('code') && <CodeButton />}\n </ToolbarGroup>\n )}\n\n {!isMobile && (hasMentions || hasSlashCommands) && <ToolbarDivider />}\n\n {/* Insert group — always visible */}\n <ToolbarGroup>\n {hasMentions && show('mention') && <MentionButton />}\n {show('emoji') && <EmojiButton />}\n {hasSlashCommands && show('slash') && <SlashCommandButton />}\n </ToolbarGroup>\n </>\n )\n}\n\n// ── ChatToolbar (main component) ────────────────────────────────\n\nexport interface ChatToolbarProps {\n editor: Editor\n /** true = default layout, ChatToolbarItem[] = whitelist, false = hidden, ReactNode = custom */\n toolbar: boolean | ChatToolbarItem[] | React.ReactNode\n isMobile: boolean\n hasMentions: boolean\n hasSlashCommands: boolean\n disabled: boolean\n}\n\nexport function ChatToolbar({\n editor,\n toolbar,\n isMobile,\n hasMentions,\n hasSlashCommands,\n disabled,\n}: ChatToolbarProps) {\n // toolbar={false} → don't render\n if (toolbar === false) return null\n\n const isCustom = typeof toolbar !== 'boolean' && !Array.isArray(toolbar)\n const items = Array.isArray(toolbar) ? toolbar : null\n\n return (\n <ToolbarContext.Provider value={{ editor, disabled }}>\n <div\n role=\"toolbar\"\n aria-label=\"Text formatting\"\n className=\"flex flex-wrap items-center gap-ds-01 border-t border-surface-border px-ds-04 py-ds-02b\"\n >\n {isCustom ? (\n // Consumer provides their own toolbar content\n toolbar\n ) : (\n // Default layout (full or whitelist)\n <DefaultToolbar items={items} isMobile={isMobile} hasMentions={hasMentions} hasSlashCommands={hasSlashCommands} />\n )}\n </div>\n </ToolbarContext.Provider>\n )\n}\n","'use client'\n\nimport { useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { cn } from '../../ui/lib/utils'\nimport { AudioWaveform } from './audio-waveform'\n\ninterface RecordingOverlayProps {\n duration: number\n analyserNode: AnalyserNode | null\n maxDuration?: number\n /** Escape key handler — cancel recording. Stop/cancel buttons are external. */\n onCancel: () => void\n}\n\nfunction formatTimer(seconds: number): { minutes: string; separator: string; secs: string } {\n const m = Math.floor(seconds / 60)\n const s = Math.floor(seconds % 60)\n return {\n minutes: String(m),\n separator: ':',\n secs: s.toString().padStart(2, '0'),\n }\n}\n\nfunction RecordingOverlay({\n duration,\n analyserNode,\n maxDuration,\n onCancel,\n}: RecordingOverlayProps) {\n const prefersReduced = useReducedMotion()\n\n // Escape key cancels recording\n React.useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onCancel()\n }\n }\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [onCancel])\n\n // Timing states\n const isWarning = maxDuration != null && maxDuration > 0 && duration >= maxDuration - 10\n const isCritical = maxDuration != null && maxDuration > 0 && duration >= maxDuration - 5\n\n // Pulse speed: faster when critical\n const pulseAnimation = isCritical\n ? 'animate-[pulse_500ms_ease-in-out_infinite]'\n : 'animate-[pulse_1s_ease-in-out_infinite]'\n\n const timer = formatTimer(duration)\n\n const timerColorClass = isCritical\n ? 'text-error-11'\n : isWarning\n ? 'text-warning-11'\n : 'text-surface-fg'\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Recording voice message\"\n className=\"absolute inset-0 flex items-center gap-ds-03 px-ds-04 py-ds-03 bg-surface-raised-hover rounded-surface z-10\"\n >\n {/* Red pulsing dot */}\n <span\n className={cn(\n 'w-ds-02b h-ds-02b shrink-0 rounded-pill bg-error-9',\n prefersReduced ? 'opacity-100' : pulseAnimation\n )}\n aria-hidden=\"true\"\n />\n\n {/* Timer */}\n <span\n className={cn(\n 'text-ds-sm font-mono tabular-nums whitespace-nowrap',\n timerColorClass\n )}\n aria-label={`${timer.minutes} minutes ${timer.secs} seconds`}\n >\n {timer.minutes}\n <span\n className={prefersReduced ? undefined : 'animate-[blink_1s_step-end_infinite]'}\n aria-hidden=\"true\"\n >\n {timer.separator}\n </span>\n {timer.secs}\n </span>\n\n {/* Live waveform — stop/cancel buttons are external (right-side button area) */}\n <div className=\"flex-1 min-w-0 overflow-hidden\">\n <AudioWaveform\n mode=\"live\"\n analyserNode={analyserNode}\n height={24}\n barCount={60}\n className=\"w-full\"\n />\n </div>\n </div>\n )\n}\nRecordingOverlay.displayName = 'RecordingOverlay'\n\nexport { RecordingOverlay }\nexport type { RecordingOverlayProps }\n","'use client'\n\nimport { IconX } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from '../../ui/icon'\nimport { durations } from '../../ui/lib/motion'\nimport { cn } from '../../ui/lib/utils'\n\nexport interface ReplyBannerProps {\n author: string\n preview: string\n onDismiss: () => void\n}\n\nexport function ReplyBanner({ author, preview, onDismiss }: ReplyBannerProps) {\n return (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: durations.moderate02, ease: [0.2, 0, 0.38, 0.9] }}\n className=\"overflow-hidden\"\n >\n <div\n role=\"status\"\n aria-label={`Replying to ${author}`}\n className=\"flex items-center gap-ds-03 border-b border-surface-border px-ds-04 py-ds-02b\"\n >\n <div className=\"flex-1 min-w-0\">\n <span className=\"text-ds-sm font-semibold text-surface-fg\">\n Replying to {author}\n </span>\n <span className=\"mx-ds-02 text-surface-fg-subtle\">&middot;</span>\n <span className=\"text-ds-sm text-surface-fg-muted truncate\">\n {preview}\n </span>\n </div>\n <button\n type=\"button\"\n onClick={onDismiss}\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control touch-target',\n 'text-surface-fg-subtle hover:text-surface-fg hover:bg-surface-raised-hover',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'active:scale-95',\n )}\n aria-label=\"Cancel reply\"\n title=\"Cancel reply\"\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n </div>\n </motion.div>\n )\n}\n","'use client'\n\nimport { IconCalendarEvent, IconClock, IconPencil,IconX } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../../ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '../../ui/dialog'\nimport { Icon } from '../../ui/icon'\nimport { durations } from '../../ui/lib/motion'\nimport { ToggleGroup, ToggleGroupItem } from '../../ui/toggle-group'\nimport { CalendarGrid } from '../date-picker/calendar-grid'\nimport { useCalendar } from '../date-picker/use-calendar'\n\n// ── Smart Presets ──────────────────────────────────────────────\n\ninterface PresetOption {\n label: string\n date: Date\n}\n\nfunction getSmartPresets(): PresetOption[] {\n const now = new Date()\n const hour = now.getHours()\n const presets: PresetOption[] = []\n\n const nextTime = (targetHour: number, daysAhead = 0) => {\n const d = new Date(now)\n d.setDate(d.getDate() + daysAhead)\n d.setHours(targetHour, 0, 0, 0)\n return d\n }\n\n const nextMonday = (targetHour: number) => {\n const d = new Date(now)\n const dayOfWeek = d.getDay()\n const daysUntilMonday = dayOfWeek === 0 ? 1 : dayOfWeek === 1 ? 7 : 8 - dayOfWeek\n d.setDate(d.getDate() + daysUntilMonday)\n d.setHours(targetHour, 0, 0, 0)\n return d\n }\n\n if (hour < 9) {\n presets.push({ label: 'Later this morning · 9:00 AM', date: nextTime(9) })\n presets.push({ label: 'This afternoon · 1:00 PM', date: nextTime(13) })\n presets.push({ label: 'This evening · 6:00 PM', date: nextTime(18) })\n } else if (hour < 13) {\n presets.push({ label: 'This afternoon · 1:00 PM', date: nextTime(13) })\n presets.push({ label: 'This evening · 6:00 PM', date: nextTime(18) })\n presets.push({ label: 'Tomorrow morning · 9:00 AM', date: nextTime(9, 1) })\n } else if (hour < 18) {\n presets.push({ label: 'This evening · 6:00 PM', date: nextTime(18) })\n presets.push({ label: 'Tomorrow morning · 9:00 AM', date: nextTime(9, 1) })\n presets.push({ label: 'Tomorrow afternoon · 1:00 PM', date: nextTime(13, 1) })\n } else {\n presets.push({ label: 'Tomorrow morning · 9:00 AM', date: nextTime(9, 1) })\n presets.push({ label: 'Tomorrow afternoon · 1:00 PM', date: nextTime(13, 1) })\n }\n\n const monday = nextMonday(9)\n if (monday.getTime() - now.getTime() > 2 * 24 * 60 * 60 * 1000) {\n presets.push({ label: 'Next Monday · 9:00 AM', date: monday })\n }\n\n return presets\n}\n\n// ── Inline Time Selector (hour, minute, AM/PM) ────────────────\n\nfunction InlineTimePicker({ value, onChange }: { value: Date; onChange: (d: Date) => void }) {\n const hours12 = value.getHours() % 12 || 12\n const minutes = value.getMinutes()\n const isPM = value.getHours() >= 12\n\n const setHour = (h: number) => {\n const d = new Date(value)\n d.setHours(isPM ? (h % 12) + 12 : h % 12)\n onChange(d)\n }\n\n const setMinute = (m: number) => {\n const d = new Date(value)\n d.setMinutes(m)\n onChange(d)\n }\n\n const togglePeriod = (pm: boolean) => {\n const d = new Date(value)\n const h = d.getHours()\n if (pm && h < 12) d.setHours(h + 12)\n else if (!pm && h >= 12) d.setHours(h - 12)\n onChange(d)\n }\n\n return (\n <div className=\"flex items-center gap-ds-02\">\n {/* Hour */}\n <select\n value={hours12}\n onChange={(e) => setHour(Number(e.target.value))}\n className=\"h-ds-sm rounded-control border border-surface-border-strong bg-surface-raised px-ds-02 text-ds-sm text-surface-fg focus:outline-hidden focus:ring-2 focus:ring-accent-9\"\n aria-label=\"Hour\"\n >\n {Array.from({ length: 12 }, (_, i) => i + 1).map((h) => (\n <option key={h} value={h}>{h}</option>\n ))}\n </select>\n\n <span className=\"text-ds-sm text-surface-fg-subtle font-medium\">:</span>\n\n {/* Minute — 5-min steps */}\n <select\n value={minutes - (minutes % 5)}\n onChange={(e) => setMinute(Number(e.target.value))}\n className=\"h-ds-sm rounded-control border border-surface-border-strong bg-surface-raised px-ds-02 text-ds-sm text-surface-fg focus:outline-hidden focus:ring-2 focus:ring-accent-9\"\n aria-label=\"Minute\"\n >\n {Array.from({ length: 12 }, (_, i) => i * 5).map((m) => (\n <option key={m} value={m}>{String(m).padStart(2, '0')}</option>\n ))}\n </select>\n\n {/* AM/PM toggle */}\n <ToggleGroup\n type=\"single\"\n value={isPM ? 'PM' : 'AM'}\n onValueChange={(v) => {\n if (v === 'AM') togglePeriod(false)\n else if (v === 'PM') togglePeriod(true)\n }}\n size=\"sm\"\n >\n <ToggleGroupItem value=\"AM\">AM</ToggleGroupItem>\n <ToggleGroupItem value=\"PM\">PM</ToggleGroupItem>\n </ToggleGroup>\n </div>\n )\n}\n\n// ── Compact Date + Time Entry (for dropdown) ──────────────────\n\nfunction CompactDateTimeEntry({\n value,\n onChange,\n minDate,\n}: {\n value: Date | null\n onChange: (d: Date) => void\n minDate?: Date\n}) {\n const now = new Date()\n const selected = value ?? (() => { const d = new Date(now); d.setHours(d.getHours() + 1, 0, 0, 0); return d })()\n\n // Format date as YYYY-MM-DD for the native input\n const dateStr = `${selected.getFullYear()}-${String(selected.getMonth() + 1).padStart(2, '0')}-${String(selected.getDate()).padStart(2, '0')}`\n\n const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const parts = e.target.value.split('-')\n if (parts.length !== 3) return\n const d = new Date(selected)\n d.setFullYear(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]))\n onChange(d)\n }\n\n const minDateStr = minDate\n ? `${minDate.getFullYear()}-${String(minDate.getMonth() + 1).padStart(2, '0')}-${String(minDate.getDate()).padStart(2, '0')}`\n : undefined\n\n return (\n <div className=\"space-y-ds-03\">\n {/* Date input */}\n <div className=\"flex items-center justify-between\">\n <span className=\"text-ds-xs font-medium text-surface-fg-subtle\">Date</span>\n <input\n type=\"date\"\n value={dateStr}\n min={minDateStr}\n onChange={handleDateChange}\n className=\"h-ds-sm rounded-control border border-surface-border-strong bg-surface-raised px-ds-03 text-ds-sm text-surface-fg focus:outline-hidden focus:ring-2 focus:ring-accent-9\"\n />\n </div>\n\n {/* Time row */}\n <div className=\"flex items-center justify-between\">\n <span className=\"text-ds-xs font-medium text-surface-fg-subtle\">Time</span>\n <InlineTimePicker value={selected} onChange={onChange} />\n </div>\n </div>\n )\n}\n\n// ── Full Calendar + Time Picker (for dialog) ──────────────────\n\nfunction FullDateTimePicker({\n value,\n onChange,\n minDate,\n}: {\n value: Date | null\n onChange: (d: Date) => void\n minDate?: Date\n}) {\n const now = new Date()\n const selected = value ?? (() => { const d = new Date(now); d.setHours(d.getHours() + 1, 0, 0, 0); return d })()\n\n const { currentMonth, goToPreviousMonth, goToNextMonth } = useCalendar(selected)\n\n const handleDateSelect = (date: Date) => {\n const d = new Date(date)\n d.setHours(selected.getHours(), selected.getMinutes(), 0, 0)\n onChange(d)\n }\n\n return (\n <div className=\"space-y-ds-03\">\n <CalendarGrid\n currentMonth={currentMonth}\n selected={selected}\n onSelect={handleDateSelect}\n onMonthChange={(d) => {\n if (d < currentMonth) goToPreviousMonth()\n else goToNextMonth()\n }}\n minDate={minDate}\n className=\"w-full\"\n />\n <div className=\"flex items-center justify-between border-t border-surface-border pt-ds-03\">\n <span className=\"text-ds-xs font-medium text-surface-fg-subtle\">Time</span>\n <InlineTimePicker value={selected} onChange={onChange} />\n </div>\n </div>\n )\n}\n\n// ── Schedule Dropdown Content (presets + inline picker) ─────────\n\nexport interface ScheduleDropdownContentProps {\n onSchedule: (date: Date) => void\n onClose: () => void\n /** Open a full dialog instead of inline picker. Consumer provides the dialog. */\n onOpenDialog?: () => void\n}\n\nexport function ScheduleDropdownContent({ onSchedule, onClose, onOpenDialog }: ScheduleDropdownContentProps) {\n const [showPicker, setShowPicker] = React.useState(false)\n const [customDate, setCustomDate] = React.useState<Date | null>(null)\n\n const presets = React.useMemo(() => getSmartPresets(), [])\n\n const handlePreset = (date: Date) => {\n onSchedule(date)\n onClose()\n }\n\n const handleCustomConfirm = () => {\n if (customDate && customDate > new Date()) {\n onSchedule(customDate)\n onClose()\n setCustomDate(null)\n setShowPicker(false)\n }\n }\n\n if (showPicker) {\n return (\n <div className=\"p-ds-04\" style={{ minWidth: 270 }}>\n <div className=\"mb-ds-03 flex items-center justify-between\">\n <p className=\"text-ds-sm font-medium text-surface-fg\">Pick date & time</p>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n onClick={() => setShowPicker(false)}\n aria-label=\"Back to presets\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </Button>\n </div>\n\n <CompactDateTimeEntry\n value={customDate}\n onChange={setCustomDate}\n minDate={new Date()}\n />\n\n <div className=\"mt-ds-03 flex justify-end\">\n <Button\n variant=\"solid\"\n size=\"sm\"\n onClick={handleCustomConfirm}\n disabled={!customDate || customDate <= new Date()}\n >\n Confirm\n </Button>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"p-ds-02\" style={{ minWidth: 260 }}>\n <p className=\"px-ds-03 py-ds-01 text-ds-xs font-medium text-surface-fg-subtle\">\n Schedule send\n </p>\n {presets.map((preset, i) => (\n <Button\n key={i}\n variant=\"ghost\"\n fullWidth\n onClick={() => handlePreset(preset.date)}\n >\n <Icon icon={IconClock} size=\"sm\" className=\"shrink-0 text-surface-fg-muted\" />\n {preset.label}\n </Button>\n ))}\n <div className=\"mx-ds-02 my-ds-02 h-px bg-surface-border\" />\n <Button\n variant=\"ghost\"\n fullWidth\n onClick={() => setShowPicker(true)}\n >\n <Icon icon={IconCalendarEvent} size=\"sm\" className=\"shrink-0 text-accent-11\" />\n Pick date & time...\n </Button>\n {onOpenDialog && (\n <Button\n variant=\"ghost\"\n fullWidth\n onClick={() => { onOpenDialog(); onClose() }}\n >\n <Icon icon={IconCalendarEvent} size=\"sm\" className=\"shrink-0 text-surface-fg-muted\" />\n Open full picker...\n </Button>\n )}\n </div>\n )\n}\n\n// ── Schedule Dialog (full-screen on mobile) ────────────────────\n\nexport interface ScheduleDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onSchedule: (date: Date) => void\n /** Pre-fill with existing scheduled date (edit mode). */\n initialDate?: Date | null\n}\n\nexport function ScheduleDialog({ open, onOpenChange, onSchedule, initialDate }: ScheduleDialogProps) {\n const [date, setDate] = React.useState<Date | null>(initialDate ?? null)\n\n // Reset when opened with new initialDate\n React.useEffect(() => {\n if (open) setDate(initialDate ?? null)\n }, [open, initialDate])\n\n const handleConfirm = () => {\n if (date && date > new Date()) {\n onSchedule(date)\n onOpenChange(false)\n }\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"sm:max-w-[380px]\">\n <DialogHeader>\n <DialogTitle>{initialDate ? 'Reschedule message' : 'Schedule send'}</DialogTitle>\n </DialogHeader>\n\n <FullDateTimePicker\n value={date}\n onChange={setDate}\n minDate={new Date()}\n />\n\n <DialogFooter className=\"gap-ds-02\">\n <Button variant=\"soft\" onClick={() => onOpenChange(false)}>Cancel</Button>\n <Button\n variant=\"solid\"\n onClick={handleConfirm}\n disabled={!date || date <= new Date()}\n >\n {initialDate ? 'Reschedule' : 'Schedule'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n\n// ── Schedule Banner ────────────────────────────────────────────\n\nfunction formatScheduleTime(date: Date): string {\n const now = new Date()\n const tomorrow = new Date(now)\n tomorrow.setDate(tomorrow.getDate() + 1)\n\n const isToday = date.toDateString() === now.toDateString()\n const isTomorrow = date.toDateString() === tomorrow.toDateString()\n\n const time = date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' })\n\n if (isToday) return `Today at ${time}`\n if (isTomorrow) return `Tomorrow at ${time}`\n return `${date.toLocaleDateString(undefined, { weekday: 'short', month: 'short', day: 'numeric' })} at ${time}`\n}\n\nexport function ScheduleBanner({ date, onClear, onEdit }: { date: Date; onClear: () => void; onEdit?: () => void }) {\n return (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n className=\"overflow-hidden\"\n >\n <div className=\"flex items-center gap-ds-03 px-ds-04 py-ds-02b text-ds-xs text-accent-11 bg-accent-2 border-b border-accent-4\">\n <Icon icon={IconClock} size=\"xs\" className=\"shrink-0\" />\n <span className=\"min-w-0 flex-1 truncate\">\n Scheduled for {formatScheduleTime(date)}\n </span>\n {onEdit && (\n <Button\n variant=\"soft\"\n size=\"icon-xs\"\n className=\"shrink-0\"\n onClick={onEdit}\n aria-label=\"Edit schedule\"\n >\n <Icon icon={IconPencil} size=\"xs\" />\n </Button>\n )}\n <Button\n variant=\"soft\"\n size=\"icon-xs\"\n className=\"shrink-0\"\n onClick={onClear}\n aria-label=\"Cancel schedule\"\n >\n <Icon icon={IconX} size=\"xs\" />\n </Button>\n </div>\n </motion.div>\n )\n}\n","'use client'\n\nimport { useCallback, useEffect,useRef, useState } from 'react'\n\nexport interface UseVoiceRecorderOptions {\n maxDuration?: number\n onComplete: (blob: Blob, duration: number, waveformData: number[]) => void\n}\n\nexport interface UseVoiceRecorderReturn {\n state: 'idle' | 'recording' | 'paused'\n duration: number\n analyserNode: AnalyserNode | null\n waveformData: number[]\n start: () => Promise<void>\n stop: () => void\n cancel: () => void\n pause: () => void\n resume: () => void\n}\n\nfunction getSupportedMimeType(): string {\n if (\n typeof MediaRecorder !== 'undefined' &&\n MediaRecorder.isTypeSupported('audio/webm;codecs=opus')\n ) {\n return 'audio/webm;codecs=opus'\n }\n if (\n typeof MediaRecorder !== 'undefined' &&\n MediaRecorder.isTypeSupported('audio/mp4')\n ) {\n return 'audio/mp4'\n }\n return ''\n}\n\nexport function useVoiceRecorder(\n options: UseVoiceRecorderOptions\n): UseVoiceRecorderReturn {\n const { maxDuration, onComplete } = options\n\n const [state, setState] = useState<'idle' | 'recording' | 'paused'>('idle')\n const [duration, setDuration] = useState(0)\n const [analyserNode, setAnalyserNode] = useState<AnalyserNode | null>(null)\n const [waveformData, setWaveformData] = useState<number[]>([])\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null)\n const audioContextRef = useRef<AudioContext | null>(null)\n const streamRef = useRef<MediaStream | null>(null)\n const chunksRef = useRef<Blob[]>([])\n const durationTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const waveformTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const maxDurationTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const analyserRef = useRef<AnalyserNode | null>(null)\n const durationRef = useRef(0)\n const waveformRef = useRef<number[]>([])\n const cancelledRef = useRef(false)\n const onCompleteRef = useRef(onComplete)\n\n // Keep onComplete ref fresh without causing re-renders of callbacks\n onCompleteRef.current = onComplete\n\n const cleanup = useCallback(() => {\n if (durationTimerRef.current !== null) {\n clearInterval(durationTimerRef.current)\n durationTimerRef.current = null\n }\n if (waveformTimerRef.current !== null) {\n clearInterval(waveformTimerRef.current)\n waveformTimerRef.current = null\n }\n if (maxDurationTimerRef.current !== null) {\n clearTimeout(maxDurationTimerRef.current)\n maxDurationTimerRef.current = null\n }\n if (streamRef.current) {\n streamRef.current.getTracks().forEach((track) => track.stop())\n streamRef.current = null\n }\n if (audioContextRef.current) {\n audioContextRef.current.close().catch(() => {})\n audioContextRef.current = null\n }\n analyserRef.current = null\n setAnalyserNode(null)\n mediaRecorderRef.current = null\n chunksRef.current = []\n }, [])\n\n const start = useCallback(async () => {\n if (typeof MediaRecorder === 'undefined') {\n throw new Error(\n 'MediaRecorder is not supported in this browser. Voice recording requires a modern browser with MediaRecorder support.'\n )\n }\n\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true })\n streamRef.current = stream\n\n const mimeType = getSupportedMimeType()\n const recorder = mimeType\n ? new MediaRecorder(stream, { mimeType })\n : new MediaRecorder(stream)\n mediaRecorderRef.current = recorder\n chunksRef.current = []\n cancelledRef.current = false\n\n // Set up Web Audio API for analyser\n const audioContext = new AudioContext()\n audioContextRef.current = audioContext\n const source = audioContext.createMediaStreamSource(stream)\n const analyser = audioContext.createAnalyser()\n analyser.fftSize = 256\n analyser.smoothingTimeConstant = 0.7\n source.connect(analyser)\n analyserRef.current = analyser\n setAnalyserNode(analyser)\n\n // Collect chunks\n recorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n chunksRef.current.push(event.data)\n }\n }\n\n // Handle stop\n recorder.onstop = () => {\n if (!cancelledRef.current) {\n const blob = new Blob(chunksRef.current, {\n type: recorder.mimeType || 'audio/webm',\n })\n // Capture current values before cleanup resets them\n const finalDuration = durationRef.current\n const finalWaveform = waveformRef.current\n cleanup()\n setState('idle')\n setDuration(0)\n setWaveformData([])\n onCompleteRef.current(blob, finalDuration, finalWaveform)\n } else {\n cleanup()\n setState('idle')\n setDuration(0)\n setWaveformData([])\n }\n }\n\n // Start recording\n recorder.start()\n\n // Duration timer\n setDuration(0)\n durationRef.current = 0\n durationTimerRef.current = setInterval(() => {\n durationRef.current += 1\n setDuration((prev) => prev + 1)\n }, 1000)\n\n // Waveform capture\n const frequencyData = new Uint8Array(analyser.frequencyBinCount)\n setWaveformData([])\n waveformRef.current = []\n waveformTimerRef.current = setInterval(() => {\n if (analyserRef.current) {\n analyserRef.current.getByteFrequencyData(frequencyData)\n let sum = 0\n for (let i = 0; i < frequencyData.length; i++) {\n sum += frequencyData[i]\n }\n const average = sum / frequencyData.length / 255\n waveformRef.current = [...waveformRef.current, average]\n setWaveformData((prev) => [...prev, average])\n }\n }, 100)\n\n // Max duration auto-stop\n if (maxDuration !== undefined && maxDuration > 0) {\n maxDurationTimerRef.current = setTimeout(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state !== 'inactive'\n ) {\n mediaRecorderRef.current.stop()\n }\n }, maxDuration * 1000)\n }\n\n setState('recording')\n }, [maxDuration, cleanup])\n\n const stop = useCallback(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state !== 'inactive'\n ) {\n cancelledRef.current = false\n mediaRecorderRef.current.stop()\n }\n }, [])\n\n const cancel = useCallback(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state !== 'inactive'\n ) {\n cancelledRef.current = true\n mediaRecorderRef.current.stop()\n } else {\n // Already inactive, just reset\n cleanup()\n setState('idle')\n setDuration(0)\n setWaveformData([])\n }\n }, [cleanup])\n\n const pause = useCallback(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state === 'recording'\n ) {\n mediaRecorderRef.current.pause()\n if (durationTimerRef.current !== null) {\n clearInterval(durationTimerRef.current)\n durationTimerRef.current = null\n }\n if (waveformTimerRef.current !== null) {\n clearInterval(waveformTimerRef.current)\n waveformTimerRef.current = null\n }\n setState('paused')\n }\n }, [])\n\n const resume = useCallback(() => {\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state === 'paused'\n ) {\n mediaRecorderRef.current.resume()\n\n // Resume duration timer\n durationTimerRef.current = setInterval(() => {\n durationRef.current += 1\n setDuration((prev) => prev + 1)\n }, 1000)\n\n // Resume waveform capture\n const frequencyData = new Uint8Array(\n analyserRef.current?.frequencyBinCount ?? 128\n )\n waveformTimerRef.current = setInterval(() => {\n if (analyserRef.current) {\n analyserRef.current.getByteFrequencyData(frequencyData)\n let sum = 0\n for (let i = 0; i < frequencyData.length; i++) {\n sum += frequencyData[i]\n }\n const average = sum / frequencyData.length / 255\n waveformRef.current = [...waveformRef.current, average]\n setWaveformData((prev) => [...prev, average])\n }\n }, 100)\n\n setState('recording')\n }\n }, [])\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (durationTimerRef.current !== null) {\n clearInterval(durationTimerRef.current)\n }\n if (waveformTimerRef.current !== null) {\n clearInterval(waveformTimerRef.current)\n }\n if (maxDurationTimerRef.current !== null) {\n clearTimeout(maxDurationTimerRef.current)\n }\n if (\n mediaRecorderRef.current &&\n mediaRecorderRef.current.state !== 'inactive'\n ) {\n mediaRecorderRef.current.stop()\n }\n if (streamRef.current) {\n streamRef.current.getTracks().forEach((track) => track.stop())\n }\n if (audioContextRef.current) {\n audioContextRef.current.close().catch(() => {})\n }\n }\n }, [])\n\n return {\n state,\n duration,\n analyserNode,\n waveformData,\n start,\n stop,\n cancel,\n pause,\n resume,\n }\n}\n","'use client'\n\nimport { computePosition, flip, offset, shift } from '@floating-ui/dom'\nimport {\n IconBold,\n IconChevronDown,\n IconClock,\n IconCode,\n IconHighlight,\n IconItalic,\n IconMicrophone,\n IconMoodSmile,\n IconPlus,\n IconSend,\n IconSquare,\n IconStrikethrough,\n IconTextSize,\n IconTrash,\n IconUnderline,\n} from '@tabler/icons-react'\nimport Highlight from '@tiptap/extension-highlight'\nimport Image from '@tiptap/extension-image'\nimport Mention from '@tiptap/extension-mention'\nimport { CharacterCount,Placeholder } from '@tiptap/extensions'\nimport { type Editor,EditorContent, Extension, useEditor, useEditorState } from '@tiptap/react'\nimport { BubbleMenu } from '@tiptap/react/menus'\nimport StarterKit from '@tiptap/starter-kit'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { MENTION_TOKEN_CLASS } from '../ui/lib/mention'\nimport { durations } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport { SplitButton } from '../ui/split-button'\nimport type { EmojiData, EmojiSet } from './emoji-picker'\nimport { EmojiNode } from './extensions/emoji-node'\nimport { createEmojiSuggestion } from './extensions/emoji-suggestion'\nimport { FileAttachment } from './extensions/file-attachment'\nimport { createSuggestionRenderer } from './extensions/mention-suggestion'\nimport type { SlashCommandGroup } from './extensions/slash-command'\nimport { createSlashCommandExtension } from './extensions/slash-command'\nimport type { Attachment } from './rich-chat-input/attachment-strip'\nimport { AttachmentStrip } from './rich-chat-input/attachment-strip'\nimport type { AudioPlayerProps } from './rich-chat-input/audio-player'\nimport { AudioPlayer } from './rich-chat-input/audio-player'\nimport type { AudioWaveformProps } from './rich-chat-input/audio-waveform'\nimport { AudioWaveform } from './rich-chat-input/audio-waveform'\nimport type { ChatToolbarItem } from './rich-chat-input/chat-toolbar'\nimport { ChatToolbar } from './rich-chat-input/chat-toolbar'\nimport { RecordingOverlay } from './rich-chat-input/recording-overlay'\nimport { ReplyBanner } from './rich-chat-input/reply-banner'\nimport { ScheduleBanner, ScheduleDialog,ScheduleDropdownContent } from './rich-chat-input/schedule-send'\nimport type { UseVoiceRecorderOptions, UseVoiceRecorderReturn } from './rich-chat-input/use-voice-recorder'\nimport { useVoiceRecorder } from './rich-chat-input/use-voice-recorder'\nimport type { MentionItem } from './rich-text-editor'\n\n// ── Re-exports ──────────────────────────────────────────────────\n\nexport type { MentionItem }\nexport type { SlashCommand, SlashCommandGroup } from './extensions/slash-command'\n\nexport { AudioWaveform }\nexport type { AudioWaveformProps }\nexport { AudioPlayer }\nexport type { AudioPlayerProps }\nexport { useVoiceRecorder }\nexport type { UseVoiceRecorderOptions, UseVoiceRecorderReturn }\n\n// ── Types ───────────────────────────────────────────────────────\n\n// Only track states that are USER-TRIGGERED (not editor-triggered).\n// idle/focused/composing are derived from editor.isEmpty at render time.\ntype InputState = 'idle' | 'recording' | 'review'\n\nexport interface RichChatInputMessage {\n html: string\n plainText: string\n attachments?: Array<{ url: string; name: string; size: number; type: string }>\n voiceNote?: { blob: Blob; duration: number }\n}\n\nexport interface RichChatInputProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSubmit' | 'content'> {\n onSubmit: (message: RichChatInputMessage) => void\n placeholder?: string\n disabled?: boolean\n /** Initial HTML content (not reactive — use for message editing). */\n content?: string\n variant?: 'compact' | 'expanded' | 'minimal' | 'inline'\n enterBehavior?: 'send' | 'newline'\n maxLength?: number\n /** When to show the character counter. @default 'near-limit' */\n charCountDisplay?: 'always' | 'focus' | 'near-limit' | 'hidden'\n mentions?: MentionItem[]\n onMentionSearch?: (query: string) => Promise<MentionItem[]>\n onMentionSelect?: (item: MentionItem) => void\n onFileUpload?: (file: File) => Promise<{ url: string; name: string; size: number }>\n onImageUpload?: (file: File) => Promise<string>\n slashCommands?: SlashCommandGroup[]\n onVoiceRecord?: (audio: Blob, duration: number) => void\n /** Called after recording stops. Consumer can transcribe and return text to insert into the editor. If null is returned, the audio is attached as a voice note. */\n onTranscribe?: (blob: Blob, duration: number) => Promise<string | null>\n maxDuration?: number\n replyTo?: { id: string; author: string; preview: string; onDismiss: () => void }\n onTyping?: (isTyping: boolean) => void\n onEmpty?: (isEmpty: boolean) => void\n isStreaming?: boolean\n onCancel?: () => void\n leadingSlot?: React.ReactNode\n trailingSlot?: React.ReactNode\n disclaimer?: string\n /** true = default toolbar, ChatToolbarItem[] = whitelist, ReactNode = custom toolbar, false = hidden */\n toolbar?: boolean | ChatToolbarItem[] | React.ReactNode\n /** Custom action button rendered to the left of the input (replaces the default attach button). Pass `false` to hide. */\n actionButton?: React.ReactNode | false\n /** Emoji art style in the picker. @default 'native' (system emoji) */\n emojiSet?: EmojiSet\n /** Called when user schedules a message. If provided, a schedule button appears next to send. */\n onSchedule?: (message: RichChatInputMessage, scheduledAt: Date) => void\n /** Split send button — dropdown options next to send (e.g. custom actions). */\n sendOptions?: Array<{\n label: string\n icon?: React.ComponentType<{ className?: string }>\n onSelect: () => void\n }>\n}\n\n// ── Variant config ──────────────────────────────────────────────\n\nconst variantConfig = {\n compact: { minHeight: 44, maxHeight: 256, showToolbar: true, toolbarPosition: 'bottom' as const },\n expanded: { minHeight: 96, maxHeight: 384, showToolbar: true, toolbarPosition: 'bottom' as const },\n minimal: { minHeight: 44, maxHeight: 128, showToolbar: false, toolbarPosition: 'bottom' as const },\n inline: { minHeight: 40, maxHeight: 160, showToolbar: false, toolbarPosition: 'top' as const },\n}\n\n// ── Chat prose (tighter than RTE, text-ds-md to match Input) ────\n\nconst CHAT_PROSE = [\n 'prose prose-sm max-w-none focus:outline-hidden',\n 'font-body text-ds-md leading-relaxed text-surface-fg',\n '[&_p.is-editor-empty:first-child]:relative',\n '[&_p.is-editor-empty:first-child::before]:text-surface-fg-subtle [&_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)] [&_p.is-editor-empty:first-child::before]:pointer-events-none [&_p.is-editor-empty:first-child::before]:absolute [&_p.is-editor-empty:first-child::before]:left-0 [&_p.is-editor-empty:first-child::before]:top-0 [&_p.is-editor-empty:first-child::before]:w-full [&_p.is-editor-empty:first-child::before]:truncate',\n '[&_p]:mb-ds-01 [&_p]:text-surface-fg',\n '[&_p:last-child]:mb-0',\n '[&_ul]:ml-ds-04 [&_ul]:list-disc [&_ol]:ml-ds-04 [&_ol]:list-decimal',\n '[&_li]:text-surface-fg',\n '[&_code]:rounded [&_code]:bg-surface-raised [&_code]:px-ds-02 [&_code]:py-[1px] [&_code]:text-ds-md [&_code]:text-accent-11',\n '[&_strong]:font-semibold [&_strong]:text-surface-fg',\n '[&_mark]:rounded-xs [&_mark]:bg-warning-3 [&_mark]:px-[2px]',\n '[&_a]:text-accent-11 [&_a]:underline',\n MENTION_TOKEN_CLASS,\n].join(' ')\n\n// ── Split Send Dropdown (chevron next to send — schedule send, etc.) ──\n\nfunction SplitSendDropdown({ options }: { options: Array<{ label: string; icon?: React.ComponentType<{ className?: string }>; onSelect: () => void }> }) {\n const [open, setOpen] = React.useState(false)\n const dropdownRef = React.useRef<HTMLDivElement>(null)\n\n // Close on outside click\n React.useEffect(() => {\n if (!open) return\n const handleClick = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) setOpen(false)\n }\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [open])\n\n return (\n <div ref={dropdownRef} className=\"relative\">\n <button\n type=\"button\"\n onClick={() => setOpen(prev => !prev)}\n title=\"More send options\"\n aria-label=\"More send options\"\n aria-expanded={open}\n className={cn(\n 'inline-flex h-ds-xs-plus w-5 items-center justify-center rounded-control touch-target',\n 'text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg',\n 'transition-colors duration-fast-01 ease-productive-standard',\n open && 'bg-surface-raised-hover text-surface-fg',\n )}\n >\n <Icon icon={IconChevronDown} size=\"xs\" />\n </button>\n {/* min-w-[200px]: component-specific dropdown width — no design token equivalent */}\n {open && (\n <div className=\"absolute bottom-full right-0 mb-ds-02 min-w-[200px] rounded-surface bg-surface-overlay p-ds-02 shadow-floating z-popover\">\n <p className=\"px-ds-03 py-ds-01 text-ds-xs font-medium text-surface-fg-subtle\">Send options</p>\n {options.map((opt, i) => (\n <button\n key={i}\n type=\"button\"\n onClick={() => { opt.onSelect(); setOpen(false) }}\n className=\"flex w-full items-center gap-ds-03 rounded-control px-ds-03 py-ds-02 text-ds-sm text-surface-fg hover:bg-surface-raised-hover transition-colors duration-fast-01\"\n >\n {opt.icon && <opt.icon className=\"h-ico-sm w-ico-sm text-surface-fg-muted\" />}\n {opt.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ── Emoji Picker Popover (lazy-loaded) ──────────────────────────\n\nconst LazyEmojiPicker = React.lazy(() =>\n import('./emoji-picker').then((m) => ({ default: m.EmojiPicker })),\n)\n\nfunction EmojiPickerPopover({ onSelect, onClose }: { onSelect: (emoji: EmojiData) => void; onClose: () => void }) {\n const ref = React.useRef<HTMLDivElement>(null)\n\n // Close on click outside\n React.useEffect(() => {\n const handleClick = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) onClose()\n }\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [onClose])\n\n // Close on Escape\n React.useEffect(() => {\n const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }\n document.addEventListener('keydown', handleKey)\n return () => document.removeEventListener('keydown', handleKey)\n }, [onClose])\n\n const fallback = (\n <div className=\"flex h-[435px] w-[352px] items-center justify-center rounded-surface bg-surface-overlay shadow-floating\">\n <span className=\"text-ds-sm text-surface-fg-subtle\">Loading…</span>\n </div>\n )\n\n return (\n <div ref={ref}>\n <React.Suspense fallback={fallback}>\n <LazyEmojiPicker onSelect={onSelect} />\n </React.Suspense>\n </div>\n )\n}\n\n// ── Toolbar Button (for BubbleMenu only — ChatToolbar has its own) ──\n\nfunction BubbleBtn({\n onClick,\n isActive = false,\n title,\n children,\n}: {\n onClick: () => void\n isActive?: boolean\n title: string\n children: React.ReactNode\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control touch-target',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n isActive ? 'bg-surface-raised-hover text-accent-11' : 'text-surface-fg-subtle',\n )}\n >\n {children}\n </button>\n )\n}\n\n// ── BubbleMenu with useEditorState (v3) ────────────────────────\n\nfunction ChatBubbleMenu({ editor }: { editor: Editor }) {\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n isBold: e.isActive('bold'),\n isItalic: e.isActive('italic'),\n isUnderline: e.isActive('underline'),\n isStrike: e.isActive('strike'),\n isHighlight: e.isActive('highlight'),\n isCode: e.isActive('code'),\n }),\n })\n\n return (\n <BubbleMenu\n editor={editor}\n className=\"flex gap-ds-01 rounded-surface bg-surface-overlay p-ds-02 shadow-floating\"\n >\n <BubbleBtn onClick={() => editor.chain().focus().toggleBold().run()} isActive={state.isBold} title=\"Bold\">\n <Icon icon={IconBold} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleItalic().run()} isActive={state.isItalic} title=\"Italic\">\n <Icon icon={IconItalic} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleUnderline().run()} isActive={state.isUnderline} title=\"Underline\">\n <Icon icon={IconUnderline} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleStrike().run()} isActive={state.isStrike} title=\"Strikethrough\">\n <Icon icon={IconStrikethrough} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleHighlight().run()} isActive={state.isHighlight} title=\"Highlight\">\n <Icon icon={IconHighlight} size=\"xs\" />\n </BubbleBtn>\n <BubbleBtn onClick={() => editor.chain().focus().toggleCode().run()} isActive={state.isCode} title=\"Code\">\n <Icon icon={IconCode} size=\"xs\" />\n </BubbleBtn>\n </BubbleMenu>\n )\n}\n\n// ── Component ───────────────────────────────────────────────────\n\nconst RichChatInput = React.forwardRef<HTMLDivElement, RichChatInputProps>(\n function RichChatInput(\n {\n onSubmit,\n placeholder = 'Type a message...',\n disabled = false,\n content = '',\n variant = 'compact',\n enterBehavior = 'send',\n maxLength,\n charCountDisplay = 'near-limit',\n mentions,\n onMentionSearch,\n onMentionSelect,\n onFileUpload,\n onImageUpload,\n slashCommands,\n onVoiceRecord,\n onTranscribe,\n maxDuration,\n replyTo,\n onTyping,\n onEmpty,\n isStreaming = false,\n onCancel,\n leadingSlot,\n trailingSlot,\n disclaimer,\n toolbar: toolbarProp = true,\n sendOptions,\n onSchedule,\n actionButton,\n emojiSet = 'native',\n className,\n ...props\n },\n ref,\n ) {\n // ── State ──────────────────────────────────────────────────\n const [state, setState] = React.useState<InputState>('idle')\n const [toolbarExpanded, setToolbarExpanded] = React.useState(false)\n const [showEmojiPicker, setShowEmojiPicker] = React.useState(false)\n const [scheduledDate, setScheduledDate] = React.useState<Date | null>(null)\n const [scheduleDialogOpen, setScheduleDialogOpen] = React.useState(false)\n const [editorFocused, setEditorFocused] = React.useState(false)\n const [charCount, setCharCount] = React.useState(0)\n const emojiAnchorRef = React.useRef<HTMLButtonElement>(null)\n const emojiFloatingRef = React.useRef<HTMLDivElement>(null)\n\n // Position emoji picker with Floating UI (auto-flips top/bottom based on space)\n React.useEffect(() => {\n if (!showEmojiPicker || !emojiAnchorRef.current || !emojiFloatingRef.current) return\n const anchor = emojiAnchorRef.current\n const floating = emojiFloatingRef.current\n\n const update = () => {\n computePosition(anchor, floating, {\n placement: 'top-end',\n middleware: [offset(8), flip(), shift({ padding: 8 })],\n }).then(({ x, y }) => {\n Object.assign(floating.style, { left: `${x}px`, top: `${y}px` })\n })\n }\n\n update()\n // Update on scroll/resize\n window.addEventListener('scroll', update, true)\n window.addEventListener('resize', update)\n return () => {\n window.removeEventListener('scroll', update, true)\n window.removeEventListener('resize', update)\n }\n }, [showEmojiPicker])\n const [attachments, setAttachments] = React.useState<Attachment[]>([])\n const [voiceNote, setVoiceNote] = React.useState<{ blob: Blob; duration: number; waveformData: number[] } | null>(null)\n const [isDragging, setIsDragging] = React.useState(false)\n // editorHeight state removed — was causing re-renders during ProseMirror DOM changes\n\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n const editorWrapperRef = React.useRef<HTMLDivElement>(null)\n const typingTimeoutRef = React.useRef<ReturnType<typeof setTimeout>>(undefined)\n const submitRef = React.useRef<(() => void) | undefined>(undefined)\n const enterBehaviorRef = React.useRef(enterBehavior)\n enterBehaviorRef.current = enterBehavior\n // Same live-ref pattern for the mention-select callback: the extensions memo\n // only rebuilds on presence changes (`!!mentions` etc.), so passing\n // onMentionSelect directly would freeze the mount-time closure. See #92.\n const onMentionSelectRef = React.useRef(onMentionSelect)\n onMentionSelectRef.current = onMentionSelect\n // Same reasoning for the mention data sources read inside the memoized\n // `items` resolver — the memo only rebuilds on presence, so a consumer\n // swapping the list or the search fn would otherwise keep the mount-time\n // value. See #92.\n const mentionsRef = React.useRef(mentions)\n mentionsRef.current = mentions\n const onMentionSearchRef = React.useRef(onMentionSearch)\n onMentionSearchRef.current = onMentionSearch\n\n const isMobile = useIsMobile()\n const config = variantConfig[variant]\n const maxHeightPx = config.maxHeight\n\n // ── Voice Recorder ────────────────────────────────────────\n const voiceRecorder = useVoiceRecorder({\n maxDuration,\n onComplete: async (blob, duration, waveformData) => {\n onVoiceRecord?.(blob, duration)\n\n // If consumer provides a transcription handler, try to transcribe\n if (onTranscribe) {\n const text = await onTranscribe(blob, duration)\n if (text != null) {\n // Insert transcribed text into the editor instead of attaching voice note\n editor?.chain().focus().insertContent(text).run()\n setState('idle') // back to idle — hasContent will be derived from editor\n return\n }\n }\n\n // Fall back to voice note attachment\n setVoiceNote({ blob, duration, waveformData })\n setState('review')\n },\n })\n\n const handleStartRecording = React.useCallback(() => {\n voiceRecorder.start()\n setState('recording')\n }, [voiceRecorder])\n\n const handleStopRecording = React.useCallback(() => {\n voiceRecorder.stop() // triggers onComplete → setState('review')\n }, [voiceRecorder])\n\n const handleCancelRecording = React.useCallback(() => {\n voiceRecorder.cancel()\n setState('idle')\n }, [voiceRecorder])\n\n // ── TipTap Extensions ─────────────────────────────────────\n const extensions = React.useMemo(() => {\n const exts = [\n StarterKit.configure({\n heading: false,\n horizontalRule: false,\n codeBlock: false,\n blockquote: false,\n // v3: Underline + Link included in StarterKit\n link: {\n openOnClick: false,\n HTMLAttributes: { class: 'text-accent-11 underline' },\n },\n }),\n Placeholder.configure({ placeholder }),\n Highlight.configure({ multicolor: false }),\n Image,\n CharacterCount.configure({ limit: maxLength || undefined }),\n FileAttachment,\n EmojiNode,\n createEmojiSuggestion(),\n // Enter-to-send\n Extension.create({\n name: 'enterToSend',\n addKeyboardShortcuts() {\n return {\n 'Enter': () => {\n if (enterBehaviorRef.current === 'send') {\n submitRef.current?.()\n return true\n }\n return false\n },\n 'Shift-Enter': () => {\n if (enterBehaviorRef.current === 'send') {\n this.editor.commands.splitBlock()\n return true\n }\n return false\n },\n 'Mod-Enter': () => {\n submitRef.current?.()\n return true\n },\n }\n },\n }),\n ]\n\n // Mentions\n if (mentions || onMentionSearch) {\n exts.push(\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n suggestion: {\n items: async ({ query }: { query: string }) => {\n if (onMentionSearchRef.current) return await onMentionSearchRef.current(query)\n const list = mentionsRef.current\n if (list) return list.filter(m => m.label.toLowerCase().includes(query.toLowerCase())).slice(0, 8)\n return []\n },\n render: createSuggestionRenderer((item: MentionItem) => onMentionSelectRef.current?.(item)),\n },\n }),\n )\n }\n\n // Slash commands\n if (slashCommands) {\n exts.push(createSlashCommandExtension(slashCommands))\n }\n\n return exts\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [placeholder, maxLength, emojiSet, !!mentions, !!onMentionSearch, !!slashCommands])\n\n // ── Editor ────────────────────────────────────────────────\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions,\n content: content || undefined,\n editable: !disabled,\n editorProps: {\n attributes: {\n class: CHAT_PROSE,\n },\n handlePaste: (_view, event) => {\n const files = Array.from(event.clipboardData?.files ?? [])\n if (files.length > 0) {\n files.forEach(processFile)\n return true\n }\n return false\n },\n },\n })\n\n // ── Submit Handler (structured output) ────────────────────\n const handleSubmit = React.useCallback(() => {\n if (!editor) return\n\n const hasText = !editor.isEmpty\n const hasAttachments = attachments.length > 0\n const hasVoice = !!voiceNote\n\n if (!hasText && !hasAttachments && !hasVoice) return\n if (isStreaming) return\n\n const message: RichChatInputMessage = {\n html: hasText ? editor.getHTML() : '',\n plainText: hasText ? editor.getText() : '',\n }\n\n if (hasAttachments) {\n message.attachments = attachments\n .filter(a => !a.uploading && a.url)\n .map(a => ({ url: a.url!, name: a.name, size: a.size, type: a.type }))\n }\n\n if (hasVoice) {\n message.voiceNote = { blob: voiceNote.blob, duration: voiceNote.duration }\n }\n\n if (scheduledDate && onSchedule) {\n onSchedule(message, scheduledDate)\n } else {\n onSubmit(message)\n }\n\n // Reset everything\n editor.commands.clearContent()\n setAttachments([])\n setVoiceNote(null)\n setScheduledDate(null)\n setState('idle')\n }, [editor, attachments, voiceNote, isStreaming, onSubmit, onSchedule, scheduledDate])\n\n // Wire submit ref (for enter-to-send extension)\n submitRef.current = handleSubmit\n\n // ── NO state tracking from editor events ──────────────────\n // Previous approach tracked idle/focused/composing via setState from TipTap\n // events. This caused React re-renders during ProseMirror DOM modifications →\n // \"removeChild\" crashes. Instead, we derive hasContent/editorIsEmpty at render\n // time, and use CSS :focus-within for focus styling. Only recording/review\n // states are tracked (user-triggered, not editor-triggered).\n\n // ── Editor height: pure CSS (no ResizeObserver/setState) ───\n // ResizeObserver was calling setEditorHeight during ProseMirror DOM changes,\n // triggering React re-renders → removeChild crashes. CSS min/max-height\n // + overflow-y: auto handles this natively without any state.\n\n // ── Typing Indicator ──────────────────────────────────────\n React.useEffect(() => {\n if (!editor || !onTyping) return\n const handleUpdate = () => {\n onTyping(true)\n clearTimeout(typingTimeoutRef.current)\n typingTimeoutRef.current = setTimeout(() => onTyping(false), 2000)\n }\n editor.on('update', handleUpdate)\n return () => {\n editor.off('update', handleUpdate)\n clearTimeout(typingTimeoutRef.current)\n }\n }, [editor, onTyping])\n\n // ── Empty State Callback ──────────────────────────────────\n React.useEffect(() => {\n if (!editor || !onEmpty) return\n const handleUpdate = () => { onEmpty(editor.isEmpty) }\n editor.on('update', handleUpdate)\n handleUpdate()\n return () => { editor.off('update', handleUpdate) }\n }, [editor, onEmpty])\n\n // ── File Handling ─────────────────────────────────────────\n const processFile = React.useCallback(async (file: File) => {\n const id = Math.random().toString(36).slice(2)\n const isImage = file.type.startsWith('image/')\n\n setAttachments(prev => [...prev, {\n id,\n name: file.name,\n size: file.size,\n type: isImage ? 'image' : 'file',\n uploading: true,\n }])\n\n try {\n if (isImage && onImageUpload) {\n const url = await onImageUpload(file)\n setAttachments(prev => prev.map(a => a.id === id ? { ...a, url, uploading: false } : a))\n } else if (onFileUpload) {\n const result = await onFileUpload(file)\n setAttachments(prev => prev.map(a => a.id === id ? { ...a, url: result.url, name: result.name, size: result.size, uploading: false } : a))\n } else {\n // No handler — create local URL for images\n if (isImage) {\n const url = URL.createObjectURL(file)\n setAttachments(prev => prev.map(a => a.id === id ? { ...a, url, uploading: false } : a))\n } else {\n setAttachments(prev => prev.filter(a => a.id !== id))\n }\n }\n } catch {\n setAttachments(prev => prev.filter(a => a.id !== id))\n }\n }, [onFileUpload, onImageUpload])\n\n const removeAttachment = React.useCallback((id: string) => {\n setAttachments(prev => prev.filter(a => a.id !== id))\n }, [])\n\n const handleDrop = React.useCallback((e: React.DragEvent) => {\n e.preventDefault()\n setIsDragging(false)\n const files = Array.from(e.dataTransfer.files)\n files.forEach(processFile)\n }, [processFile])\n\n const handleFileInput = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(e.target.files || [])\n files.forEach(processFile)\n e.target.value = '' // reset so same file can be re-selected\n }, [processFile])\n\n // ── Voice Note Review Discard ─────────────────────────────\n const handleDiscardVoice = React.useCallback(() => {\n setVoiceNote(null)\n setState('idle')\n }, [])\n\n // ── Derived Values ────────────────────────────────────────\n // v3: useEditorState subscribes to editor changes so charCount/isEmpty\n // update without full parent re-renders on every transaction.\n const editorDerived = useEditorState({\n editor,\n selector: ({ editor: e }) => {\n if (!e) return null\n return { editorIsEmpty: e.isEmpty }\n },\n })\n const editorIsEmpty = editorDerived?.editorIsEmpty ?? true\n\n // Track character count via editor event (useEditorState's deep-equal comparison\n // swallows storage.characterCount changes since the function reference is stable)\n React.useEffect(() => {\n if (!editor) return\n const updateCount = () => {\n // Compute directly from document — CharacterCount storage.characters() returns 0 in TipTap v3\n const text = editor.state.doc.textBetween(0, editor.state.doc.content.size, undefined, ' ')\n setCharCount(text.length)\n }\n updateCount()\n editor.on('update', updateCount)\n return () => { editor.off('update', updateCount) }\n }, [editor])\n const hasContent = !editorIsEmpty || attachments.length > 0 || !!voiceNote\n const isInline = variant === 'inline'\n const showToolbar = toolbarExpanded || state === 'review' || variant === 'expanded'\n const btnSize = 'icon-md' as const\n const iconSize = 'md' as const\n\n return (\n <div\n ref={ref}\n className={cn(\n 'border-t border-surface-border-subtle px-ds-05 py-ds-04',\n 'flex items-center gap-ds-03',\n className,\n )}\n {...props}\n >\n {/* Action button outside the input on the left */}\n {actionButton !== false && (\n actionButton ?? (\n (onFileUpload || onImageUpload) ? (\n <Button\n variant=\"solid\"\n size=\"icon-md\"\n onClick={() => fileInputRef.current?.click()}\n title=\"Attach\"\n aria-label=\"Attach file\"\n className=\"shrink-0\"\n >\n <Icon icon={IconPlus} size=\"md\" />\n </Button>\n ) : null\n )\n )}\n\n {/* Container */}\n <div\n role=\"region\"\n aria-label=\"Message composer\"\n className={cn(\n 'flex-1 min-w-0 overflow-hidden rounded-surface border border-surface-border-strong bg-surface-raised-hover',\n 'transition-[color,background-color,border-color,box-shadow] duration-fast-02 ease-productive-standard',\n 'hover:bg-surface-raised-active',\n 'focus-within:ring-2 focus-within:ring-accent-9 focus-within:ring-offset-2 focus-within:border-accent-9',\n state === 'recording' && 'border-error-7/30',\n isDragging && 'border-dashed border-accent-7 bg-accent-2',\n disabled && 'opacity-action-disabled cursor-not-allowed',\n )}\n onFocus={() => setEditorFocused(true)}\n onBlur={(e) => { if (!e.currentTarget.contains(e.relatedTarget)) setEditorFocused(false) }}\n onDragOver={(e) => { e.preventDefault(); setIsDragging(true) }}\n onDragLeave={() => setIsDragging(false)}\n onDrop={handleDrop}\n >\n {/* Leading slot */}\n {leadingSlot}\n\n {/* Zone 1: Reply Banner */}\n <AnimatePresence>\n {replyTo && (\n <ReplyBanner\n key=\"reply\"\n author={replyTo.author}\n preview={replyTo.preview}\n onDismiss={replyTo.onDismiss}\n />\n )}\n </AnimatePresence>\n\n {/* Schedule Banner */}\n <AnimatePresence>\n {scheduledDate && (\n <ScheduleBanner\n key=\"schedule\"\n date={scheduledDate}\n onEdit={() => setScheduleDialogOpen(true)}\n onClear={() => setScheduledDate(null)}\n />\n )}\n </AnimatePresence>\n\n {/* Zone 2: Attachment Strip */}\n <AnimatePresence>\n {attachments.length > 0 && (\n <AttachmentStrip\n key=\"attachments\"\n attachments={attachments}\n onRemoveAttachment={removeAttachment}\n />\n )}\n </AnimatePresence>\n\n {/* Toolbar above input (inline variant) — CSS transition */}\n {config.toolbarPosition === 'top' && editor && (\n <div\n className={cn(\n 'grid transition-[grid-template-rows,opacity] duration-moderate-01 ease-productive-standard',\n toolbarExpanded ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0 pointer-events-none',\n )}\n >\n <div className=\"overflow-hidden\">\n <ChatToolbar\n editor={editor}\n toolbar={toolbarProp}\n isMobile={false}\n hasMentions={!!(mentions || onMentionSearch)}\n hasSlashCommands={!!slashCommands}\n disabled={disabled}\n />\n </div>\n </div>\n )}\n\n {/* Zone 3: Editor (always mounted — never unmount TipTap) */}\n <div className=\"relative\">\n {/* Recording overlay — positioned over the editor, no AnimatePresence */}\n {state === 'recording' && (\n <RecordingOverlay\n duration={voiceRecorder.duration}\n analyserNode={voiceRecorder.analyserNode}\n maxDuration={maxDuration}\n onCancel={handleCancelRecording}\n />\n )}\n\n {/* Editor + inline action icons in one flex row */}\n <div\n ref={editorWrapperRef}\n className={cn(\n 'flex items-center px-ds-04 py-ds-03 cursor-text [&_.tiptap]:w-full [&_.tiptap]:outline-hidden',\n state === 'recording' && 'invisible',\n )}\n style={{\n minHeight: config.minHeight,\n maxHeight: maxHeightPx,\n overflowY: 'auto',\n }}\n onClick={() => editor?.commands.focus()}\n >\n {/* Editor takes all available space */}\n <div className=\"flex-1 min-w-0\">\n <EditorContent editor={editor} />\n </div>\n\n {/* Action icons — right-aligned inside input */}\n {editor && state !== 'recording' && (\n <div className=\"flex items-center gap-ds-01 shrink-0 ml-ds-03\">\n {/* Formatting toggle (A button) */}\n <button\n type=\"button\"\n onClick={() => setToolbarExpanded(prev => !prev)}\n title={toolbarExpanded ? 'Hide formatting' : 'Show formatting'}\n aria-label={toolbarExpanded ? 'Hide formatting' : 'Show formatting'}\n aria-pressed={toolbarExpanded}\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control touch-target',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n toolbarExpanded ? 'bg-surface-raised-hover text-accent-11' : 'text-surface-fg-subtle',\n )}\n >\n <Icon icon={IconTextSize} size=\"xs\" />\n </button>\n\n {/* Emoji picker */}\n <div className=\"relative\">\n <button\n ref={emojiAnchorRef}\n type=\"button\"\n onClick={() => setShowEmojiPicker(prev => !prev)}\n title=\"Emoji\"\n aria-label=\"Emoji\"\n className={cn(\n 'inline-flex h-ds-xs-plus w-ds-xs-plus items-center justify-center rounded-control touch-target transition-colors duration-fast-01',\n showEmojiPicker ? 'bg-surface-raised-hover text-accent-11' : 'text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg',\n )}\n >\n <Icon icon={IconMoodSmile} size=\"xs\" />\n </button>\n {showEmojiPicker && ReactDOM.createPortal(\n <div ref={emojiFloatingRef} className=\"absolute z-popover\" style={{ top: 0, left: 0 }}>\n <EmojiPickerPopover\n onSelect={({ id, native }) => {\n editor.chain().focus().insertContent({\n type: 'emojiNode',\n attrs: { id, native },\n }).run()\n setShowEmojiPicker(false)\n }}\n onClose={() => setShowEmojiPicker(false)}\n />\n </div>,\n document.body,\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Voice Note Review — shown in 'review' state */}\n {state === 'review' && voiceNote && (\n <div className=\"flex items-center gap-ds-03 px-ds-04 py-ds-02b border-b border-surface-border\">\n <AudioPlayer\n src={voiceNote.blob}\n duration={voiceNote.duration}\n waveformData={voiceNote.waveformData}\n className=\"flex-1\"\n />\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={handleDiscardVoice}\n aria-label=\"Discard voice note\"\n title=\"Discard voice note\"\n className=\"text-surface-fg-subtle hover:text-error-11\"\n >\n <Icon icon={IconTrash} size=\"sm\" />\n </Button>\n </div>\n )}\n\n {/* Mobile BubbleMenu — shows on text selection */}\n {isMobile && editor && !editorIsEmpty && (\n <ChatBubbleMenu editor={editor} />\n )}\n\n {/* Zone 4: Toolbar below — CSS transition instead of AnimatePresence */}\n {config.toolbarPosition === 'bottom' && editor && (\n <div\n className={cn(\n 'grid transition-[grid-template-rows,opacity] duration-moderate-01 ease-productive-standard',\n showToolbar ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0 pointer-events-none',\n )}\n >\n <div className=\"overflow-hidden\">\n <ChatToolbar\n editor={editor}\n toolbar={toolbarProp}\n isMobile={isMobile}\n hasMentions={!!(mentions || onMentionSearch)}\n hasSlashCommands={!!slashCommands}\n disabled={disabled}\n />\n </div>\n </div>\n )}\n\n {/* Character counter */}\n {maxLength && charCountDisplay !== 'hidden' && (() => {\n const ratio = charCount / maxLength\n const showAlways = charCountDisplay === 'always'\n const showFocus = charCountDisplay === 'focus' && editorFocused\n const showNearLimit = (charCountDisplay === 'near-limit' || !charCountDisplay) && ratio >= 0.8\n const visible = showAlways || showFocus || showNearLimit || ratio >= 1\n\n if (!visible) return null\n\n return (\n <div className={cn(\n 'flex justify-end px-ds-04 pb-ds-02 text-ds-xs tabular-nums transition-opacity duration-fast-01',\n ratio >= 1 ? 'text-error-11 font-medium' : ratio >= 0.9 ? 'text-warning-11' : 'text-surface-fg-subtle',\n )}>\n {charCount}/{maxLength}\n </div>\n )\n })()}\n\n {/* Trailing slot */}\n {trailingSlot}\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n onChange={handleFileInput}\n />\n </div>\n\n {/* Send/mic/recording buttons — animated transitions between states */}\n <div className=\"flex items-center gap-ds-02 shrink-0\">\n {sendOptions && sendOptions.length > 0 && state !== 'recording' && (\n <SplitSendDropdown options={sendOptions} />\n )}\n <AnimatePresence mode=\"popLayout\" initial={false}>\n {state === 'recording' && (\n <motion.div\n key=\"recording\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n className=\"flex items-center gap-ds-02\"\n >\n <Button variant=\"soft\" size={btnSize} onClick={handleCancelRecording} aria-label=\"Cancel recording\" title=\"Cancel recording\" className=\"text-surface-fg-subtle hover:text-error-11\">\n <Icon icon={IconTrash} size={iconSize} />\n </Button>\n <Button variant=\"solid\" size={btnSize} color=\"error\" onClick={handleStopRecording} aria-label=\"Stop recording\" title=\"Stop recording\">\n <Icon icon={IconSquare} size={iconSize} />\n </Button>\n </motion.div>\n )}\n {isStreaming && state !== 'recording' && (\n <motion.div\n key=\"streaming\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <Button variant=\"solid\" size={btnSize} color=\"error\" onClick={onCancel} aria-label=\"Stop\" title=\"Stop\">\n <Icon icon={IconSquare} size={iconSize} />\n </Button>\n </motion.div>\n )}\n {!isStreaming && state !== 'recording' && hasContent && onSchedule && (\n <motion.div\n key=\"split-send\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <SplitButton\n onClick={handleSubmit}\n disabled={disabled}\n aria-label={scheduledDate ? 'Schedule send' : 'Send'}\n size={btnSize}\n dropdownContent={\n <ScheduleDropdownContent\n onSchedule={(date) => setScheduledDate(date)}\n onClose={() => {}}\n onOpenDialog={() => setScheduleDialogOpen(true)}\n />\n }\n >\n <Icon icon={scheduledDate ? IconClock : IconSend} size={iconSize} />\n </SplitButton>\n </motion.div>\n )}\n {!isStreaming && state !== 'recording' && hasContent && !onSchedule && (\n <motion.div\n key=\"send\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <Button variant=\"solid\" size={btnSize} onClick={handleSubmit} disabled={disabled} aria-label=\"Send\" title=\"Send\">\n <Icon icon={IconSend} size={iconSize} />\n </Button>\n </motion.div>\n )}\n {!isStreaming && state !== 'recording' && !hasContent && onVoiceRecord && (\n <motion.div\n key=\"mic\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <Button variant=\"soft\" size={btnSize} onClick={handleStartRecording} aria-label=\"Record voice message\" title=\"Record voice message\">\n <Icon icon={IconMicrophone} size={iconSize} />\n </Button>\n </motion.div>\n )}\n {!isStreaming && state !== 'recording' && !hasContent && !onVoiceRecord && (\n <motion.div\n key=\"send-disabled\"\n initial={{ scale: 0.8, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n exit={{ scale: 0.8, opacity: 0 }}\n transition={{ duration: durations.moderate01 }}\n >\n <Button variant=\"solid\" size={btnSize} disabled aria-label=\"Send\" title=\"Send\">\n <Icon icon={IconSend} size={iconSize} />\n </Button>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n\n {/* Disclaimer */}\n {disclaimer && (\n <p className=\"mt-ds-02 text-center text-ds-xs text-surface-fg-subtle/50\">\n {disclaimer}\n </p>\n )}\n\n {/* Schedule Dialog (full picker) */}\n {onSchedule && (\n <ScheduleDialog\n open={scheduleDialogOpen}\n onOpenChange={setScheduleDialogOpen}\n onSchedule={(date) => setScheduledDate(date)}\n initialDate={scheduledDate}\n />\n )}\n </div>\n )\n },\n)\nRichChatInput.displayName = 'RichChatInput'\n\nexport { RichChatInput }\nexport type { ChatToolbarItem }\n\n// Re-export toolbar primitives for custom toolbar composition\nexport {\n BlockquoteButton,\n BoldButton,\n BulletListButton,\n CodeButton,\n EmojiButton,\n HighlightButton,\n ItalicButton,\n LinkButton,\n MentionButton,\n OrderedListButton,\n SlashCommandButton,\n StrikeButton,\n ToolbarButton,\n ToolbarDivider,\n ToolbarGroup,\n UnderlineButton,\n} from './rich-chat-input/chat-toolbar'\n"],"mappings":"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"}