@devalok/shilp-sutra 0.55.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/BREAKING.json +13 -0
  2. package/MIGRATION.md +56 -0
  3. package/README.md +16 -1
  4. package/dist/_chunks/badge-group.js +45 -45
  5. package/dist/_chunks/emoji-suggestion.js +32 -30
  6. package/dist/_chunks/emoji-suggestion.js.map +1 -1
  7. package/dist/_chunks/mention-suggestion.js +35 -34
  8. package/dist/_chunks/mention-suggestion.js.map +1 -1
  9. package/dist/_chunks/primitives-internal.js +437 -537
  10. package/dist/_chunks/primitives-internal.js.map +1 -1
  11. package/dist/composed/content-card.js +18 -18
  12. package/dist/composed/extensions/emoji-node.js +8 -7
  13. package/dist/composed/extensions/emoji-node.js.map +1 -1
  14. package/dist/composed/rich-chat-input.js +535 -526
  15. package/dist/composed/rich-chat-input.js.map +1 -1
  16. package/dist/composed/rich-text-editor.js +201 -193
  17. package/dist/composed/rich-text-editor.js.map +1 -1
  18. package/dist/tokens/primitives.css +6 -1
  19. package/dist/tokens/semantic.css +1 -1
  20. package/dist/ui/alert.js +29 -29
  21. package/dist/ui/avatar.js +42 -42
  22. package/dist/ui/banner.js +25 -25
  23. package/dist/ui/button.js +31 -31
  24. package/dist/ui/button.js.map +1 -1
  25. package/dist/ui/card.js +39 -39
  26. package/dist/ui/checkbox.d.ts.map +1 -1
  27. package/dist/ui/checkbox.js +1 -0
  28. package/dist/ui/checkbox.js.map +1 -1
  29. package/dist/ui/combobox.js +135 -135
  30. package/dist/ui/combobox.js.map +1 -1
  31. package/dist/ui/dot.js +13 -13
  32. package/dist/ui/input.js +25 -25
  33. package/dist/ui/lib/utils.js +2 -1
  34. package/dist/ui/lib/utils.js.map +1 -1
  35. package/dist/ui/number-input.js +36 -36
  36. package/dist/ui/progress.js +55 -55
  37. package/dist/ui/select.js +58 -58
  38. package/dist/ui/sheet.js +46 -46
  39. package/dist/ui/sidebar.js +128 -128
  40. package/dist/ui/sidebar.js.map +1 -1
  41. package/dist/ui/skeleton.js +39 -39
  42. package/dist/ui/slider.d.ts.map +1 -1
  43. package/dist/ui/slider.js +18 -17
  44. package/dist/ui/slider.js.map +1 -1
  45. package/dist/ui/surface.js +9 -9
  46. package/dist/ui/switch.d.ts.map +1 -1
  47. package/dist/ui/switch.js +1 -0
  48. package/dist/ui/switch.js.map +1 -1
  49. package/dist/ui/tabs.js +47 -47
  50. package/dist/ui/text.js +8 -8
  51. package/dist/ui/textarea.js +12 -12
  52. package/dist/ui/toggle.js +12 -12
  53. package/docs/recipes/install-astro.md +2 -2
  54. package/docs/recipes/install-next-app-router.md +2 -2
  55. package/docs/recipes/install-remix.md +2 -2
  56. package/docs/recipes/install-tanstack-start.md +2 -2
  57. package/docs/recipes/install-vite.md +2 -2
  58. package/docs/recipes/troubleshoot.md +26 -5
  59. package/llms.txt +1 -1
  60. package/mcp-manifest.json +24 -3
  61. package/package.json +39 -11
  62. package/skill/SKILL.md +1 -1
  63. package/skill/references/components.md +1 -1
  64. package/skill/references/setup-astro.md +2 -2
  65. package/skill/references/setup-next-app-router.md +2 -2
  66. package/skill/references/setup-remix.md +2 -2
  67. package/skill/references/setup-tanstack-start.md +2 -2
  68. package/skill/references/setup-vite.md +2 -2
  69. package/skill/references/troubleshoot.md +26 -5
  70. package/dist/_chunks/tiptap.js +0 -18809
  71. package/dist/_chunks/tiptap.js.map +0 -1
  72. package/dist/_chunks/vendor-utils.js +0 -1766
  73. package/dist/_chunks/vendor-utils.js.map +0 -1
  74. package/scripts/welcome.mjs +0 -312
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-editor.js","names":[],"sources":["../../src/composed/rich-text-editor.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconAlignCenter,\n IconAlignLeft,\n IconAlignRight,\n IconArrowBackUp,\n IconArrowForwardUp,\n IconBlockquote,\n IconBold,\n IconCode,\n IconEye,\n IconH2,\n IconH3,\n IconHighlight,\n IconItalic,\n IconLineDashed,\n IconLink,\n IconList,\n IconListCheck,\n IconListNumbers,\n IconMoodSmile,\n IconPaperclip,\n IconPhoto,\n IconStrikethrough,\n IconUnderline,\n} from '@tabler/icons-react'\nimport Highlight from '@tiptap/extension-highlight'\nimport Image from '@tiptap/extension-image'\nimport { ListKit } from '@tiptap/extension-list'\nimport Mention from '@tiptap/extension-mention'\nimport TextAlign from '@tiptap/extension-text-align'\nimport { Placeholder } from '@tiptap/extensions'\nimport { Markdown } from '@tiptap/markdown'\nimport { type Editor,EditorContent, useEditor, useEditorState } from '@tiptap/react'\nimport StarterKit from '@tiptap/starter-kit'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { MENTION_TOKEN_CLASS } from '../ui/lib/mention'\nimport { cn } from '../ui/lib/utils'\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'\n\nconst PROSE_CLASSES = [\n 'prose prose-sm max-w-none',\n 'font-body text-body-md leading-relaxed text-surface-fg',\n '[&_h2]:text-heading-sm [&_h2]:mb-ds-03 [&_h2]:mt-ds-05 [&_h2]:text-surface-fg',\n '[&_h3]:text-body-lg [&_h3]:font-semibold [&_h3]:mb-ds-02b [&_h3]:mt-ds-04 [&_h3]:text-surface-fg',\n '[&_p]:mb-ds-02b [&_p]:text-surface-fg-muted',\n '[&_ul]:ml-ds-05 [&_ul]:list-disc [&_ol]:ml-ds-05 [&_ol]:list-decimal',\n '[&_li]:text-surface-fg-muted',\n '[&_code]:rounded [&_code]:bg-surface-raised [&_code]:px-ds-02b [&_code]:py-ds-01 [&_code]:text-body-md [&_code]:text-accent-11',\n '[&_pre]:rounded-surface [&_pre]:bg-surface-raised [&_pre]:p-ds-04',\n '[&_strong]:font-semibold [&_strong]:text-surface-fg',\n // slop-allow: side-stripe — blockquote left-rule is standard typography, not a card accent-rail\n '[&_blockquote]:border-l-[3px] [&_blockquote]:border-accent-6 [&_blockquote]:pl-ds-04 [&_blockquote]:italic [&_blockquote]:text-surface-fg-subtle',\n '[&_mark]:rounded-xs [&_mark]:bg-warning-3 [&_mark]:px-[2px]',\n '[&_ul[data-type=\"taskList\"]]:ml-0 [&_ul[data-type=\"taskList\"]]:list-none [&_li[data-type=\"taskItem\"]]:flex [&_li[data-type=\"taskItem\"]]:items-start [&_li[data-type=\"taskItem\"]]:gap-ds-02',\n '[&_hr]:my-ds-04 [&_hr]:border-surface-border-strong',\n '[&_a]:text-accent-11 [&_a]:underline [&_a]:decoration-accent-6 hover:[&_a]:decoration-accent-11',\n '[&_img]:max-w-full [&_img]:rounded-control [&_img]:my-ds-03',\n MENTION_TOKEN_CLASS,\n] as const\n\ninterface ToolbarButtonProps {\n onClick: () => void\n isActive?: boolean\n disabled?: boolean\n title: string\n children: React.ReactNode\n}\n\nfunction ToolbarButton({\n onClick,\n isActive = false,\n disabled = false,\n title,\n children,\n}: ToolbarButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\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 transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n isActive\n ? 'bg-surface-raised-hover text-accent-11'\n : 'text-surface-fg-subtle',\n )}\n >\n {children}\n </button>\n )\n}\n\nfunction LinkButton({ editor }: { editor: Editor }) {\n const [showInput, setShowInput] = React.useState(false)\n const [url, setUrl] = React.useState('')\n const inputRef = React.useRef<HTMLInputElement>(null)\n const { isLink } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isLink: e.isActive('link') }),\n })\n\n const handleToggle = () => {\n if (isLink) {\n editor.chain().focus().unsetLink().run()\n return\n }\n const previousUrl = editor.getAttributes('link').href || ''\n setUrl(previousUrl)\n setShowInput(true)\n setTimeout(() => inputRef.current?.focus(), 0)\n }\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault()\n if (url.trim()) {\n editor.chain().focus().setLink({ href: url.trim() }).run()\n }\n setShowInput(false)\n setUrl('')\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n setShowInput(false)\n setUrl('')\n editor.commands.focus()\n }\n }\n\n return (\n <div className=\"relative\">\n <ToolbarButton onClick={handleToggle} isActive={isLink} title=\"Link\">\n <Icon icon={IconLink} size=\"sm\" />\n </ToolbarButton>\n {showInput && (\n <form\n onSubmit={handleSubmit}\n aria-label=\"Edit link URL\"\n className=\"absolute left-0 top-full z-popover mt-ds-01 flex items-center gap-ds-02 rounded-control bg-surface-overlay p-ds-02 shadow-raised-hover\"\n >\n <input\n ref={inputRef}\n type=\"url\"\n value={url}\n onChange={(e) => setUrl(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"https://...\"\n className=\"h-ds-sm w-[240px] rounded-control-inner border border-surface-border-strong bg-surface-overlay px-ds-03 text-body-sm text-surface-fg focus:border-accent-7 focus:outline-hidden\"\n />\n <Button type=\"submit\" variant=\"solid\" size=\"sm\">\n Apply\n </Button>\n </form>\n )}\n </div>\n )\n}\n\nfunction ToolbarDivider() {\n return <div className=\"mx-ds-02 h-ds-05 w-px bg-surface-border\" />\n}\n\nfunction Toolbar({ editor, toolbar, onImageClick, onFileClick, onEmojiClick, trailing, showControls = true }: {\n editor: Editor\n toolbar?: ToolbarItem[]\n onImageClick?: () => void\n onFileClick?: () => void\n onEmojiClick?: () => void\n /** Right-aligned content (e.g. a source-view toggle). */\n trailing?: React.ReactNode\n /** Hide the formatting controls, keeping only `trailing`. @default true */\n showControls?: boolean\n}) {\n // v3: useEditorState subscribes to specific state slices so the toolbar\n // re-renders only when active-state or can-undo/redo actually changes.\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 isH2: e.isActive('heading', { level: 2 }),\n isH3: e.isActive('heading', { level: 3 }),\n isBlockquote: e.isActive('blockquote'),\n isBulletList: e.isActive('bulletList'),\n isOrderedList: e.isActive('orderedList'),\n isTaskList: e.isActive('taskList'),\n isCodeBlock: e.isActive('codeBlock'),\n isLink: e.isActive('link'),\n isAlignLeft: e.isActive({ textAlign: 'left' }),\n isAlignCenter: e.isActive({ textAlign: 'center' }),\n isAlignRight: e.isActive({ textAlign: 'right' }),\n canUndo: e.can().undo(),\n canRedo: e.can().redo(),\n }),\n })\n\n const show = (item: ToolbarItem) => !toolbar || toolbar.includes(item)\n\n // Each group is an array of ToolbarItem names that belong to it.\n // A divider renders between two adjacent groups only if both have at least one visible item.\n const hasInline = show('bold') || show('italic') || show('underline') || show('strike') || show('highlight')\n const hasBlock = show('h2') || show('h3') || show('blockquote')\n const hasList = show('bulletList') || show('orderedList') || show('taskList') || show('codeBlock')\n const hasMedia = show('link') || (!!onImageClick && show('image')) || (!!onFileClick && show('file')) || show('hr')\n const hasAlign = show('alignLeft') || show('alignCenter') || show('alignRight')\n const hasEmojiGroup = !!onEmojiClick && show('emoji')\n const hasHistory = show('undo') || show('redo')\n\n return (\n <div role=\"toolbar\" aria-label=\"Text formatting\" className=\"flex min-h-[2.75rem] flex-wrap items-center gap-ds-01 border-b border-surface-border-strong px-ds-04 py-ds-02b\">\n {showControls && (<>\n {/* Inline formatting */}\n {show('bold') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBold().run()} isActive={state.isBold} title=\"Bold\">\n <Icon icon={IconBold} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('italic') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleItalic().run()} isActive={state.isItalic} title=\"Italic\">\n <Icon icon={IconItalic} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('underline') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleUnderline().run()} isActive={state.isUnderline} title=\"Underline\">\n <Icon icon={IconUnderline} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('strike') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleStrike().run()} isActive={state.isStrike} title=\"Strikethrough\">\n <Icon icon={IconStrikethrough} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('highlight') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHighlight().run()} isActive={state.isHighlight} title=\"Highlight\">\n <Icon icon={IconHighlight} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasInline && hasBlock && <ToolbarDivider />}\n\n {/* Block formatting */}\n {show('h2') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()} isActive={state.isH2} title=\"Heading 2\">\n <Icon icon={IconH2} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('h3') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()} isActive={state.isH3} title=\"Heading 3\">\n <Icon icon={IconH3} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('blockquote') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBlockquote().run()} isActive={state.isBlockquote} title=\"Blockquote\">\n <Icon icon={IconBlockquote} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasBlock && hasList && <ToolbarDivider />}\n\n {/* Lists */}\n {show('bulletList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBulletList().run()} isActive={state.isBulletList} title=\"Bullet list\">\n <Icon icon={IconList} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('orderedList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleOrderedList().run()} isActive={state.isOrderedList} title=\"Ordered list\">\n <Icon icon={IconListNumbers} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('taskList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleTaskList().run()} isActive={state.isTaskList} title=\"Task list\">\n <Icon icon={IconListCheck} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('codeBlock') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleCodeBlock().run()} isActive={state.isCodeBlock} title=\"Code block\">\n <Icon icon={IconCode} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasList && hasMedia && <ToolbarDivider />}\n\n {/* Media & Links */}\n {show('link') && <LinkButton editor={editor} />}\n {onImageClick && show('image') && (\n <ToolbarButton onClick={onImageClick} title=\"Insert image\">\n <Icon icon={IconPhoto} size=\"sm\" />\n </ToolbarButton>\n )}\n {onFileClick && show('file') && (\n <ToolbarButton onClick={onFileClick} title=\"Attach file\">\n <Icon icon={IconPaperclip} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('hr') && (\n <ToolbarButton onClick={() => editor.chain().focus().setHorizontalRule().run()} title=\"Horizontal rule\">\n <Icon icon={IconLineDashed} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {hasMedia && hasAlign && <ToolbarDivider />}\n\n {/* Alignment */}\n {show('alignLeft') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('left').run()} isActive={state.isAlignLeft} title=\"Align left\">\n <Icon icon={IconAlignLeft} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('alignCenter') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('center').run()} isActive={state.isAlignCenter} title=\"Align center\">\n <Icon icon={IconAlignCenter} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('alignRight') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('right').run()} isActive={state.isAlignRight} title=\"Align right\">\n <Icon icon={IconAlignRight} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {hasAlign && (hasEmojiGroup || hasHistory) && <ToolbarDivider />}\n\n {/* Emoji */}\n {onEmojiClick && show('emoji') && (\n <ToolbarButton onClick={onEmojiClick} title=\"Emoji\">\n <Icon icon={IconMoodSmile} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {/* History */}\n {show('undo') && (\n <ToolbarButton onClick={() => editor.chain().focus().undo().run()} disabled={!state.canUndo} title=\"Undo\">\n <Icon icon={IconArrowBackUp} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('redo') && (\n <ToolbarButton onClick={() => editor.chain().focus().redo().run()} disabled={!state.canRedo} title=\"Redo\">\n <Icon icon={IconArrowForwardUp} size=\"sm\" />\n </ToolbarButton>\n )}\n </>)}\n {trailing && <div className=\"ml-auto flex items-center pl-ds-02\">{trailing}</div>}\n </div>\n )\n}\n\nconst LazyPicker = React.lazy(() =>\n import('./emoji-picker').then((m) => ({ default: m.EmojiPicker })),\n)\n\nfunction EmojiPickerLazy({ onSelect }: { onSelect: (emoji: EmojiData) => void }) {\n const fallback = <div className=\"flex h-[435px] w-[352px] items-center justify-center rounded-surface bg-surface-overlay shadow-raised-hover\"><span className=\"text-body-sm text-surface-fg-subtle\">Loading…</span></div>\n\n return (\n <React.Suspense fallback={fallback}>\n <LazyPicker onSelect={onSelect} />\n </React.Suspense>\n )\n}\n\nexport type ToolbarItem =\n | 'bold' | 'italic' | 'underline' | 'strike' | 'highlight'\n | 'h2' | 'h3' | 'blockquote'\n | 'bulletList' | 'orderedList' | 'taskList' | 'codeBlock'\n | 'link' | 'image' | 'file' | 'hr'\n | 'alignLeft' | 'alignCenter' | 'alignRight'\n | 'emoji' | 'undo' | 'redo'\n\nexport interface MentionItem {\n id: string\n label: string\n avatar?: string\n}\n\n/**\n * A Tiptap-powered rich text editor with a configurable toolbar, @mentions,\n * emoji suggestions, file/image uploads, and task lists.\n *\n * Emits HTML by default, or Markdown when `format=\"markdown\"`. NOTE: the HTML\n * output is the editor's raw HTML and is NOT sanitized — do not render it as\n * untrusted content without sanitizing it first. Storing Markdown (and\n * rendering via MarkdownViewer) sidesteps that risk entirely.\n */\nexport interface RichTextEditorProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'onChange' | 'content'> {\n /** Content format read and emitted. `markdown` for Markdown in/out; `html` uses HTML. @default 'html' */\n format?: 'html' | 'markdown'\n /** Initial content, interpreted per `format`. Updates are NOT reactive — use `onChange` for controlled state. */\n content?: string\n placeholder?: string\n /** Called with the editor content (HTML, or Markdown when `format=\"markdown\"`) whenever it changes. */\n onChange?: (value: string) => void\n className?: string\n /** Set to false to render in read-only mode (e.g. for previewing). */\n editable?: boolean\n /** Called when an image is pasted/dropped. Return a URL. If not provided, images inline as base64. */\n onImageUpload?: (file: File) => Promise<string>\n /** Called when a non-image file is dropped/pasted. If not provided, non-image files are ignored. */\n onFileUpload?: (file: File) => Promise<{ url: string; name: string; size: number }>\n /** Whitelist of toolbar items to display. Omit to show all. */\n toolbar?: ToolbarItem[]\n /** Static list of mentionable items (shown when user types @). */\n mentions?: MentionItem[]\n /** Async mention search. Takes precedence over static `mentions` list. */\n onMentionSearch?: (query: string) => Promise<MentionItem[]>\n /** Called when a mention is selected from the suggestion dropdown. */\n onMentionSelect?: (item: MentionItem) => void\n /** Emoji art style. @default 'native' */\n emojiSet?: EmojiSet\n /** Show a source-view toggle (raw Markdown ⇄ visual) in the top-right of the default editor. @default false */\n sourceToggle?: boolean\n /** Controlled source-view state — drive it from an external button. */\n sourceMode?: boolean\n /** Uncontrolled initial source-view state. @default false */\n defaultSourceMode?: boolean\n /** Called when the source view toggles (raw Markdown ⇄ visual). */\n onSourceModeChange?: (source: boolean) => void\n}\n\n// --------------------------- compound slot context ------------------------\n\ninterface RTEContextValue {\n editor: Editor\n toolbar?: ToolbarItem[]\n editable: boolean\n onImageClick: () => void\n onFileClick?: () => void\n onEmojiClick: () => void\n /** Raw-Markdown source view active. */\n sourceMode: boolean\n setSourceMode: (source: boolean) => void\n toggleSource: () => void\n sourceText: string\n onSourceChange: (value: string) => void\n}\n\nconst RTEContext = React.createContext<RTEContextValue | null>(null)\n\n/** Access the editor + toolbar wiring inside a `<RichTextEditor.Provider>`. */\nfunction useRichTextEditor(): RTEContextValue {\n const ctx = React.useContext(RTEContext)\n if (!ctx) throw new Error('RichTextEditor.Toolbar / .Content must be used within <RichTextEditor.Provider>')\n return ctx\n}\n\nexport interface RichTextEditorProviderProps extends RichTextEditorProps {\n children?: React.ReactNode\n}\n\n/**\n * Owns the Tiptap editor + all upload/emoji/mention plumbing and provides it to\n * `RichTextEditor.Toolbar` / `RichTextEditor.Content`. Compose your own layout\n * (toolbar top/bottom/floating, or bring your own) around these slots, or use\n * `<RichTextEditor>` for the batteries-included default.\n */\nconst RichTextEditorProvider = React.forwardRef<HTMLDivElement, RichTextEditorProviderProps>(\n function RichTextEditorProvider({\n format = 'html',\n content = '',\n placeholder = 'Start writing...',\n onChange,\n className,\n editable = true,\n toolbar,\n onImageUpload,\n onFileUpload,\n mentions,\n onMentionSearch,\n onMentionSelect,\n sourceMode: sourceModeProp,\n defaultSourceMode = false,\n onSourceModeChange,\n // @deprecated no-op since the frimousse migration (native-only emoji). Kept\n // out of `...props` so it never leaks onto the DOM.\n emojiSet: _emojiSet = 'native',\n // Default-render-only flag; dropped here so it never leaks onto the DOM.\n sourceToggle: _sourceToggle,\n children,\n ...props\n}, ref) {\n const editorRef = React.useRef<ReturnType<typeof useEditor>>(null)\n const isInternalChangeRef = React.useRef(false)\n const reduceMotion = useReducedMotion()\n const [showEmojiPicker, setShowEmojiPicker] = React.useState(false)\n\n // Source view (raw Markdown), controllable.\n const [uncontrolledSource, setUncontrolledSource] = React.useState(defaultSourceMode)\n const sourceMode = sourceModeProp ?? uncontrolledSource\n const setSourceMode = React.useCallback(\n (v: boolean) => {\n if (sourceModeProp === undefined) setUncontrolledSource(v)\n onSourceModeChange?.(v)\n },\n [sourceModeProp, onSourceModeChange],\n )\n const [sourceText, setSourceText] = React.useState('')\n const emojiPickerRef = React.useRef<HTMLDivElement>(null)\n const imageInputRef = React.useRef<HTMLInputElement>(null)\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n\n const handleImageInsert = async (file: File) => {\n const ed = editorRef.current\n if (!ed) return\n if (onImageUpload) {\n const url = await onImageUpload(file)\n if (url && /^https?:\\/\\//i.test(url)) {\n ed.chain().focus().setImage({ src: url }).run()\n }\n } else {\n const reader = new FileReader()\n reader.onload = () => {\n ed.chain().focus().setImage({ src: reader.result as string }).run()\n }\n reader.readAsDataURL(file)\n }\n }\n\n const handleFileInsert = async (file: File) => {\n const ed = editorRef.current\n if (!ed || !onFileUpload) return\n const result = await onFileUpload(file)\n ed.chain().focus().insertContent({\n type: 'fileAttachment',\n attrs: { url: result.url, name: result.name, size: result.size },\n }).run()\n }\n\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions: [\n StarterKit.configure({\n heading: { levels: [2, 3] },\n // v3: Underline + Link are now included in StarterKit\n link: {\n openOnClick: false,\n protocols: ['http', 'https', 'mailto'],\n validate: (href: string) => /^(https?:\\/\\/|mailto:)/i.test(href),\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n },\n }),\n Placeholder.configure({\n placeholder,\n emptyEditorClass:\n 'before:content-[attr(data-placeholder)] before:text-surface-fg-subtle before:float-left before:h-0 before:pointer-events-none',\n }),\n Highlight.configure({ multicolor: false }),\n ListKit.configure({\n bulletList: false, // Already in StarterKit\n orderedList: false, // Already in StarterKit\n listItem: false, // Already in StarterKit\n listKeymap: false, // Already in StarterKit\n taskList: {},\n taskItem: { nested: true },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Image.configure({\n allowBase64: true,\n HTMLAttributes: {\n class: 'max-w-full rounded-control',\n },\n }),\n FileAttachment,\n ...(mentions || onMentionSearch ? [\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n suggestion: {\n items: async ({ query }: { query: string }) => {\n if (onMentionSearch) return await onMentionSearch(query)\n if (mentions) return mentions.filter(m => m.label.toLowerCase().includes(query.toLowerCase())).slice(0, 8)\n return []\n },\n render: createSuggestionRenderer(onMentionSelect),\n },\n }),\n ] : []),\n EmojiNode,\n createEmojiSuggestion(),\n Markdown,\n ],\n content,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n editable,\n editorProps: {\n handleDrop: (_view, event, _slice, moved) => {\n if (moved || !event.dataTransfer?.files.length) return false\n const file = event.dataTransfer.files[0]\n if (!file) return false\n if (file.type.startsWith('image/')) {\n handleImageInsert(file)\n return true\n }\n if (onFileUpload) {\n handleFileInsert(file)\n return true\n }\n return false\n },\n handlePaste: (_view, event) => {\n const file = event.clipboardData?.files[0]\n if (!file) return false\n if (file.type.startsWith('image/')) {\n handleImageInsert(file)\n return true\n }\n if (onFileUpload) {\n handleFileInsert(file)\n return true\n }\n return false\n },\n attributes: {\n class: cn(\n ...PROSE_CLASSES,\n 'focus:outline-hidden',\n 'min-h-[120px] px-ds-04 py-ds-04',\n ),\n },\n },\n onUpdate: ({ editor: ed }) => {\n isInternalChangeRef.current = true\n onChange?.(format === 'markdown' ? ed.getMarkdown() : ed.getHTML())\n queueMicrotask(() => {\n isInternalChangeRef.current = false\n })\n },\n })\n\n React.useEffect(() => {\n editorRef.current = editor\n }, [editor])\n\n // Close emoji picker on click outside\n React.useEffect(() => {\n if (!showEmojiPicker) return\n const handleClickOutside = (e: MouseEvent) => {\n if (emojiPickerRef.current && !emojiPickerRef.current.contains(e.target as Node)) {\n setShowEmojiPicker(false)\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [showEmojiPicker])\n\n React.useEffect(() => {\n if (isInternalChangeRef.current) return\n if (!editor) return\n const current = format === 'markdown' ? editor.getMarkdown() : editor.getHTML()\n if (content !== current) {\n editor.commands.setContent(content, {\n emitUpdate: false,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n })\n }\n }, [editor, content, format])\n\n // Entering source view: seed the textarea with the editor's current Markdown.\n React.useEffect(() => {\n if (sourceMode && editor) setSourceText(editor.getMarkdown())\n // Only re-seed on the source-mode transition, not on every keystroke.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [sourceMode])\n\n if (!editor) return null\n\n const onSourceChange = (v: string) => {\n setSourceText(v)\n // Push edits back into the doc so `onChange` fires in the configured format.\n editor.commands.setContent(v, { contentType: 'markdown' })\n }\n\n const ctx: RTEContextValue = {\n editor,\n toolbar,\n editable,\n onImageClick: () => imageInputRef.current?.click(),\n onFileClick: onFileUpload ? () => fileInputRef.current?.click() : undefined,\n onEmojiClick: () => setShowEmojiPicker((prev) => !prev),\n sourceMode,\n setSourceMode,\n toggleSource: () => setSourceMode(!sourceMode),\n sourceText,\n onSourceChange,\n }\n\n return (\n <RTEContext.Provider value={ctx}>\n <div ref={ref} {...props} className={cn('relative', className)}>\n {/* Emoji picker rendered outside the overflow-hidden box so it isn't clipped */}\n <AnimatePresence>\n {showEmojiPicker && (\n <motion.div\n key=\"emoji-picker\"\n ref={emojiPickerRef}\n initial={reduceMotion ? false : { opacity: 0, scale: 0.96, y: 4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={reduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.96, y: 4 }}\n transition={{ duration: 0.14, ease: 'easeOut' }}\n className=\"absolute bottom-full right-0 z-popover mb-ds-02 origin-bottom-right\"\n onKeyDown={(e) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n setShowEmojiPicker(false)\n }\n }}\n >\n <EmojiPickerLazy\n onSelect={({ id, native }) => {\n editor.chain().focus().insertContent({\n type: 'emojiNode',\n attrs: { id, native },\n }).run()\n setShowEmojiPicker(false)\n }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Upload image\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleImageInsert(file)\n e.target.value = ''\n }}\n />\n {onFileUpload && (\n <input\n ref={fileInputRef}\n type=\"file\"\n aria-label=\"Upload file\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleFileInsert(file)\n e.target.value = ''\n }}\n />\n )}\n {children}\n </div>\n </RTEContext.Provider>\n )\n},\n)\n\nRichTextEditorProvider.displayName = 'RichTextEditor.Provider'\n\n/**\n * The formatting toolbar. Reads the editor from `<RichTextEditor.Provider>`.\n * In source view the format controls hide but `trailing` (e.g. the source\n * toggle) stays, so the bar persists.\n */\nfunction RichTextEditorToolbarSlot({ trailing }: { trailing?: React.ReactNode }) {\n const { editor, toolbar, editable, sourceMode, onImageClick, onFileClick, onEmojiClick } = useRichTextEditor()\n if (!editable) return null\n const showControls = !sourceMode\n if (!showControls && !trailing) return null\n return (\n <Toolbar\n editor={editor}\n toolbar={toolbar}\n showControls={showControls}\n trailing={trailing}\n onImageClick={onImageClick}\n onFileClick={onFileClick}\n onEmojiClick={onEmojiClick}\n />\n )\n}\nRichTextEditorToolbarSlot.displayName = 'RichTextEditor.Toolbar'\n\n/** The content area — the visual editor, or a raw-Markdown textarea in source view. */\nfunction RichTextEditorContentSlot() {\n const { editor, sourceMode, sourceText, onSourceChange } = useRichTextEditor()\n const reduce = useReducedMotion()\n const enter = reduce ? { opacity: 0 } : { opacity: 0, y: 4 }\n return (\n <AnimatePresence mode=\"wait\" initial={false}>\n {sourceMode ? (\n <motion.div key=\"source\" initial={enter} animate={{ opacity: 1, y: 0 }} exit={enter} transition={{ duration: 0.14, ease: 'easeOut' }}>\n <textarea\n value={sourceText}\n onChange={(e) => onSourceChange(e.target.value)}\n spellCheck={false}\n aria-label=\"Markdown source\"\n className=\"block min-h-[120px] w-full resize-y bg-surface-raised px-ds-04 py-ds-04 font-mono text-body-sm leading-ds-relaxed text-surface-fg focus:outline-hidden\"\n />\n </motion.div>\n ) : (\n <motion.div key=\"visual\" initial={enter} animate={{ opacity: 1, y: 0 }} exit={enter} transition={{ duration: 0.14, ease: 'easeOut' }}>\n <EditorContent editor={editor} />\n </motion.div>\n )}\n </AnimatePresence>\n )\n}\nRichTextEditorContentSlot.displayName = 'RichTextEditor.Content'\n\n/**\n * A source-view toggle (raw Markdown ⇄ visual). Text + icon by default;\n * pass `iconOnly` for a compact button. Place it anywhere inside a Provider.\n */\nfunction RichTextEditorSourceToggleSlot({ className, iconOnly = false }: { className?: string; iconOnly?: boolean }) {\n const { sourceMode, toggleSource } = useRichTextEditor()\n const aria = sourceMode ? 'Switch to visual editor' : 'Switch to Markdown source'\n const icon = sourceMode ? IconEye : IconCode\n if (iconOnly) {\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-pressed={sourceMode}\n aria-label={aria}\n title={aria}\n className={className}\n onClick={toggleSource}\n >\n <Icon icon={icon} size=\"sm\" />\n </Button>\n )\n }\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-pressed={sourceMode}\n aria-label={aria}\n startIcon={icon}\n className={className}\n onClick={toggleSource}\n >\n {sourceMode ? 'Editor' : 'Markdown'}\n </Button>\n )\n}\nRichTextEditorSourceToggleSlot.displayName = 'RichTextEditor.SourceToggle'\n\n// Batteries-included default: Provider + bordered box + toolbar-over-content.\nconst RichTextEditorBase = React.forwardRef<HTMLDivElement, RichTextEditorProps>(\n function RichTextEditor(props, ref) {\n return (\n <RichTextEditorProvider ref={ref} {...props}>\n <div\n className={cn(\n 'overflow-hidden rounded-surface border border-surface-border-strong bg-surface-raised',\n 'transition-colors ease-productive-standard focus-within:border-surface-border-strong',\n )}\n >\n <RichTextEditorToolbarSlot\n trailing={props.sourceToggle ? <RichTextEditorSourceToggleSlot /> : undefined}\n />\n <RichTextEditorContentSlot />\n </div>\n </RichTextEditorProvider>\n )\n },\n)\nRichTextEditorBase.displayName = 'RichTextEditor'\n\nconst RichTextEditor = Object.assign(RichTextEditorBase, {\n Provider: RichTextEditorProvider,\n Toolbar: RichTextEditorToolbarSlot,\n Content: RichTextEditorContentSlot,\n SourceToggle: RichTextEditorSourceToggleSlot,\n})\n\nexport interface RichTextViewerProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'content'> {\n content: string\n /** Content format. `markdown` parses Markdown; `html` (default) parses HTML. @default 'html' */\n format?: 'html' | 'markdown'\n className?: string\n}\n\nconst RichTextViewer = React.forwardRef<HTMLDivElement, RichTextViewerProps>(\n function RichTextViewer({ content, format = 'html', className, ...props }, ref) {\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions: [\n StarterKit.configure({\n heading: { levels: [2, 3] },\n link: {\n openOnClick: true,\n protocols: ['http', 'https', 'mailto'],\n validate: (href: string) => /^(https?:\\/\\/|mailto:)/i.test(href),\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n },\n }),\n Highlight.configure({ multicolor: false }),\n ListKit.configure({\n bulletList: false,\n orderedList: false,\n listItem: false,\n listKeymap: false,\n taskList: {},\n taskItem: { nested: true },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Image.configure({\n allowBase64: true,\n HTMLAttributes: {\n class: 'max-w-full rounded-control',\n },\n }),\n FileAttachment,\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n }),\n Markdown,\n ],\n content,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n editable: false,\n editorProps: {\n attributes: {\n class: cn(...PROSE_CLASSES),\n },\n },\n })\n\n if (!editor) return null\n\n return (\n <div ref={ref} {...props} className={className}>\n <EditorContent editor={editor} />\n </div>\n )\n},\n)\n\nRichTextViewer.displayName = 'RichTextViewer'\n\nexport {\n RichTextEditor,\n RichTextEditorProvider,\n RichTextEditorToolbarSlot as RichTextEditorToolbar,\n RichTextEditorContentSlot as RichTextEditorContent,\n RichTextEditorSourceToggleSlot as RichTextEditorSourceToggle,\n useRichTextEditor,\n RichTextViewer,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rich-text-editor.js","names":[],"sources":["../../src/composed/rich-text-editor.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconAlignCenter,\n IconAlignLeft,\n IconAlignRight,\n IconArrowBackUp,\n IconArrowForwardUp,\n IconBlockquote,\n IconBold,\n IconCode,\n IconEye,\n IconH2,\n IconH3,\n IconHighlight,\n IconItalic,\n IconLineDashed,\n IconLink,\n IconList,\n IconListCheck,\n IconListNumbers,\n IconMoodSmile,\n IconPaperclip,\n IconPhoto,\n IconStrikethrough,\n IconUnderline,\n} from '@tabler/icons-react'\nimport Highlight from '@tiptap/extension-highlight'\nimport Image from '@tiptap/extension-image'\nimport { ListKit } from '@tiptap/extension-list'\nimport Mention from '@tiptap/extension-mention'\nimport TextAlign from '@tiptap/extension-text-align'\nimport { Placeholder } from '@tiptap/extensions'\nimport { Markdown } from '@tiptap/markdown'\nimport { type Editor,EditorContent, useEditor, useEditorState } from '@tiptap/react'\nimport StarterKit from '@tiptap/starter-kit'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Button } from '../ui/button'\nimport { Icon } from '../ui/icon'\nimport { MENTION_TOKEN_CLASS } from '../ui/lib/mention'\nimport { cn } from '../ui/lib/utils'\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'\n\nconst PROSE_CLASSES = [\n 'prose prose-sm max-w-none',\n 'font-body text-body-md leading-relaxed text-surface-fg',\n '[&_h2]:text-heading-sm [&_h2]:mb-ds-03 [&_h2]:mt-ds-05 [&_h2]:text-surface-fg',\n '[&_h3]:text-body-lg [&_h3]:font-semibold [&_h3]:mb-ds-02b [&_h3]:mt-ds-04 [&_h3]:text-surface-fg',\n '[&_p]:mb-ds-02b [&_p]:text-surface-fg-muted',\n '[&_ul]:ml-ds-05 [&_ul]:list-disc [&_ol]:ml-ds-05 [&_ol]:list-decimal',\n '[&_li]:text-surface-fg-muted',\n '[&_code]:rounded [&_code]:bg-surface-raised [&_code]:px-ds-02b [&_code]:py-ds-01 [&_code]:text-body-md [&_code]:text-accent-11',\n '[&_pre]:rounded-surface [&_pre]:bg-surface-raised [&_pre]:p-ds-04',\n '[&_strong]:font-semibold [&_strong]:text-surface-fg',\n // slop-allow: side-stripe — blockquote left-rule is standard typography, not a card accent-rail\n '[&_blockquote]:border-l-[3px] [&_blockquote]:border-accent-6 [&_blockquote]:pl-ds-04 [&_blockquote]:italic [&_blockquote]:text-surface-fg-subtle',\n '[&_mark]:rounded-xs [&_mark]:bg-warning-3 [&_mark]:px-[2px]',\n '[&_ul[data-type=\"taskList\"]]:ml-0 [&_ul[data-type=\"taskList\"]]:list-none [&_li[data-type=\"taskItem\"]]:flex [&_li[data-type=\"taskItem\"]]:items-start [&_li[data-type=\"taskItem\"]]:gap-ds-02',\n '[&_hr]:my-ds-04 [&_hr]:border-surface-border-strong',\n '[&_a]:text-accent-11 [&_a]:underline [&_a]:decoration-accent-6 hover:[&_a]:decoration-accent-11',\n '[&_img]:max-w-full [&_img]:rounded-control [&_img]:my-ds-03',\n MENTION_TOKEN_CLASS,\n] as const\n\ninterface ToolbarButtonProps {\n onClick: () => void\n isActive?: boolean\n disabled?: boolean\n title: string\n children: React.ReactNode\n}\n\nfunction ToolbarButton({\n onClick,\n isActive = false,\n disabled = false,\n title,\n children,\n}: ToolbarButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\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 transition-colors duration-fast-01 ease-productive-standard',\n 'hover:bg-surface-raised-hover',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n isActive\n ? 'bg-surface-raised-hover text-accent-11'\n : 'text-surface-fg-subtle',\n )}\n >\n {children}\n </button>\n )\n}\n\nfunction LinkButton({ editor }: { editor: Editor }) {\n const [showInput, setShowInput] = React.useState(false)\n const [url, setUrl] = React.useState('')\n const inputRef = React.useRef<HTMLInputElement>(null)\n const { isLink } = useEditorState({\n editor,\n selector: ({ editor: e }) => ({ isLink: e.isActive('link') }),\n })\n\n const handleToggle = () => {\n if (isLink) {\n editor.chain().focus().unsetLink().run()\n return\n }\n const previousUrl = editor.getAttributes('link').href || ''\n setUrl(previousUrl)\n setShowInput(true)\n setTimeout(() => inputRef.current?.focus(), 0)\n }\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault()\n if (url.trim()) {\n editor.chain().focus().setLink({ href: url.trim() }).run()\n }\n setShowInput(false)\n setUrl('')\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n setShowInput(false)\n setUrl('')\n editor.commands.focus()\n }\n }\n\n return (\n <div className=\"relative\">\n <ToolbarButton onClick={handleToggle} isActive={isLink} title=\"Link\">\n <Icon icon={IconLink} size=\"sm\" />\n </ToolbarButton>\n {showInput && (\n <form\n onSubmit={handleSubmit}\n aria-label=\"Edit link URL\"\n className=\"absolute left-0 top-full z-popover mt-ds-01 flex items-center gap-ds-02 rounded-control bg-surface-overlay p-ds-02 shadow-raised-hover\"\n >\n <input\n ref={inputRef}\n type=\"url\"\n value={url}\n onChange={(e) => setUrl(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"https://...\"\n className=\"h-ds-sm w-[240px] rounded-control-inner border border-surface-border-strong bg-surface-overlay px-ds-03 text-body-sm text-surface-fg focus:border-accent-7 focus:outline-hidden\"\n />\n <Button type=\"submit\" variant=\"solid\" size=\"sm\">\n Apply\n </Button>\n </form>\n )}\n </div>\n )\n}\n\nfunction ToolbarDivider() {\n return <div className=\"mx-ds-02 h-ds-05 w-px bg-surface-border\" />\n}\n\nfunction Toolbar({ editor, toolbar, onImageClick, onFileClick, onEmojiClick, trailing, showControls = true }: {\n editor: Editor\n toolbar?: ToolbarItem[]\n onImageClick?: () => void\n onFileClick?: () => void\n onEmojiClick?: () => void\n /** Right-aligned content (e.g. a source-view toggle). */\n trailing?: React.ReactNode\n /** Hide the formatting controls, keeping only `trailing`. @default true */\n showControls?: boolean\n}) {\n // v3: useEditorState subscribes to specific state slices so the toolbar\n // re-renders only when active-state or can-undo/redo actually changes.\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 isH2: e.isActive('heading', { level: 2 }),\n isH3: e.isActive('heading', { level: 3 }),\n isBlockquote: e.isActive('blockquote'),\n isBulletList: e.isActive('bulletList'),\n isOrderedList: e.isActive('orderedList'),\n isTaskList: e.isActive('taskList'),\n isCodeBlock: e.isActive('codeBlock'),\n isLink: e.isActive('link'),\n isAlignLeft: e.isActive({ textAlign: 'left' }),\n isAlignCenter: e.isActive({ textAlign: 'center' }),\n isAlignRight: e.isActive({ textAlign: 'right' }),\n canUndo: e.can().undo(),\n canRedo: e.can().redo(),\n }),\n })\n\n const show = (item: ToolbarItem) => !toolbar || toolbar.includes(item)\n\n // Each group is an array of ToolbarItem names that belong to it.\n // A divider renders between two adjacent groups only if both have at least one visible item.\n const hasInline = show('bold') || show('italic') || show('underline') || show('strike') || show('highlight')\n const hasBlock = show('h2') || show('h3') || show('blockquote')\n const hasList = show('bulletList') || show('orderedList') || show('taskList') || show('codeBlock')\n const hasMedia = show('link') || (!!onImageClick && show('image')) || (!!onFileClick && show('file')) || show('hr')\n const hasAlign = show('alignLeft') || show('alignCenter') || show('alignRight')\n const hasEmojiGroup = !!onEmojiClick && show('emoji')\n const hasHistory = show('undo') || show('redo')\n\n return (\n <div role=\"toolbar\" aria-label=\"Text formatting\" className=\"flex min-h-[2.75rem] flex-wrap items-center gap-ds-01 border-b border-surface-border-strong px-ds-04 py-ds-02b\">\n {showControls && (<>\n {/* Inline formatting */}\n {show('bold') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBold().run()} isActive={state.isBold} title=\"Bold\">\n <Icon icon={IconBold} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('italic') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleItalic().run()} isActive={state.isItalic} title=\"Italic\">\n <Icon icon={IconItalic} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('underline') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleUnderline().run()} isActive={state.isUnderline} title=\"Underline\">\n <Icon icon={IconUnderline} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('strike') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleStrike().run()} isActive={state.isStrike} title=\"Strikethrough\">\n <Icon icon={IconStrikethrough} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('highlight') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHighlight().run()} isActive={state.isHighlight} title=\"Highlight\">\n <Icon icon={IconHighlight} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasInline && hasBlock && <ToolbarDivider />}\n\n {/* Block formatting */}\n {show('h2') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()} isActive={state.isH2} title=\"Heading 2\">\n <Icon icon={IconH2} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('h3') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()} isActive={state.isH3} title=\"Heading 3\">\n <Icon icon={IconH3} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('blockquote') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBlockquote().run()} isActive={state.isBlockquote} title=\"Blockquote\">\n <Icon icon={IconBlockquote} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasBlock && hasList && <ToolbarDivider />}\n\n {/* Lists */}\n {show('bulletList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleBulletList().run()} isActive={state.isBulletList} title=\"Bullet list\">\n <Icon icon={IconList} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('orderedList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleOrderedList().run()} isActive={state.isOrderedList} title=\"Ordered list\">\n <Icon icon={IconListNumbers} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('taskList') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleTaskList().run()} isActive={state.isTaskList} title=\"Task list\">\n <Icon icon={IconListCheck} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n {show('codeBlock') && (\n <ToolbarButton onClick={() => editor.chain().focus().toggleCodeBlock().run()} isActive={state.isCodeBlock} title=\"Code block\">\n <Icon icon={IconCode} size=\"sm\" stroke=\"bold\" />\n </ToolbarButton>\n )}\n\n {hasList && hasMedia && <ToolbarDivider />}\n\n {/* Media & Links */}\n {show('link') && <LinkButton editor={editor} />}\n {onImageClick && show('image') && (\n <ToolbarButton onClick={onImageClick} title=\"Insert image\">\n <Icon icon={IconPhoto} size=\"sm\" />\n </ToolbarButton>\n )}\n {onFileClick && show('file') && (\n <ToolbarButton onClick={onFileClick} title=\"Attach file\">\n <Icon icon={IconPaperclip} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('hr') && (\n <ToolbarButton onClick={() => editor.chain().focus().setHorizontalRule().run()} title=\"Horizontal rule\">\n <Icon icon={IconLineDashed} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {hasMedia && hasAlign && <ToolbarDivider />}\n\n {/* Alignment */}\n {show('alignLeft') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('left').run()} isActive={state.isAlignLeft} title=\"Align left\">\n <Icon icon={IconAlignLeft} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('alignCenter') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('center').run()} isActive={state.isAlignCenter} title=\"Align center\">\n <Icon icon={IconAlignCenter} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('alignRight') && (\n <ToolbarButton onClick={() => editor.chain().focus().setTextAlign('right').run()} isActive={state.isAlignRight} title=\"Align right\">\n <Icon icon={IconAlignRight} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {hasAlign && (hasEmojiGroup || hasHistory) && <ToolbarDivider />}\n\n {/* Emoji */}\n {onEmojiClick && show('emoji') && (\n <ToolbarButton onClick={onEmojiClick} title=\"Emoji\">\n <Icon icon={IconMoodSmile} size=\"sm\" />\n </ToolbarButton>\n )}\n\n {/* History */}\n {show('undo') && (\n <ToolbarButton onClick={() => editor.chain().focus().undo().run()} disabled={!state.canUndo} title=\"Undo\">\n <Icon icon={IconArrowBackUp} size=\"sm\" />\n </ToolbarButton>\n )}\n {show('redo') && (\n <ToolbarButton onClick={() => editor.chain().focus().redo().run()} disabled={!state.canRedo} title=\"Redo\">\n <Icon icon={IconArrowForwardUp} size=\"sm\" />\n </ToolbarButton>\n )}\n </>)}\n {trailing && <div className=\"ml-auto flex items-center pl-ds-02\">{trailing}</div>}\n </div>\n )\n}\n\nconst LazyPicker = React.lazy(() =>\n import('./emoji-picker').then((m) => ({ default: m.EmojiPicker })),\n)\n\nfunction EmojiPickerLazy({ onSelect }: { onSelect: (emoji: EmojiData) => void }) {\n const fallback = <div className=\"flex h-[435px] w-[352px] items-center justify-center rounded-surface bg-surface-overlay shadow-raised-hover\"><span className=\"text-body-sm text-surface-fg-subtle\">Loading…</span></div>\n\n return (\n <React.Suspense fallback={fallback}>\n <LazyPicker onSelect={onSelect} />\n </React.Suspense>\n )\n}\n\nexport type ToolbarItem =\n | 'bold' | 'italic' | 'underline' | 'strike' | 'highlight'\n | 'h2' | 'h3' | 'blockquote'\n | 'bulletList' | 'orderedList' | 'taskList' | 'codeBlock'\n | 'link' | 'image' | 'file' | 'hr'\n | 'alignLeft' | 'alignCenter' | 'alignRight'\n | 'emoji' | 'undo' | 'redo'\n\nexport interface MentionItem {\n id: string\n label: string\n avatar?: string\n}\n\n/**\n * A Tiptap-powered rich text editor with a configurable toolbar, @mentions,\n * emoji suggestions, file/image uploads, and task lists.\n *\n * Emits HTML by default, or Markdown when `format=\"markdown\"`. NOTE: the HTML\n * output is the editor's raw HTML and is NOT sanitized — do not render it as\n * untrusted content without sanitizing it first. Storing Markdown (and\n * rendering via MarkdownViewer) sidesteps that risk entirely.\n */\nexport interface RichTextEditorProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'onChange' | 'content'> {\n /** Content format read and emitted. `markdown` for Markdown in/out; `html` uses HTML. @default 'html' */\n format?: 'html' | 'markdown'\n /** Initial content, interpreted per `format`. Updates are NOT reactive — use `onChange` for controlled state. */\n content?: string\n placeholder?: string\n /** Called with the editor content (HTML, or Markdown when `format=\"markdown\"`) whenever it changes. */\n onChange?: (value: string) => void\n className?: string\n /** Set to false to render in read-only mode (e.g. for previewing). */\n editable?: boolean\n /** Called when an image is pasted/dropped. Return a URL. If not provided, images inline as base64. */\n onImageUpload?: (file: File) => Promise<string>\n /** Called when a non-image file is dropped/pasted. If not provided, non-image files are ignored. */\n onFileUpload?: (file: File) => Promise<{ url: string; name: string; size: number }>\n /** Whitelist of toolbar items to display. Omit to show all. */\n toolbar?: ToolbarItem[]\n /** Static list of mentionable items (shown when user types @). */\n mentions?: MentionItem[]\n /** Async mention search. Takes precedence over static `mentions` list. */\n onMentionSearch?: (query: string) => Promise<MentionItem[]>\n /** Called when a mention is selected from the suggestion dropdown. */\n onMentionSelect?: (item: MentionItem) => void\n /** Emoji art style. @default 'native' */\n emojiSet?: EmojiSet\n /** Show a source-view toggle (raw Markdown ⇄ visual) in the top-right of the default editor. @default false */\n sourceToggle?: boolean\n /** Controlled source-view state — drive it from an external button. */\n sourceMode?: boolean\n /** Uncontrolled initial source-view state. @default false */\n defaultSourceMode?: boolean\n /** Called when the source view toggles (raw Markdown ⇄ visual). */\n onSourceModeChange?: (source: boolean) => void\n}\n\n// --------------------------- compound slot context ------------------------\n\ninterface RTEContextValue {\n editor: Editor\n toolbar?: ToolbarItem[]\n editable: boolean\n onImageClick: () => void\n onFileClick?: () => void\n onEmojiClick: () => void\n /** Raw-Markdown source view active. */\n sourceMode: boolean\n setSourceMode: (source: boolean) => void\n toggleSource: () => void\n sourceText: string\n onSourceChange: (value: string) => void\n}\n\nconst RTEContext = React.createContext<RTEContextValue | null>(null)\n\n/** Access the editor + toolbar wiring inside a `<RichTextEditor.Provider>`. */\nfunction useRichTextEditor(): RTEContextValue {\n const ctx = React.useContext(RTEContext)\n if (!ctx) throw new Error('RichTextEditor.Toolbar / .Content must be used within <RichTextEditor.Provider>')\n return ctx\n}\n\nexport interface RichTextEditorProviderProps extends RichTextEditorProps {\n children?: React.ReactNode\n}\n\n/**\n * Owns the Tiptap editor + all upload/emoji/mention plumbing and provides it to\n * `RichTextEditor.Toolbar` / `RichTextEditor.Content`. Compose your own layout\n * (toolbar top/bottom/floating, or bring your own) around these slots, or use\n * `<RichTextEditor>` for the batteries-included default.\n */\nconst RichTextEditorProvider = React.forwardRef<HTMLDivElement, RichTextEditorProviderProps>(\n function RichTextEditorProvider({\n format = 'html',\n content = '',\n placeholder = 'Start writing...',\n onChange,\n className,\n editable = true,\n toolbar,\n onImageUpload,\n onFileUpload,\n mentions,\n onMentionSearch,\n onMentionSelect,\n sourceMode: sourceModeProp,\n defaultSourceMode = false,\n onSourceModeChange,\n // @deprecated no-op since the frimousse migration (native-only emoji). Kept\n // out of `...props` so it never leaks onto the DOM.\n emojiSet: _emojiSet = 'native',\n // Default-render-only flag; dropped here so it never leaks onto the DOM.\n sourceToggle: _sourceToggle,\n children,\n ...props\n}, ref) {\n const editorRef = React.useRef<ReturnType<typeof useEditor>>(null)\n const isInternalChangeRef = React.useRef(false)\n const reduceMotion = useReducedMotion()\n const [showEmojiPicker, setShowEmojiPicker] = React.useState(false)\n\n // Source view (raw Markdown), controllable.\n const [uncontrolledSource, setUncontrolledSource] = React.useState(defaultSourceMode)\n const sourceMode = sourceModeProp ?? uncontrolledSource\n const setSourceMode = React.useCallback(\n (v: boolean) => {\n if (sourceModeProp === undefined) setUncontrolledSource(v)\n onSourceModeChange?.(v)\n },\n [sourceModeProp, onSourceModeChange],\n )\n const [sourceText, setSourceText] = React.useState('')\n const emojiPickerRef = React.useRef<HTMLDivElement>(null)\n const imageInputRef = React.useRef<HTMLInputElement>(null)\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n\n const handleImageInsert = async (file: File) => {\n const ed = editorRef.current\n if (!ed) return\n if (onImageUpload) {\n const url = await onImageUpload(file)\n if (url && /^https?:\\/\\//i.test(url)) {\n ed.chain().focus().setImage({ src: url }).run()\n }\n } else {\n const reader = new FileReader()\n reader.onload = () => {\n ed.chain().focus().setImage({ src: reader.result as string }).run()\n }\n reader.readAsDataURL(file)\n }\n }\n\n const handleFileInsert = async (file: File) => {\n const ed = editorRef.current\n if (!ed || !onFileUpload) return\n const result = await onFileUpload(file)\n ed.chain().focus().insertContent({\n type: 'fileAttachment',\n attrs: { url: result.url, name: result.name, size: result.size },\n }).run()\n }\n\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions: [\n StarterKit.configure({\n heading: { levels: [2, 3] },\n // v3: Underline + Link are now included in StarterKit\n link: {\n openOnClick: false,\n protocols: ['http', 'https', 'mailto'],\n validate: (href: string) => /^(https?:\\/\\/|mailto:)/i.test(href),\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n },\n }),\n Placeholder.configure({\n placeholder,\n emptyEditorClass:\n 'before:content-[attr(data-placeholder)] before:text-surface-fg-subtle before:float-left before:h-0 before:pointer-events-none',\n }),\n Highlight.configure({ multicolor: false }),\n ListKit.configure({\n bulletList: false, // Already in StarterKit\n orderedList: false, // Already in StarterKit\n listItem: false, // Already in StarterKit\n listKeymap: false, // Already in StarterKit\n taskList: {},\n taskItem: { nested: true },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Image.configure({\n allowBase64: true,\n HTMLAttributes: {\n class: 'max-w-full rounded-control',\n },\n }),\n FileAttachment,\n ...(mentions || onMentionSearch ? [\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n suggestion: {\n items: async ({ query }: { query: string }) => {\n if (onMentionSearch) return await onMentionSearch(query)\n if (mentions) return mentions.filter(m => m.label.toLowerCase().includes(query.toLowerCase())).slice(0, 8)\n return []\n },\n render: createSuggestionRenderer(onMentionSelect),\n },\n }),\n ] : []),\n EmojiNode,\n createEmojiSuggestion(),\n Markdown,\n ],\n content,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n editable,\n editorProps: {\n handleDrop: (_view, event, _slice, moved) => {\n if (moved || !event.dataTransfer?.files.length) return false\n const file = event.dataTransfer.files[0]\n if (!file) return false\n if (file.type.startsWith('image/')) {\n handleImageInsert(file)\n return true\n }\n if (onFileUpload) {\n handleFileInsert(file)\n return true\n }\n return false\n },\n handlePaste: (_view, event) => {\n const file = event.clipboardData?.files[0]\n if (!file) return false\n if (file.type.startsWith('image/')) {\n handleImageInsert(file)\n return true\n }\n if (onFileUpload) {\n handleFileInsert(file)\n return true\n }\n return false\n },\n attributes: {\n class: cn(\n ...PROSE_CLASSES,\n 'focus:outline-hidden',\n 'min-h-[120px] px-ds-04 py-ds-04',\n ),\n },\n },\n onUpdate: ({ editor: ed }) => {\n isInternalChangeRef.current = true\n onChange?.(format === 'markdown' ? ed.getMarkdown() : ed.getHTML())\n queueMicrotask(() => {\n isInternalChangeRef.current = false\n })\n },\n })\n\n React.useEffect(() => {\n editorRef.current = editor\n }, [editor])\n\n // Close emoji picker on click outside\n React.useEffect(() => {\n if (!showEmojiPicker) return\n const handleClickOutside = (e: MouseEvent) => {\n if (emojiPickerRef.current && !emojiPickerRef.current.contains(e.target as Node)) {\n setShowEmojiPicker(false)\n }\n }\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }, [showEmojiPicker])\n\n React.useEffect(() => {\n if (isInternalChangeRef.current) return\n if (!editor) return\n const current = format === 'markdown' ? editor.getMarkdown() : editor.getHTML()\n if (content !== current) {\n editor.commands.setContent(content, {\n emitUpdate: false,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n })\n }\n }, [editor, content, format])\n\n // Entering source view: seed the textarea with the editor's current Markdown.\n React.useEffect(() => {\n if (sourceMode && editor) setSourceText(editor.getMarkdown())\n // Only re-seed on the source-mode transition, not on every keystroke.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [sourceMode])\n\n if (!editor) return null\n\n const onSourceChange = (v: string) => {\n setSourceText(v)\n // Push edits back into the doc so `onChange` fires in the configured format.\n editor.commands.setContent(v, { contentType: 'markdown' })\n }\n\n const ctx: RTEContextValue = {\n editor,\n toolbar,\n editable,\n onImageClick: () => imageInputRef.current?.click(),\n onFileClick: onFileUpload ? () => fileInputRef.current?.click() : undefined,\n onEmojiClick: () => setShowEmojiPicker((prev) => !prev),\n sourceMode,\n setSourceMode,\n toggleSource: () => setSourceMode(!sourceMode),\n sourceText,\n onSourceChange,\n }\n\n return (\n <RTEContext.Provider value={ctx}>\n <div ref={ref} {...props} className={cn('relative', className)}>\n {/* Emoji picker rendered outside the overflow-hidden box so it isn't clipped */}\n <AnimatePresence>\n {showEmojiPicker && (\n <motion.div\n key=\"emoji-picker\"\n ref={emojiPickerRef}\n initial={reduceMotion ? false : { opacity: 0, scale: 0.96, y: 4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={reduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.96, y: 4 }}\n transition={{ duration: 0.14, ease: 'easeOut' }}\n className=\"absolute bottom-full right-0 z-popover mb-ds-02 origin-bottom-right\"\n onKeyDown={(e) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n setShowEmojiPicker(false)\n }\n }}\n >\n <EmojiPickerLazy\n onSelect={({ id, native }) => {\n editor.chain().focus().insertContent({\n type: 'emojiNode',\n attrs: { id, native },\n }).run()\n setShowEmojiPicker(false)\n }}\n />\n </motion.div>\n )}\n </AnimatePresence>\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n aria-label=\"Upload image\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleImageInsert(file)\n e.target.value = ''\n }}\n />\n {onFileUpload && (\n <input\n ref={fileInputRef}\n type=\"file\"\n aria-label=\"Upload file\"\n className=\"hidden\"\n onChange={(e) => {\n const file = e.target.files?.[0]\n if (file) handleFileInsert(file)\n e.target.value = ''\n }}\n />\n )}\n {children}\n </div>\n </RTEContext.Provider>\n )\n},\n)\n\nRichTextEditorProvider.displayName = 'RichTextEditor.Provider'\n\n/**\n * The formatting toolbar. Reads the editor from `<RichTextEditor.Provider>`.\n * In source view the format controls hide but `trailing` (e.g. the source\n * toggle) stays, so the bar persists.\n */\nfunction RichTextEditorToolbarSlot({ trailing }: { trailing?: React.ReactNode }) {\n const { editor, toolbar, editable, sourceMode, onImageClick, onFileClick, onEmojiClick } = useRichTextEditor()\n if (!editable) return null\n const showControls = !sourceMode\n if (!showControls && !trailing) return null\n return (\n <Toolbar\n editor={editor}\n toolbar={toolbar}\n showControls={showControls}\n trailing={trailing}\n onImageClick={onImageClick}\n onFileClick={onFileClick}\n onEmojiClick={onEmojiClick}\n />\n )\n}\nRichTextEditorToolbarSlot.displayName = 'RichTextEditor.Toolbar'\n\n/** The content area — the visual editor, or a raw-Markdown textarea in source view. */\nfunction RichTextEditorContentSlot() {\n const { editor, sourceMode, sourceText, onSourceChange } = useRichTextEditor()\n const reduce = useReducedMotion()\n const enter = reduce ? { opacity: 0 } : { opacity: 0, y: 4 }\n return (\n <AnimatePresence mode=\"wait\" initial={false}>\n {sourceMode ? (\n <motion.div key=\"source\" initial={enter} animate={{ opacity: 1, y: 0 }} exit={enter} transition={{ duration: 0.14, ease: 'easeOut' }}>\n <textarea\n value={sourceText}\n onChange={(e) => onSourceChange(e.target.value)}\n spellCheck={false}\n aria-label=\"Markdown source\"\n className=\"block min-h-[120px] w-full resize-y bg-surface-raised px-ds-04 py-ds-04 font-mono text-body-sm leading-ds-relaxed text-surface-fg focus:outline-hidden\"\n />\n </motion.div>\n ) : (\n <motion.div key=\"visual\" initial={enter} animate={{ opacity: 1, y: 0 }} exit={enter} transition={{ duration: 0.14, ease: 'easeOut' }}>\n <EditorContent editor={editor} />\n </motion.div>\n )}\n </AnimatePresence>\n )\n}\nRichTextEditorContentSlot.displayName = 'RichTextEditor.Content'\n\n/**\n * A source-view toggle (raw Markdown ⇄ visual). Text + icon by default;\n * pass `iconOnly` for a compact button. Place it anywhere inside a Provider.\n */\nfunction RichTextEditorSourceToggleSlot({ className, iconOnly = false }: { className?: string; iconOnly?: boolean }) {\n const { sourceMode, toggleSource } = useRichTextEditor()\n const aria = sourceMode ? 'Switch to visual editor' : 'Switch to Markdown source'\n const icon = sourceMode ? IconEye : IconCode\n if (iconOnly) {\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-pressed={sourceMode}\n aria-label={aria}\n title={aria}\n className={className}\n onClick={toggleSource}\n >\n <Icon icon={icon} size=\"sm\" />\n </Button>\n )\n }\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-pressed={sourceMode}\n aria-label={aria}\n startIcon={icon}\n className={className}\n onClick={toggleSource}\n >\n {sourceMode ? 'Editor' : 'Markdown'}\n </Button>\n )\n}\nRichTextEditorSourceToggleSlot.displayName = 'RichTextEditor.SourceToggle'\n\n// Batteries-included default: Provider + bordered box + toolbar-over-content.\nconst RichTextEditorBase = React.forwardRef<HTMLDivElement, RichTextEditorProps>(\n function RichTextEditor(props, ref) {\n return (\n <RichTextEditorProvider ref={ref} {...props}>\n <div\n className={cn(\n 'overflow-hidden rounded-surface border border-surface-border-strong bg-surface-raised',\n 'transition-colors ease-productive-standard focus-within:border-surface-border-strong',\n )}\n >\n <RichTextEditorToolbarSlot\n trailing={props.sourceToggle ? <RichTextEditorSourceToggleSlot /> : undefined}\n />\n <RichTextEditorContentSlot />\n </div>\n </RichTextEditorProvider>\n )\n },\n)\nRichTextEditorBase.displayName = 'RichTextEditor'\n\nconst RichTextEditor = Object.assign(RichTextEditorBase, {\n Provider: RichTextEditorProvider,\n Toolbar: RichTextEditorToolbarSlot,\n Content: RichTextEditorContentSlot,\n SourceToggle: RichTextEditorSourceToggleSlot,\n})\n\nexport interface RichTextViewerProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'content'> {\n content: string\n /** Content format. `markdown` parses Markdown; `html` (default) parses HTML. @default 'html' */\n format?: 'html' | 'markdown'\n className?: string\n}\n\nconst RichTextViewer = React.forwardRef<HTMLDivElement, RichTextViewerProps>(\n function RichTextViewer({ content, format = 'html', className, ...props }, ref) {\n const editor = useEditor({\n immediatelyRender: false, // SSR-safe — prevents hydration mismatch in Next.js\n extensions: [\n StarterKit.configure({\n heading: { levels: [2, 3] },\n link: {\n openOnClick: true,\n protocols: ['http', 'https', 'mailto'],\n validate: (href: string) => /^(https?:\\/\\/|mailto:)/i.test(href),\n HTMLAttributes: {\n rel: 'noopener noreferrer',\n target: '_blank',\n },\n },\n }),\n Highlight.configure({ multicolor: false }),\n ListKit.configure({\n bulletList: false,\n orderedList: false,\n listItem: false,\n listKeymap: false,\n taskList: {},\n taskItem: { nested: true },\n }),\n TextAlign.configure({ types: ['heading', 'paragraph'] }),\n Image.configure({\n allowBase64: true,\n HTMLAttributes: {\n class: 'max-w-full rounded-control',\n },\n }),\n FileAttachment,\n Mention.configure({\n HTMLAttributes: { class: 'mention' },\n }),\n Markdown,\n ],\n content,\n contentType: format === 'markdown' ? 'markdown' : undefined,\n editable: false,\n editorProps: {\n attributes: {\n class: cn(...PROSE_CLASSES),\n },\n },\n })\n\n if (!editor) return null\n\n return (\n <div ref={ref} {...props} className={className}>\n <EditorContent editor={editor} />\n </div>\n )\n},\n)\n\nRichTextViewer.displayName = 'RichTextViewer'\n\nexport {\n RichTextEditor,\n RichTextEditorProvider,\n RichTextEditorToolbarSlot as RichTextEditorToolbar,\n RichTextEditorContentSlot as RichTextEditorContent,\n RichTextEditorSourceToggleSlot as RichTextEditorSourceToggle,\n useRichTextEditor,\n RichTextViewer,\n}\n"],"mappings":"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"}
@@ -60,7 +60,12 @@
60
60
  --neutral-6: oklch(0.78 0.0053 350);
61
61
  --neutral-7: oklch(0.7 0.0074 350);
62
62
  --neutral-8: oklch(0.62 0.0089 350);
63
- --neutral-9: oklch(0.55 0.01 350);
63
+ /* 0.55 0.54: at 0.55 this measured 4.472:1 on --neutral-2 (the light
64
+ surface-base), just under WCAG AA's 4.5 for normal text. 0.54 gives
65
+ 4.664:1. The intermediate 0.545 also clears at 4.567, but with only
66
+ 0.067 of headroom — a later tweak to surface-base would silently push it
67
+ back under, which is how the previous attempt at this fix landed short. */
68
+ --neutral-9: oklch(0.54 0.01 350);
64
69
  --neutral-10: oklch(0.5 0.01 350);
65
70
  --neutral-11: oklch(0.43 0.0074 350);
66
71
  --neutral-12: oklch(0.32 0.0042 350);
@@ -180,7 +180,7 @@
180
180
  --color-surface-fg-disabled: var(--neutral-8);
181
181
  --color-surface-fg: var(--neutral-12);
182
182
  --color-surface-fg-muted: var(--neutral-11);
183
- --color-surface-fg-subtle: var(--neutral-9); /* darkened for WCAG AA 4.5:1 */
183
+ --color-surface-fg-subtle: var(--neutral-9); /* 4.664:1 on surface-base — WCAG AA (verify, don't assume: see neutral-9) */
184
184
  --color-surface-border: var(--neutral-6); /* bumped for WCAG 1.4.11 (interactive/control edge) */
185
185
  --color-surface-border-strong: var(--neutral-7);
186
186
  --color-surface-border-subtle: var(--neutral-5);
package/dist/ui/alert.js CHANGED
@@ -1,14 +1,14 @@
1
1
  "use client";
2
2
  import { motionProps as e, springs as t } from "./lib/motion.js";
3
- import { cva as n } from "../_chunks/vendor-utils.js";
4
- import { cn as r } from "./lib/utils.js";
5
- import { Icon as i } from "./icon.js";
6
- import * as a from "react";
7
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
8
- import { IconAlertCircle as c, IconAlertTriangle as l, IconCircleCheck as u, IconInfoCircle as d, IconX as f } from "@tabler/icons-react";
9
- import { AnimatePresence as p, motion as m } from "framer-motion";
3
+ import { cn as n } from "./lib/utils.js";
4
+ import { Icon as r } from "./icon.js";
5
+ import * as i from "react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ import { IconAlertCircle as s, IconAlertTriangle as c, IconCircleCheck as l, IconInfoCircle as u, IconX as d } from "@tabler/icons-react";
8
+ import { AnimatePresence as f, motion as p } from "framer-motion";
9
+ import { cva as m } from "class-variance-authority";
10
10
  //#region src/ui/alert.tsx
11
- var h = n("relative flex rounded-surface border", {
11
+ var h = m("relative flex rounded-surface border", {
12
12
  variants: {
13
13
  variant: {
14
14
  subtle: "",
@@ -111,18 +111,18 @@ var h = n("relative flex rounded-surface border", {
111
111
  size: "md"
112
112
  }
113
113
  }), g = {
114
- info: d,
115
- success: u,
116
- warning: l,
117
- error: c,
118
- neutral: d
119
- }, _ = a.forwardRef(({ className: n, variant: c = "subtle", color: l = "info", size: u = "md", title: d, onDismiss: _, children: v, ...y }, b) => {
120
- let x = g[l ?? "info"], [S, C] = a.useState(!0), w = a.useCallback(() => {
114
+ info: u,
115
+ success: l,
116
+ warning: c,
117
+ error: s,
118
+ neutral: u
119
+ }, _ = i.forwardRef(({ className: s, variant: c = "subtle", color: l = "info", size: u = "md", title: m, onDismiss: _, children: v, ...y }, b) => {
120
+ let x = g[l ?? "info"], [S, C] = i.useState(!0), w = i.useCallback(() => {
121
121
  C(!1);
122
122
  }, []), T = u === "sm" ? "sm" : u === "lg" ? "lg" : "md", E = u === "sm" ? "xs" : "sm", D = u === "sm" ? "text-body-xs" : "text-body-md", O = u === "sm" ? "text-body-sm" : u === "lg" ? "text-heading-xs" : "text-body-md";
123
- return /* @__PURE__ */ o(p, {
123
+ return /* @__PURE__ */ a(f, {
124
124
  onExitComplete: _,
125
- children: S && /* @__PURE__ */ s(m.div, {
125
+ children: S && /* @__PURE__ */ o(p.div, {
126
126
  ref: b,
127
127
  initial: {
128
128
  opacity: 1,
@@ -137,36 +137,36 @@ var h = n("relative flex rounded-surface border", {
137
137
  y: -8
138
138
  },
139
139
  transition: t.snappy,
140
- className: r(h({
140
+ className: n(h({
141
141
  variant: c,
142
142
  color: l,
143
143
  size: u
144
- }), n),
144
+ }), s),
145
145
  role: "alert",
146
146
  ...e(y),
147
147
  children: [
148
- /* @__PURE__ */ o(i, {
148
+ /* @__PURE__ */ a(r, {
149
149
  icon: x,
150
150
  size: T,
151
151
  className: "mt-ds-01 shrink-0"
152
152
  }),
153
- /* @__PURE__ */ s("div", {
153
+ /* @__PURE__ */ o("div", {
154
154
  className: "flex-1 min-w-0",
155
- children: [d && /* @__PURE__ */ o("p", {
156
- className: r(O, "font-semibold mb-ds-01"),
157
- children: d
158
- }), /* @__PURE__ */ o("div", {
159
- className: r(D, c !== "solid" && "text-surface-fg-muted"),
155
+ children: [m && /* @__PURE__ */ a("p", {
156
+ className: n(O, "font-semibold mb-ds-01"),
157
+ children: m
158
+ }), /* @__PURE__ */ a("div", {
159
+ className: n(D, c !== "solid" && "text-surface-fg-muted"),
160
160
  children: v
161
161
  })]
162
162
  }),
163
- _ && /* @__PURE__ */ o("button", {
163
+ _ && /* @__PURE__ */ a("button", {
164
164
  type: "button",
165
165
  onClick: w,
166
166
  className: "shrink-0 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-control-inner text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:text-surface-fg-muted hover:bg-surface-raised-hover active:scale-95 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9",
167
167
  "aria-label": "Dismiss",
168
- children: /* @__PURE__ */ o(i, {
169
- icon: f,
168
+ children: /* @__PURE__ */ a(r, {
169
+ icon: d,
170
170
  size: E
171
171
  })
172
172
  })
package/dist/ui/avatar.js CHANGED
@@ -1,15 +1,15 @@
1
1
  "use client";
2
2
  import { springs as e } from "./lib/motion.js";
3
- import { cva as t } from "../_chunks/vendor-utils.js";
4
- import { cn as n } from "./lib/utils.js";
5
- import { Fallback as r, Image as i, Root as a } from "../_chunks/primitives/react-avatar.js";
6
- import { Dot as o } from "./dot.js";
7
- import { Skeleton as s } from "./skeleton.js";
8
- import * as c from "react";
9
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
10
- import { motion as d } from "framer-motion";
3
+ import { cn as t } from "./lib/utils.js";
4
+ import { Fallback as n, Image as r, Root as i } from "../_chunks/primitives/react-avatar.js";
5
+ import { Dot as a } from "./dot.js";
6
+ import { Skeleton as o } from "./skeleton.js";
7
+ import * as s from "react";
8
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
9
+ import { motion as u } from "framer-motion";
10
+ import { cva as d } from "class-variance-authority";
11
11
  //#region src/ui/avatar.tsx
12
- var f = c.createContext("circle"), p = c.createContext("md"), m = t("relative flex shrink-0 overflow-hidden", {
12
+ var f = s.createContext("circle"), p = s.createContext("md"), m = d("relative flex shrink-0 overflow-hidden", {
13
13
  variants: {
14
14
  size: {
15
15
  xs: "h-ds-xs w-ds-xs",
@@ -97,52 +97,52 @@ function S(e) {
97
97
  for (let n = 0; n < e.length; n++) t = (t << 5) + t + e.charCodeAt(n) | 0;
98
98
  return x[Math.abs(t) % x.length];
99
99
  }
100
- var C = c.forwardRef(({ className: t, size: r, shape: i, status: c, ring: b, badge: x, loading: S, children: C, ...w }, T) => {
101
- let E = i ?? "circle", D = b && b !== "none" ? n("ring-2 ring-offset-2 ring-offset-surface-raised", v[b], y[E]) : void 0;
102
- if (S) return /* @__PURE__ */ l("span", {
100
+ var C = s.forwardRef(({ className: n, size: r, shape: s, status: d, ring: b, badge: x, loading: S, children: C, ...w }, T) => {
101
+ let E = s ?? "circle", D = b && b !== "none" ? t("ring-2 ring-offset-2 ring-offset-surface-raised", v[b], y[E]) : void 0;
102
+ if (S) return /* @__PURE__ */ c("span", {
103
103
  ref: T,
104
- className: n("relative inline-flex shrink-0", D),
105
- children: /* @__PURE__ */ l(s, {
106
- className: n(m({
104
+ className: t("relative inline-flex shrink-0", D),
105
+ children: /* @__PURE__ */ c(o, {
106
+ className: t(m({
107
107
  size: r,
108
- shape: i
108
+ shape: s
109
109
  })),
110
110
  "data-slot": "avatar-skeleton"
111
111
  })
112
112
  });
113
113
  let O = x !== void 0 && x !== 0;
114
- return /* @__PURE__ */ l(f.Provider, {
114
+ return /* @__PURE__ */ c(f.Provider, {
115
115
  value: E,
116
- children: /* @__PURE__ */ l(p.Provider, {
116
+ children: /* @__PURE__ */ c(p.Provider, {
117
117
  value: r ?? "md",
118
- children: /* @__PURE__ */ u("span", {
119
- className: n("relative inline-flex shrink-0", D),
118
+ children: /* @__PURE__ */ l("span", {
119
+ className: t("relative inline-flex shrink-0", D),
120
120
  children: [
121
- /* @__PURE__ */ l(a, {
121
+ /* @__PURE__ */ c(i, {
122
122
  ref: T,
123
- className: n(m({
123
+ className: t(m({
124
124
  size: r,
125
- shape: i
126
- }), t),
125
+ shape: s
126
+ }), n),
127
127
  ...w,
128
128
  children: C
129
129
  }),
130
- c && /* @__PURE__ */ l("span", {
130
+ d && /* @__PURE__ */ c("span", {
131
131
  className: "absolute bottom-0 right-0",
132
132
  role: "img",
133
- "aria-label": g[c],
134
- children: /* @__PURE__ */ l(o, {
135
- color: h[c],
133
+ "aria-label": g[d],
134
+ children: /* @__PURE__ */ c(a, {
135
+ color: h[d],
136
136
  size: _[r ?? "md"],
137
137
  withBorder: !0,
138
138
  "aria-hidden": !0
139
139
  })
140
140
  }),
141
- O && (x === "dot" ? /* @__PURE__ */ l("span", {
141
+ O && (x === "dot" ? /* @__PURE__ */ c("span", {
142
142
  className: "absolute -right-0.5 -top-0.5 h-ds-03 w-ds-03 rounded-pill bg-error-9 ring-2 ring-surface-raised",
143
143
  "data-slot": "avatar-badge-dot",
144
144
  "aria-hidden": "true"
145
- }) : typeof x == "number" ? /* @__PURE__ */ l(d.span, {
145
+ }) : typeof x == "number" ? /* @__PURE__ */ c(u.span, {
146
146
  initial: { scale: 0 },
147
147
  animate: { scale: 1 },
148
148
  transition: e.smooth,
@@ -151,7 +151,7 @@ var C = c.forwardRef(({ className: t, size: r, shape: i, status: c, ring: b, bad
151
151
  role: "status",
152
152
  "aria-label": `${x > 99 ? "99+" : x} notifications`,
153
153
  children: x > 99 ? "99+" : x
154
- }) : /* @__PURE__ */ l("span", {
154
+ }) : /* @__PURE__ */ c("span", {
155
155
  className: "absolute -right-1 -top-1",
156
156
  "data-slot": "avatar-badge-custom",
157
157
  children: x
@@ -161,8 +161,8 @@ var C = c.forwardRef(({ className: t, size: r, shape: i, status: c, ring: b, bad
161
161
  })
162
162
  });
163
163
  });
164
- C.displayName = a.displayName;
165
- var w = c.forwardRef(({ className: t, ...r }, a) => /* @__PURE__ */ l(d.span, {
164
+ C.displayName = i.displayName;
165
+ var w = s.forwardRef(({ className: n, ...i }, a) => /* @__PURE__ */ c(u.span, {
166
166
  initial: { scale: .96 },
167
167
  animate: {
168
168
  opacity: 1,
@@ -170,23 +170,23 @@ var w = c.forwardRef(({ className: t, ...r }, a) => /* @__PURE__ */ l(d.span, {
170
170
  },
171
171
  transition: e.smooth,
172
172
  className: "absolute inset-0 h-full w-full",
173
- children: /* @__PURE__ */ l(i, {
173
+ children: /* @__PURE__ */ c(r, {
174
174
  ref: a,
175
- className: n("aspect-square h-full w-full", t),
176
- ...r
175
+ className: t("aspect-square h-full w-full", n),
176
+ ...i
177
177
  })
178
178
  }));
179
- w.displayName = i.displayName;
180
- var T = c.forwardRef(({ className: e, colorSeed: t, children: i, ...a }, o) => {
181
- let s = typeof i == "string" ? i : "", u = S(t ?? s), d = c.useContext(f), m = c.useContext(p), h = d === "square" ? "rounded-none" : d === "rounded" ? "rounded-control" : "rounded-pill", g = s.length === 1 ? "tracking-wide" : "tracking-normal";
182
- return /* @__PURE__ */ l(r, {
179
+ w.displayName = r.displayName;
180
+ var T = s.forwardRef(({ className: e, colorSeed: r, children: i, ...a }, o) => {
181
+ let l = typeof i == "string" ? i : "", u = S(r ?? l), d = s.useContext(f), m = s.useContext(p), h = d === "square" ? "rounded-none" : d === "rounded" ? "rounded-control" : "rounded-pill", g = l.length === 1 ? "tracking-wide" : "tracking-normal";
182
+ return /* @__PURE__ */ c(n, {
183
183
  ref: o,
184
184
  "data-slot": "avatar-fallback",
185
- className: n("flex h-full w-full items-center justify-center font-semibold", h, b[m], u.bg, u.text, g, e),
185
+ className: t("flex h-full w-full items-center justify-center font-semibold", h, b[m], u.bg, u.text, g, e),
186
186
  ...a,
187
187
  children: i
188
188
  });
189
189
  });
190
- T.displayName = r.displayName;
190
+ T.displayName = n.displayName;
191
191
  //#endregion
192
192
  export { C as Avatar, T as AvatarFallback, w as AvatarImage, m as avatarVariants };