@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.
- package/BREAKING.json +13 -0
- package/MIGRATION.md +56 -0
- package/README.md +16 -1
- package/dist/_chunks/badge-group.js +45 -45
- package/dist/_chunks/emoji-suggestion.js +32 -30
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +35 -34
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/primitives-internal.js +437 -537
- package/dist/_chunks/primitives-internal.js.map +1 -1
- package/dist/composed/content-card.js +18 -18
- package/dist/composed/extensions/emoji-node.js +8 -7
- package/dist/composed/extensions/emoji-node.js.map +1 -1
- package/dist/composed/rich-chat-input.js +535 -526
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +201 -193
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/tokens/primitives.css +6 -1
- package/dist/tokens/semantic.css +1 -1
- package/dist/ui/alert.js +29 -29
- package/dist/ui/avatar.js +42 -42
- package/dist/ui/banner.js +25 -25
- package/dist/ui/button.js +31 -31
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.js +39 -39
- package/dist/ui/checkbox.d.ts.map +1 -1
- package/dist/ui/checkbox.js +1 -0
- package/dist/ui/checkbox.js.map +1 -1
- package/dist/ui/combobox.js +135 -135
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/dot.js +13 -13
- package/dist/ui/input.js +25 -25
- package/dist/ui/lib/utils.js +2 -1
- package/dist/ui/lib/utils.js.map +1 -1
- package/dist/ui/number-input.js +36 -36
- package/dist/ui/progress.js +55 -55
- package/dist/ui/select.js +58 -58
- package/dist/ui/sheet.js +46 -46
- package/dist/ui/sidebar.js +128 -128
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/skeleton.js +39 -39
- package/dist/ui/slider.d.ts.map +1 -1
- package/dist/ui/slider.js +18 -17
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/surface.js +9 -9
- package/dist/ui/switch.d.ts.map +1 -1
- package/dist/ui/switch.js +1 -0
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/tabs.js +47 -47
- package/dist/ui/text.js +8 -8
- package/dist/ui/textarea.js +12 -12
- package/dist/ui/toggle.js +12 -12
- package/docs/recipes/install-astro.md +2 -2
- package/docs/recipes/install-next-app-router.md +2 -2
- package/docs/recipes/install-remix.md +2 -2
- package/docs/recipes/install-tanstack-start.md +2 -2
- package/docs/recipes/install-vite.md +2 -2
- package/docs/recipes/troubleshoot.md +26 -5
- package/llms.txt +1 -1
- package/mcp-manifest.json +24 -3
- package/package.json +39 -11
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +1 -1
- package/skill/references/setup-astro.md +2 -2
- package/skill/references/setup-next-app-router.md +2 -2
- package/skill/references/setup-remix.md +2 -2
- package/skill/references/setup-tanstack-start.md +2 -2
- package/skill/references/setup-vite.md +2 -2
- package/skill/references/troubleshoot.md +26 -5
- package/dist/_chunks/tiptap.js +0 -18809
- package/dist/_chunks/tiptap.js.map +0 -1
- package/dist/_chunks/vendor-utils.js +0 -1766
- package/dist/_chunks/vendor-utils.js.map +0 -1
- 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
|
-
|
|
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);
|
package/dist/tokens/semantic.css
CHANGED
|
@@ -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); /*
|
|
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 {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
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 =
|
|
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:
|
|
115
|
-
success:
|
|
116
|
-
warning:
|
|
117
|
-
error:
|
|
118
|
-
neutral:
|
|
119
|
-
}, _ =
|
|
120
|
-
let x = g[l ?? "info"], [S, C] =
|
|
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__ */
|
|
123
|
+
return /* @__PURE__ */ a(f, {
|
|
124
124
|
onExitComplete: _,
|
|
125
|
-
children: S && /* @__PURE__ */
|
|
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:
|
|
140
|
+
className: n(h({
|
|
141
141
|
variant: c,
|
|
142
142
|
color: l,
|
|
143
143
|
size: u
|
|
144
|
-
}),
|
|
144
|
+
}), s),
|
|
145
145
|
role: "alert",
|
|
146
146
|
...e(y),
|
|
147
147
|
children: [
|
|
148
|
-
/* @__PURE__ */
|
|
148
|
+
/* @__PURE__ */ a(r, {
|
|
149
149
|
icon: x,
|
|
150
150
|
size: T,
|
|
151
151
|
className: "mt-ds-01 shrink-0"
|
|
152
152
|
}),
|
|
153
|
-
/* @__PURE__ */
|
|
153
|
+
/* @__PURE__ */ o("div", {
|
|
154
154
|
className: "flex-1 min-w-0",
|
|
155
|
-
children: [
|
|
156
|
-
className:
|
|
157
|
-
children:
|
|
158
|
-
}), /* @__PURE__ */
|
|
159
|
-
className:
|
|
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__ */
|
|
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__ */
|
|
169
|
-
icon:
|
|
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 {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
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 =
|
|
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 =
|
|
101
|
-
let E =
|
|
102
|
-
if (S) return /* @__PURE__ */
|
|
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:
|
|
105
|
-
children: /* @__PURE__ */
|
|
106
|
-
className:
|
|
104
|
+
className: t("relative inline-flex shrink-0", D),
|
|
105
|
+
children: /* @__PURE__ */ c(o, {
|
|
106
|
+
className: t(m({
|
|
107
107
|
size: r,
|
|
108
|
-
shape:
|
|
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__ */
|
|
114
|
+
return /* @__PURE__ */ c(f.Provider, {
|
|
115
115
|
value: E,
|
|
116
|
-
children: /* @__PURE__ */
|
|
116
|
+
children: /* @__PURE__ */ c(p.Provider, {
|
|
117
117
|
value: r ?? "md",
|
|
118
|
-
children: /* @__PURE__ */
|
|
119
|
-
className:
|
|
118
|
+
children: /* @__PURE__ */ l("span", {
|
|
119
|
+
className: t("relative inline-flex shrink-0", D),
|
|
120
120
|
children: [
|
|
121
|
-
/* @__PURE__ */
|
|
121
|
+
/* @__PURE__ */ c(i, {
|
|
122
122
|
ref: T,
|
|
123
|
-
className:
|
|
123
|
+
className: t(m({
|
|
124
124
|
size: r,
|
|
125
|
-
shape:
|
|
126
|
-
}),
|
|
125
|
+
shape: s
|
|
126
|
+
}), n),
|
|
127
127
|
...w,
|
|
128
128
|
children: C
|
|
129
129
|
}),
|
|
130
|
-
|
|
130
|
+
d && /* @__PURE__ */ c("span", {
|
|
131
131
|
className: "absolute bottom-0 right-0",
|
|
132
132
|
role: "img",
|
|
133
|
-
"aria-label": g[
|
|
134
|
-
children: /* @__PURE__ */
|
|
135
|
-
color: h[
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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 =
|
|
165
|
-
var w =
|
|
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__ */
|
|
173
|
+
children: /* @__PURE__ */ c(r, {
|
|
174
174
|
ref: a,
|
|
175
|
-
className:
|
|
176
|
-
...
|
|
175
|
+
className: t("aspect-square h-full w-full", n),
|
|
176
|
+
...i
|
|
177
177
|
})
|
|
178
178
|
}));
|
|
179
|
-
w.displayName =
|
|
180
|
-
var T =
|
|
181
|
-
let
|
|
182
|
-
return /* @__PURE__ */
|
|
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:
|
|
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 =
|
|
190
|
+
T.displayName = n.displayName;
|
|
191
191
|
//#endregion
|
|
192
192
|
export { C as Avatar, T as AvatarFallback, w as AvatarImage, m as avatarVariants };
|