@keboola/design 13.0.1 → 13.1.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 (39) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +31 -0
  3. package/README.md +2 -2
  4. package/dist/{AIKit-VB7CXeQk.js → AIKit-BVCWP9Ks.js} +261 -69
  5. package/dist/AIKit-BVCWP9Ks.js.map +1 -0
  6. package/dist/{CodeEditor-jZMw1ioj.js → CodeEditor-Df7VVx08.js} +2 -2
  7. package/dist/{CodeEditor-jZMw1ioj.js.map → CodeEditor-Df7VVx08.js.map} +1 -1
  8. package/dist/{ColorModeSwitch-BBzn1D0u.js → ColorModeSwitch-D8Cki137.js} +2 -2
  9. package/dist/{ColorModeSwitch-BBzn1D0u.js.map → ColorModeSwitch-D8Cki137.js.map} +1 -1
  10. package/dist/{DropdownMenu-C5FLPkvR.js → DropdownMenu-BJGLjpVc.js} +3 -3
  11. package/dist/{DropdownMenu-C5FLPkvR.js.map → DropdownMenu-BJGLjpVc.js.map} +1 -1
  12. package/dist/{SectionNav-BTBiitiQ.js → SectionNav-I2p2uXTd.js} +2 -2
  13. package/dist/{SectionNav-BTBiitiQ.js.map → SectionNav-I2p2uXTd.js.map} +1 -1
  14. package/dist/{Sidebar-BTv636Cq.js → Sidebar-D9ytIs8V.js} +2 -2
  15. package/dist/{Sidebar-BTv636Cq.js.map → Sidebar-D9ytIs8V.js.map} +1 -1
  16. package/dist/Toast-NrOdDDru.js +76 -0
  17. package/dist/Toast-NrOdDDru.js.map +1 -0
  18. package/dist/editors.js +1 -1
  19. package/dist/index.d.ts +46 -12
  20. package/dist/index.js +9 -8
  21. package/dist/internal/blocks/AIKit.js +1 -1
  22. package/dist/internal/blocks/ColorModeSwitch.js +1 -1
  23. package/dist/internal/blocks/ExportMenu.js +1 -1
  24. package/dist/internal/blocks/SectionNav.js +1 -1
  25. package/dist/internal/blocks/SplitButton.js +1 -1
  26. package/dist/internal/components/DropdownMenu.js +1 -1
  27. package/dist/internal/components/Sidebar.js +1 -1
  28. package/dist/internal/components/Toast.js +1 -1
  29. package/dist/internal/hooks/useAltDigitHotkey.js +51 -0
  30. package/dist/internal/hooks/useAltDigitHotkey.js.map +1 -0
  31. package/dist/markdown-editor.d.ts +22 -1
  32. package/dist/markdown-editor.js +443 -201
  33. package/dist/markdown-editor.js.map +1 -1
  34. package/dist/rjsf.js +1 -1
  35. package/dist/styles.css +1 -1
  36. package/package.json +1 -1
  37. package/dist/AIKit-VB7CXeQk.js.map +0 -1
  38. package/dist/Toast-PfQf3vj-.js +0 -49
  39. package/dist/Toast-PfQf3vj-.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-editor.js","names":["ListIcon","LinkIcon","ListIcon"],"sources":["../src/blocks/MarkdownEditor/context.ts","../src/blocks/MarkdownEditor/nodes/ImageNodeComponent.tsx","../src/blocks/MarkdownEditor/nodes/ImageNode.tsx","../src/blocks/MarkdownEditor/nodes/MermaidNodeComponent.tsx","../src/blocks/MarkdownEditor/nodes/MermaidNode.tsx","../src/blocks/MarkdownEditor/plugins/ImagePastePlugin.tsx","../src/blocks/MarkdownEditor/plugins/KeyboardPlugin.tsx","../src/blocks/MarkdownEditor/transformers.ts","../src/blocks/MarkdownEditor/plugins/MarkdownSyncPlugin.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/AlignmentDropdown.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/BlockTypeDropdown.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/ToolbarButton.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/LinkPanel.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/ToolbarDivider.tsx","../src/blocks/MarkdownEditor/plugins/ToolbarPlugin.tsx","../src/blocks/MarkdownEditor/theme.ts","../src/blocks/MarkdownEditor/MarkdownEditor.tsx"],"sourcesContent":["import { createContext, use } from 'react';\nimport type { ReactNode } from 'react';\n\ntype ImageRenderer = (props: { src: string; alt: string }) => ReactNode;\n\nconst ImageRendererContext = createContext<ImageRenderer | null>(null);\n\nexport const ImageRendererProvider = ImageRendererContext;\n\nexport const useImageRenderer = (): ImageRenderer | null => use(ImageRendererContext);\n","import { useImageRenderer } from '../context';\n\nconst isPlaceholder = (src: string) => src.startsWith('upload-placeholder-');\n\nexport const ImageNodeComponent = ({ src, alt }: { src: string; alt: string }) => {\n const renderer = useImageRenderer();\n\n if (isPlaceholder(src)) {\n return (\n <span className=\"tw:inline-flex tw:items-center tw:gap-1 tw:rounded tw:bg-neutral-100 tw:px-2 tw:py-1 tw:text-xs tw:text-neutral-400\">\n Uploading image…\n </span>\n );\n }\n\n if (renderer) return <>{renderer({ src, alt })}</>;\n return <img src={src} alt={alt} />;\n};\n","/* eslint-disable react/only-export-components -- Lexical convention: $create/$is helpers co-locate with node */\nimport type { ReactNode } from 'react';\nimport type {\n DOMConversionMap,\n DOMExportOutput,\n EditorConfig,\n LexicalNode,\n NodeKey,\n SerializedLexicalNode,\n Spread,\n} from 'lexical';\nimport { DecoratorNode } from 'lexical';\n\nimport { ImageNodeComponent } from './ImageNodeComponent';\n\ntype SerializedImageNode = Spread<{ src: string; altText: string }, SerializedLexicalNode>;\n\nexport class ImageNode extends DecoratorNode<ReactNode> {\n __src: string;\n __altText: string;\n\n static override getType(): string {\n return 'image';\n }\n\n static override clone(node: ImageNode): ImageNode {\n return new ImageNode(node.__src, node.__altText, node.__key);\n }\n\n constructor(src: string, altText: string, key?: NodeKey) {\n super(key);\n this.__src = src;\n this.__altText = altText;\n }\n\n getSrc(): string {\n return this.__src;\n }\n\n getAlt(): string {\n return this.__altText;\n }\n\n setSrc(src: string): void {\n const writable = this.getWritable();\n writable.__src = src;\n }\n\n setAlt(altText: string): void {\n const writable = this.getWritable();\n writable.__altText = altText;\n }\n\n override createDOM(config: EditorConfig): HTMLElement {\n const span = document.createElement('span');\n const className = config.theme.image;\n if (typeof className === 'string') {\n span.className = className;\n }\n return span;\n }\n\n override updateDOM(): boolean {\n return false;\n }\n\n override decorate(): ReactNode {\n return <ImageNodeComponent src={this.__src} alt={this.__altText} />;\n }\n\n override isInline(): boolean {\n return true;\n }\n\n static override importJSON(serializedNode: SerializedImageNode): ImageNode {\n return $createImageNode(serializedNode.src, serializedNode.altText);\n }\n\n override exportJSON(): SerializedImageNode {\n return {\n type: 'image',\n version: 1,\n src: this.__src,\n altText: this.__altText,\n };\n }\n\n override exportDOM(): DOMExportOutput {\n const element = document.createElement('img');\n element.setAttribute('src', this.__src);\n element.setAttribute('alt', this.__altText);\n return { element };\n }\n\n static override importDOM(): DOMConversionMap | null {\n return {\n img: () => ({\n conversion: (domNode: HTMLElement) => {\n const src = domNode.getAttribute('src') || '';\n const alt = domNode.getAttribute('alt') || '';\n return { node: $createImageNode(src, alt) };\n },\n priority: 0,\n }),\n };\n }\n}\n\nexport const $createImageNode = (src: string, altText: string): ImageNode => {\n return new ImageNode(src, altText);\n};\n\nexport const $isImageNode = (node: LexicalNode | null | undefined): node is ImageNode => {\n return node instanceof ImageNode;\n};\n","import { lazy, Suspense } from 'react';\n\nimport { Skeleton } from '../../../components/Skeleton/Skeleton';\n\nconst MermaidDiagram = lazy(() =>\n import('../../../blocks/MermaidDiagram/MermaidDiagram').then(\n (m) => ({ default: m.MermaidDiagram }),\n (error: unknown) => {\n // Falling back to raw code on chunk-load failure (typically a stale tab after deploy).\n // Logging so we don't silently swap implementations.\n console.error('[MarkdownEditor] failed to load MermaidDiagram chunk', error);\n return {\n default: ({ code }: { code: string }) => (\n <pre>\n <code>{code}</code>\n </pre>\n ),\n };\n },\n ),\n);\n\nexport const MermaidNodeComponent = ({ code }: { code: string }) => {\n return (\n <Suspense\n fallback={\n <div className=\"tw:my-3 tw:overflow-hidden tw:rounded-card tw:border tw:border-neutral-150 tw:bg-neutral-50 tw:p-6\">\n <Skeleton className=\"tw:h-40\" />\n </div>\n }\n >\n <MermaidDiagram code={code} />\n </Suspense>\n );\n};\n","/* eslint-disable react/only-export-components -- Lexical convention: $create/$is helpers co-locate with node */\nimport type { ReactNode } from 'react';\nimport type { LexicalNode, NodeKey, SerializedLexicalNode, Spread } from 'lexical';\nimport { DecoratorNode } from 'lexical';\n\nimport { MermaidNodeComponent } from './MermaidNodeComponent';\n\ntype SerializedMermaidNode = Spread<{ code: string }, SerializedLexicalNode>;\n\nexport class MermaidNode extends DecoratorNode<ReactNode> {\n __code: string;\n\n static override getType(): string {\n return 'mermaid';\n }\n\n static override clone(node: MermaidNode): MermaidNode {\n return new MermaidNode(node.__code, node.__key);\n }\n\n constructor(code: string, key?: NodeKey) {\n super(key);\n this.__code = code;\n }\n\n getCode(): string {\n return this.__code;\n }\n\n setCode(code: string): void {\n const writable = this.getWritable();\n writable.__code = code;\n }\n\n override createDOM(): HTMLElement {\n const div = document.createElement('div');\n div.setAttribute('data-lexical-mermaid', 'true');\n return div;\n }\n\n override updateDOM(): boolean {\n return false;\n }\n\n override decorate(): ReactNode {\n return <MermaidNodeComponent code={this.__code} />;\n }\n\n override isInline(): boolean {\n return false;\n }\n\n static override importJSON(serializedNode: SerializedMermaidNode): MermaidNode {\n return $createMermaidNode(serializedNode.code);\n }\n\n override exportJSON(): SerializedMermaidNode {\n return {\n type: 'mermaid',\n version: 1,\n code: this.__code,\n };\n }\n}\n\nexport const $createMermaidNode = (code: string): MermaidNode => {\n return new MermaidNode(code);\n};\n\nexport const $isMermaidNode = (node: LexicalNode | null | undefined): node is MermaidNode => {\n return node instanceof MermaidNode;\n};\n","import { useEffect } from 'react';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport type { NodeKey } from 'lexical';\nimport {\n $getNodeByKey,\n $insertNodes,\n COMMAND_PRIORITY_CRITICAL,\n DROP_COMMAND,\n PASTE_COMMAND,\n} from 'lexical';\n\nimport { toast } from '../../../components/Toast/toast';\nimport { useStableCallback } from '../../../hooks/useStableCallback';\nimport { $createImageNode, $isImageNode } from '../nodes/ImageNode';\n\nconst ACCEPTED_IMAGE_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n];\n\nconst MAX_IMAGE_SIZE = 10 * 1024 * 1024; // 10 MB\n\nconst PLACEHOLDER_PREFIX = 'upload-placeholder-';\n\nconst generatePlaceholderId = (): string => {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n};\n\nconst isAcceptedImageType = (type: string) => ACCEPTED_IMAGE_TYPES.includes(type);\n\nconst getImageFilesFromDataTransfer = (dataTransfer: DataTransfer | null): File[] => {\n if (!dataTransfer) return [];\n\n if (dataTransfer.items.length > 0) {\n const files: File[] = [];\n for (const item of dataTransfer.items) {\n if (item.kind === 'file' && isAcceptedImageType(item.type)) {\n const file = item.getAsFile();\n if (file) files.push(file);\n }\n }\n if (files.length > 0) return files;\n }\n\n return Array.from(dataTransfer.files).filter((file) => isAcceptedImageType(file.type));\n};\n\nconst escapeMarkdownAlt = (text: string) => text.replace(/[[\\]()]/g, '');\n\ntype ImagePastePluginProps = {\n onImageUpload?: (file: File) => Promise<{ url: string }>;\n};\n\nexport const ImagePastePlugin = ({ onImageUpload }: ImagePastePluginProps) => {\n const [editor] = useLexicalComposerContext();\n // Whether an uploader is configured at all — the commands below must decline\n // paste and drop when it isn't, so Lexical falls back to its default handling.\n // A boolean, so it only changes identity when the prop appears or disappears.\n const canUploadImages = onImageUpload != null;\n const uploadImage = useStableCallback((file: File) => onImageUpload?.(file));\n\n useEffect(() => {\n const uploadFile = (file: File) => {\n if (!canUploadImages) return;\n\n if (file.size > MAX_IMAGE_SIZE) {\n toast.error(`Image \"${file.name}\" is too large. Maximum size is 10 MB.`);\n return;\n }\n\n // Insert placeholder and start upload outside the command handler\n // to avoid nested editor.update() batching issues\n let nodeKey: NodeKey | null = null;\n\n editor.update(() => {\n const placeholderNode = $createImageNode(\n `${PLACEHOLDER_PREFIX}${generatePlaceholderId()}`,\n 'Uploading image\\u2026',\n );\n $insertNodes([placeholderNode]);\n nodeKey = placeholderNode.getKey();\n });\n\n if (!nodeKey) return;\n const capturedKey: NodeKey = nodeKey;\n\n uploadImage(file)\n ?.then(({ url }) => {\n editor.update(() => {\n const node = $getNodeByKey(capturedKey);\n if ($isImageNode(node)) {\n const altText = escapeMarkdownAlt(file.name.replace(/\\.[^.]+$/, '') || 'image');\n node.setSrc(url);\n node.setAlt(altText);\n }\n });\n })\n .catch((error: unknown) => {\n console.error('[MarkdownEditor] image upload failed', error);\n toast.error(`Failed to upload \"${file.name}\". Please try again.`);\n editor.update(() => {\n const node = $getNodeByKey(capturedKey);\n if (node) node.remove();\n });\n });\n };\n\n const removePaste = editor.registerCommand(\n PASTE_COMMAND,\n (event) => {\n if (!canUploadImages) return false;\n if (!(event instanceof ClipboardEvent)) return false;\n const files = getImageFilesFromDataTransfer(event.clipboardData);\n if (files.length === 0) return false;\n\n event.preventDefault();\n // Defer upload to next microtask to escape the command handler's update context\n Promise.resolve().then(() => files.forEach(uploadFile));\n return true;\n },\n COMMAND_PRIORITY_CRITICAL,\n );\n\n const removeDrop = editor.registerCommand(\n DROP_COMMAND,\n (event: DragEvent) => {\n if (!canUploadImages) return false;\n const files = getImageFilesFromDataTransfer(event.dataTransfer);\n if (files.length === 0) return false;\n\n event.preventDefault();\n // Defer upload to next microtask to escape the command handler's update context\n Promise.resolve().then(() => files.forEach(uploadFile));\n return true;\n },\n COMMAND_PRIORITY_CRITICAL,\n );\n\n return () => {\n removePaste();\n removeDrop();\n };\n }, [editor, canUploadImages, uploadImage]);\n\n return null;\n};\n","import { useEffect, useRef } from 'react';\nimport type { RefObject } from 'react';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { COMMAND_PRIORITY_HIGH, KEY_DOWN_COMMAND } from 'lexical';\n\nimport { useStableCallback } from '../../../hooks/useStableCallback';\n\ntype KeyboardPluginProps = {\n /** Invoked on Cmd/Ctrl+Enter, without blurring. */\n onSave?: () => void;\n /** Escape in inline-edit mode. Callers reset `value` to the last-committed state here. */\n onCancel?: () => void;\n /** Plain Enter blurs the editor instead of breaking the paragraph; Shift+Enter still breaks. */\n singleLine?: boolean;\n /** Escape blurs the editor. Inline-edit only; elsewhere a stray Esc must keep focus. */\n blurOnEscape?: boolean;\n /**\n * Set before the Escape blur so the blur handler skips `onSave` on the reverted value.\n * The consumer resets it on read.\n */\n skipBlurSaveRef?: RefObject<boolean>;\n};\n\nexport const KeyboardPlugin = ({\n onSave,\n onCancel,\n singleLine,\n blurOnEscape,\n skipBlurSaveRef,\n}: KeyboardPluginProps) => {\n const [editor] = useLexicalComposerContext();\n const handleSave = useStableCallback(() => onSave?.());\n const handleCancel = useStableCallback(() => onCancel?.());\n const singleLineRef = useRef(singleLine);\n singleLineRef.current = singleLine;\n const blurOnEscapeRef = useRef(blurOnEscape);\n blurOnEscapeRef.current = blurOnEscape;\n const skipBlurSaveExternalRef = skipBlurSaveRef;\n\n useEffect(() => {\n return editor.registerCommand(\n KEY_DOWN_COMMAND,\n (event: KeyboardEvent) => {\n if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {\n event.preventDefault();\n handleSave();\n return true;\n }\n if (event.key === 'Enter' && !event.shiftKey && !event.altKey && singleLineRef.current) {\n event.preventDefault();\n editor.getRootElement()?.blur();\n return true;\n }\n if (event.key === 'Escape' && blurOnEscapeRef.current) {\n if (skipBlurSaveExternalRef) skipBlurSaveExternalRef.current = true;\n handleCancel();\n editor.getRootElement()?.blur();\n return true;\n }\n return false;\n },\n COMMAND_PRIORITY_HIGH,\n );\n }, [editor, skipBlurSaveExternalRef, handleSave, handleCancel]);\n\n return null;\n};\n","import type {\n ElementTransformer,\n MultilineElementTransformer,\n TextMatchTransformer,\n Transformer,\n} from '@lexical/markdown';\nimport { CHECK_LIST, TRANSFORMERS } from '@lexical/markdown';\nimport {\n $createHorizontalRuleNode,\n $isHorizontalRuleNode,\n HorizontalRuleNode,\n} from '@lexical/react/LexicalHorizontalRuleNode';\n\nimport { $createImageNode, $isImageNode, ImageNode } from './nodes/ImageNode';\nimport { $createMermaidNode, $isMermaidNode, MermaidNode } from './nodes/MermaidNode';\n\n/** Markdown image: `![alt](src)` */\nconst IMAGE: TextMatchTransformer = {\n dependencies: [ImageNode],\n export: (node) => {\n if (!$isImageNode(node)) return null;\n return `![${node.getAlt()}](${node.getSrc()})`;\n },\n importRegExp: /!\\[([^\\]]*)\\]\\(([^)]+)\\)/,\n regExp: /!\\[([^\\]]*)\\]\\(([^)]+)\\)$/,\n replace: (textNode, match) => {\n const [, alt = '', src = ''] = match;\n const imageNode = $createImageNode(src, alt);\n textNode.replace(imageNode);\n },\n trigger: ')',\n type: 'text-match',\n};\n\n/** Horizontal rule: `---`, `***`, or `___` */\nconst HORIZONTAL_RULE: ElementTransformer = {\n dependencies: [HorizontalRuleNode],\n export: (node) => {\n return $isHorizontalRuleNode(node) ? '---' : null;\n },\n regExp: /^(---|\\*\\*\\*|___)$/,\n replace: (parentNode) => {\n const node = $createHorizontalRuleNode();\n parentNode.replace(node);\n },\n type: 'element',\n};\n\n/** Fenced mermaid block: ` ```mermaid ... ``` ` → MermaidNode (rendered as diagram) */\nconst MERMAID: MultilineElementTransformer = {\n dependencies: [MermaidNode],\n export: (node) => {\n if (!$isMermaidNode(node)) return null;\n return '```mermaid\\n' + node.getCode() + '\\n```';\n },\n regExpStart: /^[ \\t]*(`{3,})mermaid(?:\\s.*)?$/,\n regExpEnd: {\n optional: true,\n regExp: /^[ \\t]*`{3,}$/,\n },\n replace: (rootNode, _children, _startMatch, _endMatch, linesInBetween) => {\n if (!linesInBetween) return;\n const code = linesInBetween.join('\\n').trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n },\n handleImportAfterStartMatch: ({\n lines,\n rootNode,\n startLineIndex,\n startMatch,\n }): [boolean, number] => {\n const fence = startMatch[1];\n if (!fence) return [false, startLineIndex];\n const fenceLength = fence.trim().length;\n const endRegex = new RegExp(`^[ \\\\t]*\\`{${fenceLength},}$`);\n\n for (let i = startLineIndex + 1; i < lines.length; i++) {\n if (endRegex.test(lines[i] ?? '')) {\n const code = lines\n .slice(startLineIndex + 1, i)\n .join('\\n')\n .trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n return [true, i];\n }\n }\n\n // No closing fence — consume remaining lines\n const code = lines\n .slice(startLineIndex + 1)\n .join('\\n')\n .trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n return [true, lines.length - 1];\n },\n type: 'multiline-element',\n};\n\n/**\n * Our transformers plus Lexical's built-ins; order matters.\n *\n * - MERMAID precedes TRANSFORMERS, so it wins over the generic CODE transformer.\n * - IMAGE precedes LINK, so `![alt](url)` is not parsed as `!` + link.\n */\nexport const CUSTOM_TRANSFORMERS: Transformer[] = [\n IMAGE,\n HORIZONTAL_RULE,\n CHECK_LIST,\n MERMAID,\n ...TRANSFORMERS,\n];\n\n/**\n * No transformers: `singleLine` mode edits plain-text entity names, not markdown.\n *\n * - Inline formatting would corrupt names like `a_b_c` (italics, then `\\_` on export).\n * - Pair with `unescapeMarkdownText` on export (see MarkdownSyncPlugin).\n */\nexport const SINGLE_LINE_TRANSFORMERS: Transformer[] = [];\n\n// GFM tables have no Lexical transformer: fenced on import, unfenced on export.\n\nconst TABLE_FENCE_LANG = '__kbc_table__';\n\nconst isTableLine = (line: string): boolean => {\n const trimmed = line.trim();\n return trimmed.startsWith('|') && trimmed.endsWith('|');\n};\n\nconst CODE_FENCE_REGEX = /^[ \\t]*`{3,}/;\n\n/** Wrap GFM tables in code fences so they survive Lexical's markdown round-trip. */\nexport const preprocessMarkdown = (markdown: string): string => {\n const lines = markdown.split('\\n');\n const result: string[] = [];\n let tableLines: string[] = [];\n let insideCodeFence = false;\n\n const flushTable = () => {\n if (tableLines.length >= 2) {\n result.push(`\\`\\`\\`${TABLE_FENCE_LANG}`);\n result.push(...tableLines);\n result.push('```');\n } else {\n // Single pipe line isn't a table — keep as-is\n result.push(...tableLines);\n }\n tableLines = [];\n };\n\n for (const line of lines) {\n if (CODE_FENCE_REGEX.test(line)) {\n if (tableLines.length > 0) flushTable();\n insideCodeFence = !insideCodeFence;\n result.push(line);\n continue;\n }\n\n if (insideCodeFence) {\n result.push(line);\n continue;\n }\n\n if (isTableLine(line)) {\n tableLines.push(line);\n } else {\n if (tableLines.length > 0) flushTable();\n result.push(line);\n }\n }\n if (tableLines.length > 0) flushTable();\n\n return result.join('\\n');\n};\n\n/** Unwrap code-fenced tables back to raw GFM table markdown. */\nexport const postprocessMarkdown = (markdown: string): string => {\n const regex = new RegExp(`\\`\\`\\`${TABLE_FENCE_LANG}\\\\n([\\\\s\\\\S]*?)\\\\n\\`\\`\\``, 'g');\n return markdown.replace(regex, '$1');\n};\n\n/** Reverses Lexical's export escaping of `* _ ` ~ \\`, for `singleLine` plain-text names. */\nexport const unescapeMarkdownText = (markdown: string): string =>\n markdown.replace(/\\\\([*_`~\\\\])/g, '$1');\n","import { useEffect, useRef } from 'react';\nimport type { Transformer } from '@lexical/markdown';\nimport { $convertFromMarkdownString, $convertToMarkdownString } from '@lexical/markdown';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\n\nimport { useStableCallback } from '../../../hooks/useStableCallback';\nimport {\n CUSTOM_TRANSFORMERS,\n postprocessMarkdown,\n preprocessMarkdown,\n unescapeMarkdownText,\n} from '../transformers';\n\nconst IMPORT_TAG = 'markdown-import';\n\ntype MarkdownSyncPluginProps = {\n value: string;\n editable: boolean;\n onChange?: (markdown: string) => void;\n transformers?: Transformer[];\n /**\n * Plain-text mode: export a bare entity name instead of markdown. Unescapes the punctuation\n * Lexical escapes on export (`\\_` → `_`), so names with underscores don't persist backslashes.\n */\n singleLine?: boolean;\n};\n\nexport const MarkdownSyncPlugin = ({\n value,\n editable,\n onChange,\n transformers = CUSTOM_TRANSFORMERS,\n singleLine = false,\n}: MarkdownSyncPluginProps) => {\n const [editor] = useLexicalComposerContext();\n const lastExportedRef = useRef(value);\n const handleChange = useStableCallback((markdown: string) => onChange?.(markdown));\n const transformersRef = useRef(transformers);\n transformersRef.current = transformers;\n const singleLineRef = useRef(singleLine);\n singleLineRef.current = singleLine;\n\n // Sync editable state — only when it actually changes\n useEffect(() => {\n editor.setEditable(editable);\n }, [editor, editable]);\n\n // Import: external value -> editor state\n useEffect(() => {\n if (value === lastExportedRef.current) return;\n lastExportedRef.current = value;\n\n editor.update(\n () => {\n $convertFromMarkdownString(preprocessMarkdown(value), transformersRef.current);\n },\n { tag: IMPORT_TAG },\n );\n }, [editor, value]);\n\n // Export: editor state -> onChange (subscription)\n useEffect(() => {\n return editor.registerUpdateListener(({ tags }) => {\n if (tags.has(IMPORT_TAG)) return;\n\n editor.getEditorState().read(() => {\n const raw = $convertToMarkdownString(transformersRef.current);\n const markdown = singleLineRef.current\n ? unescapeMarkdownText(raw)\n : postprocessMarkdown(raw);\n if (markdown !== lastExportedRef.current) {\n lastExportedRef.current = markdown;\n handleChange(markdown);\n }\n });\n });\n }, [editor, handleChange]);\n\n return null;\n};\n","import { useRef } from 'react';\nimport {\n $getSelection,\n $setSelection,\n type BaseSelection,\n type ElementFormatType,\n FORMAT_ELEMENT_COMMAND,\n type LexicalEditor,\n} from 'lexical';\n\nimport { DropdownMenu } from '../../../../components/DropdownMenu';\nimport { Tooltip } from '../../../../components/Tooltip';\nimport {\n AlignCenter,\n AlignJustify,\n AlignLeft,\n AlignRight,\n ChevronDown,\n type LucideIcon,\n} from '../../../../icons';\nimport { cn } from '../../../../utils';\n\nconst ALIGNMENT_OPTIONS: { value: ElementFormatType; label: string; icon: LucideIcon }[] = [\n { value: 'left', label: 'Left', icon: AlignLeft },\n { value: 'center', label: 'Center', icon: AlignCenter },\n { value: 'right', label: 'Right', icon: AlignRight },\n { value: 'justify', label: 'Justify', icon: AlignJustify },\n];\n\nconst ALIGNMENT_ICONS: Record<string, LucideIcon> = Object.fromEntries(\n ALIGNMENT_OPTIONS.map(({ value, icon }) => [value, icon]),\n);\n\nexport const AlignmentDropdown = ({\n editor,\n alignment,\n}: {\n editor: LexicalEditor;\n alignment: ElementFormatType;\n}) => {\n const savedSelectionRef = useRef<BaseSelection | null>(null);\n\n const handleOpenChange = (open: boolean) => {\n if (open) {\n editor.getEditorState().read(() => {\n const selection = $getSelection();\n savedSelectionRef.current = selection ? selection.clone() : null;\n });\n }\n };\n\n const handleSelect = (align: ElementFormatType) => {\n // Restore selection and dispatch within the same update so the command sees\n // the restored selection (otherwise dispatchCommand may race with the queued\n // $setSelection and apply the format to the wrong block).\n editor.update(() => {\n if (savedSelectionRef.current) {\n $setSelection(savedSelectionRef.current);\n }\n editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, align);\n });\n };\n\n const CurrentAlignmentIcon = ALIGNMENT_ICONS[alignment] ?? AlignLeft;\n\n return (\n <DropdownMenu onOpenChange={handleOpenChange}>\n <Tooltip tooltip=\"Text alignment\" placement=\"top\" triggerAsChild>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'tw:flex tw:h-7 tw:cursor-pointer tw:items-center tw:gap-1 tw:rounded tw:border-0 tw:bg-transparent tw:px-1.5 tw:text-xs tw:text-muted-foreground',\n 'tw:hover:bg-accent',\n )}\n >\n <CurrentAlignmentIcon className=\"tw:size-4\" />\n <ChevronDown className=\"tw:size-3\" />\n </button>\n </DropdownMenu.Trigger>\n </Tooltip>\n <DropdownMenu.Content align=\"start\" className=\"tw:min-w-32\">\n {ALIGNMENT_OPTIONS.map(({ value, label, icon: IconComp }) => (\n <DropdownMenu.Item\n key={value}\n onSelect={() => handleSelect(value)}\n className={cn(\n 'tw:flex tw:items-center tw:gap-2',\n alignment === value && 'tw:bg-secondary-50 tw:text-secondary-500',\n )}\n >\n <IconComp className=\"tw:size-4\" />\n {label}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu>\n );\n};\n","import { useRef } from 'react';\nimport { $createCodeNode } from '@lexical/code';\nimport { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list';\nimport { $createHeadingNode, $createQuoteNode } from '@lexical/rich-text';\nimport { $getNearestBlockElementAncestorOrThrow } from '@lexical/utils';\nimport {\n $createParagraphNode,\n $getSelection,\n $isRangeSelection,\n $setSelection,\n type BaseSelection,\n type LexicalEditor,\n} from 'lexical';\n\nimport { DropdownMenu } from '../../../../components/DropdownMenu';\nimport { Tooltip } from '../../../../components/Tooltip';\nimport {\n ChevronDown,\n Heading1,\n Heading2,\n Heading3,\n List as ListIcon,\n ListOrdered,\n type LucideIcon,\n Quote,\n SquareCode,\n Type,\n} from '../../../../icons';\nimport { cn } from '../../../../utils';\n\nconst BLOCK_TYPE_META = {\n paragraph: { label: 'Normal', icon: Type satisfies LucideIcon, selectable: true },\n h1: { label: 'Heading 1', icon: Heading1 satisfies LucideIcon, selectable: true },\n h2: { label: 'Heading 2', icon: Heading2 satisfies LucideIcon, selectable: true },\n h3: { label: 'Heading 3', icon: Heading3 satisfies LucideIcon, selectable: true },\n bullet: { label: 'Bullet List', icon: ListIcon satisfies LucideIcon, selectable: false },\n number: { label: 'Numbered List', icon: ListOrdered satisfies LucideIcon, selectable: false },\n quote: { label: 'Quote', icon: Quote satisfies LucideIcon, selectable: false },\n code: { label: 'Code Block', icon: SquareCode satisfies LucideIcon, selectable: false },\n} as const;\n\ntype BlockType = keyof typeof BLOCK_TYPE_META;\n\nconst BLOCK_TYPE_OPTIONS = (\n Object.entries(BLOCK_TYPE_META) as [BlockType, (typeof BLOCK_TYPE_META)[BlockType]][]\n)\n .filter(([, meta]) => meta.selectable)\n .map(([value, { label, icon }]) => ({ value, label, icon }));\n\nconst isBlockType = (value: string): value is BlockType =>\n Object.prototype.hasOwnProperty.call(BLOCK_TYPE_META, value);\n\nexport const BlockTypeDropdown = ({\n editor,\n blockType,\n}: {\n editor: LexicalEditor;\n blockType: string;\n}) => {\n const savedSelectionRef = useRef<BaseSelection | null>(null);\n const currentMeta = isBlockType(blockType) ? BLOCK_TYPE_META[blockType] : null;\n const CurrentBlockIcon = currentMeta?.icon ?? Type;\n\n const handleOpenChange = (open: boolean) => {\n if (open) {\n editor.getEditorState().read(() => {\n const selection = $getSelection();\n savedSelectionRef.current = selection ? selection.clone() : null;\n });\n }\n };\n\n const handleSelect = (type: BlockType) => {\n editor.update(() => {\n if (savedSelectionRef.current) {\n $setSelection(savedSelectionRef.current);\n }\n\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n if (type === 'bullet') {\n editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);\n return;\n }\n if (type === 'number') {\n editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);\n return;\n }\n\n const anchorNode = selection.anchor.getNode();\n const element = $getNearestBlockElementAncestorOrThrow(anchorNode);\n\n const newNode =\n type === 'h1' || type === 'h2' || type === 'h3'\n ? $createHeadingNode(type)\n : type === 'quote'\n ? $createQuoteNode()\n : type === 'code'\n ? $createCodeNode()\n : $createParagraphNode();\n\n element.getChildren().forEach((child) => newNode.append(child));\n element.replace(newNode);\n });\n };\n\n return (\n <DropdownMenu onOpenChange={handleOpenChange}>\n <Tooltip tooltip=\"Change block type\" placement=\"top\" triggerAsChild>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'tw:flex tw:h-7 tw:cursor-pointer tw:items-center tw:gap-1.5 tw:rounded tw:border-0 tw:bg-transparent tw:px-1.5 tw:text-xs tw:text-muted-foreground',\n 'tw:hover:bg-accent',\n )}\n >\n <CurrentBlockIcon className=\"tw:size-4\" />\n {currentMeta?.label ?? 'Normal'}\n <ChevronDown className=\"tw:size-3\" />\n </button>\n </DropdownMenu.Trigger>\n </Tooltip>\n <DropdownMenu.Content align=\"start\" className=\"tw:min-w-40\">\n {BLOCK_TYPE_OPTIONS.map(({ value, label, icon: IconComp }) => (\n <DropdownMenu.Item\n key={value}\n onSelect={() => handleSelect(value)}\n className={cn(\n 'tw:flex tw:items-center tw:gap-2',\n blockType === value && 'tw:bg-secondary-50 tw:text-secondary-500',\n )}\n >\n <IconComp className=\"tw:size-4\" />\n {label}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu>\n );\n};\n","import type { ReactNode } from 'react';\n\nimport { Tooltip } from '../../../../components/Tooltip';\nimport { cn } from '../../../../utils';\n\nexport const ToolbarButton = ({\n active,\n disabled,\n onClick,\n tooltip,\n children,\n className: extraClassName,\n}: {\n active?: boolean;\n disabled?: boolean;\n onClick: () => void;\n tooltip: ReactNode;\n children: ReactNode;\n className?: string;\n}) => (\n <Tooltip tooltip={tooltip} placement=\"top\" triggerAsChild>\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onClick}\n className={cn(\n 'tw:flex tw:h-7 tw:min-w-7 tw:cursor-pointer tw:items-center tw:justify-center tw:rounded tw:border-0 tw:bg-transparent tw:px-1 tw:text-xs tw:text-muted-foreground',\n 'tw:hover:bg-accent tw:disabled:cursor-not-allowed tw:disabled:opacity-30',\n active && 'tw:bg-secondary-100 tw:text-secondary-500',\n extraClassName,\n )}\n >\n {children}\n </button>\n </Tooltip>\n);\n","import { useRef, useState } from 'react';\nimport type { KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport { $createLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';\nimport {\n $createTextNode,\n $getSelection,\n $isRangeSelection,\n $setSelection,\n type BaseSelection,\n type LexicalEditor,\n} from 'lexical';\n\nimport { FormGroup } from '../../../../blocks/FormGroup';\nimport { TextInput } from '../../../../blocks/TextInput';\nimport { Button } from '../../../../components/Button';\nimport { ButtonGroup } from '../../../../components/ButtonGroup';\nimport { Label } from '../../../../components/Label';\nimport { Link as LinkIcon } from '../../../../icons';\n\nimport { ToolbarButton } from './ToolbarButton';\n\nconst insertLink = (\n editor: LexicalEditor,\n url: string,\n label: string,\n savedSelection: BaseSelection | null,\n) => {\n editor.update(() => {\n $setSelection(savedSelection);\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n const selectedText = selection.getTextContent();\n if (selectedText && label === selectedText) {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, url);\n return;\n }\n }\n\n const linkNode = $createLinkNode(url);\n const textNode = $createTextNode(label || url);\n linkNode.append(textNode);\n\n if ($isRangeSelection(selection)) {\n selection.insertNodes([linkNode]);\n }\n });\n};\n\nexport const LinkPanel = ({ editor, isLink }: { editor: LexicalEditor; isLink: boolean }) => {\n const [open, setOpen] = useState(false);\n const [url, setUrl] = useState('');\n const [label, setLabel] = useState('');\n const savedSelectionRef = useRef<BaseSelection | null>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n\n const handleOpen = () => {\n editor.getEditorState().read(() => {\n const selection = $getSelection();\n savedSelectionRef.current = selection ? selection.clone() : null;\n\n if ($isRangeSelection(selection)) {\n const text = selection.getTextContent();\n if (text) setLabel(text);\n }\n });\n setOpen(true);\n };\n\n const handleClose = () => {\n setOpen(false);\n setUrl('');\n setLabel('');\n savedSelectionRef.current = null;\n editor.focus();\n };\n\n const handleSubmit = () => {\n const trimmedUrl = url.trim();\n if (!trimmedUrl) return;\n\n insertLink(editor, trimmedUrl, label.trim(), savedSelectionRef.current);\n handleClose();\n };\n\n const handleKeyDown = (e: ReactKeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleSubmit();\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n handleClose();\n }\n };\n\n if (isLink) {\n return (\n <ToolbarButton\n active\n onClick={() => editor.dispatchCommand(TOGGLE_LINK_COMMAND, null)}\n tooltip=\"Remove Link\"\n >\n <LinkIcon className=\"tw:size-4\" />\n </ToolbarButton>\n );\n }\n\n return (\n <div className=\"tw:relative\">\n <ToolbarButton active={open} onClick={handleOpen} tooltip=\"Insert Link\">\n <LinkIcon className=\"tw:size-4\" />\n </ToolbarButton>\n {open && (\n <div\n ref={panelRef}\n className=\"tw:absolute tw:left-0 tw:top-full tw:z-50 tw:mt-1 tw:w-80 tw:rounded-md tw:border tw:border-border tw:bg-popover tw:p-3 tw:text-popover-foreground tw:shadow-lg\"\n >\n <div className=\"tw:flex tw:flex-col tw:gap-2\">\n <FormGroup>\n <Label htmlFor=\"link-label\" className=\"tw:mb-1 tw:text-xs\">\n Label\n </Label>\n <TextInput\n id=\"link-label\"\n autoFocus\n placeholder=\"Link text\"\n value={label}\n onValueChange={setLabel}\n onKeyDown={handleKeyDown}\n variant=\"secondary\"\n />\n </FormGroup>\n <FormGroup>\n <Label htmlFor=\"link-url\" className=\"tw:mb-1 tw:text-xs\">\n URL\n </Label>\n <TextInput\n id=\"link-url\"\n placeholder=\"https://…\"\n value={url}\n onValueChange={setUrl}\n onKeyDown={handleKeyDown}\n variant=\"secondary\"\n />\n </FormGroup>\n <ButtonGroup>\n <Button size=\"small\" variant=\"outline\" onClick={handleClose}>\n Cancel\n </Button>\n <Button size=\"small\" onClick={handleSubmit} disabled={!url.trim()}>\n Add link\n </Button>\n </ButtonGroup>\n </div>\n </div>\n )}\n </div>\n );\n};\n","export const ToolbarDivider = () => <div className=\"tw:mx-0.5 tw:h-5 tw:w-px tw:bg-border\" />;\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { $createCodeNode, $isCodeNode } from '@lexical/code';\nimport { $isLinkNode } from '@lexical/link';\nimport {\n $isListNode,\n INSERT_ORDERED_LIST_COMMAND,\n INSERT_UNORDERED_LIST_COMMAND,\n REMOVE_LIST_COMMAND,\n} from '@lexical/list';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { $createQuoteNode, $isHeadingNode, $isQuoteNode } from '@lexical/rich-text';\nimport { $getNearestBlockElementAncestorOrThrow } from '@lexical/utils';\nimport {\n $createParagraphNode,\n $getSelection,\n $isRangeSelection,\n type ElementFormatType,\n FORMAT_TEXT_COMMAND,\n} from 'lexical';\n\nimport {\n Bold,\n Code,\n Italic,\n List as ListIcon,\n ListOrdered,\n Quote,\n SquareCode,\n Strikethrough,\n Underline,\n} from '../../../icons';\n\nimport { AlignmentDropdown } from './toolbar/AlignmentDropdown';\nimport { BlockTypeDropdown } from './toolbar/BlockTypeDropdown';\nimport { LinkPanel } from './toolbar/LinkPanel';\nimport { ToolbarButton } from './toolbar/ToolbarButton';\nimport { ToolbarDivider } from './toolbar/ToolbarDivider';\n\nconst ELEMENT_FORMAT_TYPES = ['left', 'center', 'right', 'justify', 'start', 'end', ''] as const;\n\nconst isElementFormatType = (value: string): value is ElementFormatType =>\n (ELEMENT_FORMAT_TYPES as readonly string[]).includes(value);\n\nconst toElementFormatType = (value: string): ElementFormatType =>\n isElementFormatType(value) ? value : 'left';\n\nexport const ToolbarPlugin = () => {\n const [editor] = useLexicalComposerContext();\n const [isBold, setIsBold] = useState(false);\n const [isItalic, setIsItalic] = useState(false);\n const [isUnderline, setIsUnderline] = useState(false);\n const [isStrikethrough, setIsStrikethrough] = useState(false);\n const [isCode, setIsCode] = useState(false);\n const [isLink, setIsLink] = useState(false);\n const [blockType, setBlockType] = useState<string>('paragraph');\n const [alignment, setAlignment] = useState<ElementFormatType>('left');\n const [isVisible, setIsVisible] = useState(false);\n const [position, setPosition] = useState<{ top: number; left: number } | null>(null);\n const toolbarRef = useRef<HTMLDivElement>(null);\n const isMouseDownRef = useRef(false);\n const hasSelectionRef = useRef(false);\n\n const updatePosition = useCallback(() => {\n const nativeSelection = window.getSelection();\n if (!nativeSelection || nativeSelection.rangeCount === 0) return;\n const range = nativeSelection.getRangeAt(0);\n const rect = range.getBoundingClientRect();\n if (rect.width > 0) {\n const toolbarWidth = toolbarRef.current?.offsetWidth ?? 300;\n setPosition({\n top: rect.top + window.scrollY - 8,\n left: Math.max(8, rect.left + window.scrollX + rect.width / 2 - toolbarWidth / 2),\n });\n }\n }, []);\n\n useEffect(() => {\n const handleMouseDown = () => {\n isMouseDownRef.current = true;\n };\n const handleMouseUp = () => {\n isMouseDownRef.current = false;\n if (hasSelectionRef.current) {\n setIsVisible(true);\n }\n };\n document.addEventListener('mousedown', handleMouseDown);\n document.addEventListener('mouseup', handleMouseUp);\n return () => {\n document.removeEventListener('mousedown', handleMouseDown);\n document.removeEventListener('mouseup', handleMouseUp);\n };\n }, []);\n\n const updateToolbar = useCallback(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n hasSelectionRef.current = false;\n setIsVisible(false);\n return;\n }\n\n const hasSelection = !selection.isCollapsed() && selection.getTextContent().length > 0;\n hasSelectionRef.current = hasSelection;\n\n if (!hasSelection) {\n setIsVisible(false);\n } else if (!isMouseDownRef.current) {\n setIsVisible(true);\n }\n\n if (hasSelection) {\n updatePosition();\n }\n\n setIsBold(selection.hasFormat('bold'));\n setIsItalic(selection.hasFormat('italic'));\n setIsUnderline(selection.hasFormat('underline'));\n setIsStrikethrough(selection.hasFormat('strikethrough'));\n setIsCode(selection.hasFormat('code'));\n\n const node = selection.anchor.getNode();\n const parent = node.getParent();\n setIsLink($isLinkNode(parent) || $isLinkNode(node));\n\n const blockElement = $getNearestBlockElementAncestorOrThrow(node);\n\n if ($isListNode(blockElement)) {\n const listType = blockElement.getListType();\n setBlockType(listType === 'number' ? 'number' : 'bullet');\n } else if ($isHeadingNode(blockElement)) {\n setBlockType(blockElement.getTag());\n } else if ($isCodeNode(blockElement)) {\n setBlockType('code');\n } else if ($isQuoteNode(blockElement)) {\n setBlockType('quote');\n } else {\n setBlockType('paragraph');\n }\n\n setAlignment(toElementFormatType(blockElement.getFormatType()));\n }, [updatePosition]);\n\n useEffect(() => {\n const unregisterUpdate = editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n updateToolbar();\n });\n });\n\n return () => {\n unregisterUpdate();\n };\n }, [editor, updateToolbar]);\n\n if (!isVisible || !position) return null;\n\n return createPortal(\n <div\n ref={toolbarRef}\n role=\"toolbar\"\n aria-label=\"Formatting options\"\n onMouseDown={(e) => e.preventDefault()}\n style={{ top: position.top, left: position.left }}\n className=\"tw:absolute tw:z-[1060] tw:flex tw:-translate-y-full tw:items-center tw:gap-0.5 tw:rounded-lg tw:border tw:border-border tw:bg-popover tw:px-1.5 tw:py-1 tw:text-popover-foreground tw:shadow-lg\"\n >\n <BlockTypeDropdown editor={editor} blockType={blockType} />\n\n <ToolbarDivider />\n\n <ToolbarButton\n active={isBold}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold')}\n tooltip=\"Bold (Ctrl+B)\"\n >\n <Bold className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={isItalic}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic')}\n tooltip=\"Italic (Ctrl+I)\"\n >\n <Italic className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={isUnderline}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline')}\n tooltip=\"Underline (Ctrl+U)\"\n >\n <Underline className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={isStrikethrough}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough')}\n tooltip=\"Strikethrough\"\n >\n <Strikethrough className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={isCode}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'code')}\n tooltip=\"Inline Code\"\n >\n <Code className=\"tw:size-4\" />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n <LinkPanel editor={editor} isLink={isLink} />\n\n <ToolbarDivider />\n\n <ToolbarButton\n active={blockType === 'bullet'}\n onClick={() => {\n if (blockType === 'bullet') {\n editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);\n } else {\n editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);\n }\n }}\n tooltip=\"Bullet List\"\n >\n <ListIcon className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={blockType === 'number'}\n onClick={() => {\n if (blockType === 'number') {\n editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);\n } else {\n editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);\n }\n }}\n tooltip=\"Numbered List\"\n >\n <ListOrdered className=\"tw:size-4\" />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n <AlignmentDropdown editor={editor} alignment={alignment} />\n\n <ToolbarDivider />\n\n <ToolbarButton\n active={blockType === 'quote'}\n onClick={() => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n const anchorNode = selection.anchor.getNode();\n const element = $getNearestBlockElementAncestorOrThrow(anchorNode);\n const newNode = blockType === 'quote' ? $createParagraphNode() : $createQuoteNode();\n element.getChildren().forEach((child) => newNode.append(child));\n element.replace(newNode);\n });\n }}\n tooltip=\"Quote\"\n >\n <Quote className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={blockType === 'code'}\n onClick={() => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n const anchorNode = selection.anchor.getNode();\n const element = $getNearestBlockElementAncestorOrThrow(anchorNode);\n const newNode = blockType === 'code' ? $createParagraphNode() : $createCodeNode();\n element.getChildren().forEach((child) => newNode.append(child));\n element.replace(newNode);\n });\n }}\n tooltip=\"Code Block\"\n >\n <SquareCode className=\"tw:size-4\" />\n </ToolbarButton>\n </div>,\n document.body,\n );\n};\n","import type { EditorThemeClasses } from 'lexical';\n\n/**\n * Lexical editor theme — maps node types to CSS classes.\n * The editor container uses `tw:prose` so semantic elements (headings, lists, blockquotes, etc.)\n * are styled by Tailwind Typography. We only need explicit classes for text formatting\n * (bold, italic, etc.) because Lexical renders those as `<span>` elements.\n */\nexport const editorTheme: EditorThemeClasses = {\n link: 'tw:cursor-pointer tw:!text-primary tw:underline',\n text: {\n bold: 'tw:font-bold',\n italic: 'tw:italic',\n strikethrough: 'tw:line-through',\n underline: 'tw:underline',\n code: 'tw:rounded tw:bg-muted tw:px-1 tw:py-0.5 tw:font-mono tw:text-[0.85em]',\n },\n list: {\n ol: 'tw:!list-decimal',\n ul: 'tw:!list-disc',\n checklist: 'tw:!list-none tw:!pl-0',\n listitemChecked: [\n 'tw:relative tw:!pl-6 tw:list-none tw:outline-hidden tw:line-through tw:text-muted-foreground',\n 'tw:before:content-[\"\"] tw:before:absolute tw:before:left-0 tw:before:top-[3px]',\n 'tw:before:size-4 tw:before:rounded tw:before:border tw:before:border-solid',\n 'tw:before:bg-primary tw:before:border-primary tw:before:cursor-pointer',\n 'tw:after:content-[\"\"] tw:after:absolute tw:after:left-[5.5px] tw:after:top-[5.5px]',\n 'tw:after:w-1 tw:after:h-2 tw:after:border-primary-foreground tw:after:border-solid',\n 'tw:after:border-r-[1.5px] tw:after:border-b-[1.5px] tw:after:border-t-0 tw:after:border-l-0',\n 'tw:after:rotate-45',\n ].join(' '),\n listitemUnchecked: [\n 'tw:relative tw:!pl-6 tw:list-none tw:outline-hidden',\n 'tw:before:content-[\"\"] tw:before:absolute tw:before:left-0 tw:before:top-[3px]',\n 'tw:before:size-4 tw:before:rounded tw:before:border tw:before:border-solid',\n 'tw:before:border-input tw:before:bg-background tw:before:cursor-pointer',\n ].join(' '),\n },\n};\n","import { useRef, useState } from 'react';\nimport type { FocusEvent, ReactNode } from 'react';\nimport { CodeNode } from '@lexical/code';\nimport { LinkNode } from '@lexical/link';\nimport { ListItemNode, ListNode } from '@lexical/list';\nimport { $convertFromMarkdownString } from '@lexical/markdown';\nimport { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';\nimport { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin';\nimport { ClickableLinkPlugin } from '@lexical/react/LexicalClickableLinkPlugin';\nimport type { InitialConfigType } from '@lexical/react/LexicalComposer';\nimport { LexicalComposer } from '@lexical/react/LexicalComposer';\nimport { ContentEditable } from '@lexical/react/LexicalContentEditable';\nimport { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';\nimport { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';\nimport { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';\nimport { HorizontalRulePlugin } from '@lexical/react/LexicalHorizontalRulePlugin';\nimport { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';\nimport { ListPlugin } from '@lexical/react/LexicalListPlugin';\nimport { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin';\nimport { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';\nimport { TabIndentationPlugin } from '@lexical/react/LexicalTabIndentationPlugin';\nimport { HeadingNode, QuoteNode } from '@lexical/rich-text';\n\nimport { cn } from '../../utils';\n\nimport { ImageNode } from './nodes/ImageNode';\nimport { MermaidNode } from './nodes/MermaidNode';\nimport { ImagePastePlugin } from './plugins/ImagePastePlugin';\nimport { KeyboardPlugin } from './plugins/KeyboardPlugin';\nimport { MarkdownSyncPlugin } from './plugins/MarkdownSyncPlugin';\nimport { ToolbarPlugin } from './plugins/ToolbarPlugin';\nimport { ImageRendererProvider } from './context';\nimport { editorTheme } from './theme';\nimport { CUSTOM_TRANSFORMERS, preprocessMarkdown, SINGLE_LINE_TRANSFORMERS } from './transformers';\n\nexport type MarkdownEditorProps = {\n /** Markdown string (controlled) */\n value: string;\n onChange?: (markdown: string) => void;\n /** Permanent view-only (e.g. no edit permission). Hides the toolbar. */\n readOnly?: boolean;\n /** Temporary block (e.g. save in flight). Behaves like `readOnly`. */\n disabled?: boolean;\n placeholder?: string;\n autoFocus?: boolean;\n /** Invoked on Cmd/Ctrl+Enter. */\n onSave?: () => void;\n /**\n * Escape in inline-edit mode (`singleLine || saveOnBlur`).\n * Callers reset `value` to the last-committed state here.\n */\n onCancel?: () => void;\n /** The resolved URL becomes the image src in the markdown. */\n onImageUpload?: (file: File) => Promise<{ url: string }>;\n className?: string;\n imageRenderer?: (props: { src: string; alt: string }) => ReactNode;\n showToolbar?: boolean;\n /**\n * No prose wrapper, min-height or padding — blends into surrounding text for inline editing.\n * Set typography via `className`.\n */\n compact?: boolean;\n /** Calls `onSave` when focus leaves the editor (the toolbar doesn't count). */\n saveOnBlur?: boolean;\n /**\n * No block-level markdown; Enter blurs the editor, Shift+Enter inserts a soft break.\n * Use for editable titles.\n */\n singleLine?: boolean;\n /** Clamps to 2 lines with an ellipsis while not focused; focus shows everything. */\n clampDisplay?: boolean;\n /**\n * Minimum height in lines; `0` removes the floor. Default ~4 lines.\n * Ignored in `compact` mode.\n */\n minRows?: number;\n};\n\nconst EDITOR_NODES = [\n ImageNode,\n MermaidNode,\n HeadingNode,\n QuoteNode,\n ListNode,\n ListItemNode,\n CodeNode,\n LinkNode,\n HorizontalRuleNode,\n];\n\nexport const MarkdownEditor = ({\n value,\n onChange,\n readOnly = false,\n placeholder,\n autoFocus = false,\n disabled = false,\n onSave,\n onCancel,\n onImageUpload,\n className,\n imageRenderer,\n showToolbar = false,\n compact = false,\n saveOnBlur = false,\n singleLine = false,\n clampDisplay = false,\n minRows,\n}: MarkdownEditorProps) => {\n const editable = !readOnly && !disabled;\n const transformers = singleLine ? SINGLE_LINE_TRANSFORMERS : CUSTOM_TRANSFORMERS;\n const useDefaultMinHeight = !compact && minRows === undefined;\n const customMinHeight =\n !compact && minRows !== undefined ? { minHeight: `${minRows * 1.75}em` } : undefined;\n\n // Lexical reads editorState only on first render; later prop changes are applied by MarkdownSyncPlugin.\n const [initialConfig] = useState<InitialConfigType>(() => ({\n namespace: 'MarkdownEditor',\n theme: editorTheme,\n nodes: EDITOR_NODES,\n onError: (error: Error) => {\n console.error('[MarkdownEditor] uncaught editor error', error);\n },\n editable,\n editorState: () => {\n $convertFromMarkdownString(preprocessMarkdown(value), transformers);\n },\n }));\n\n // Set by KeyboardPlugin before its Escape blur, so the blur doesn't commit the reverted value.\n const skipBlurSaveRef = useRef(false);\n\n const handleBlur =\n saveOnBlur && onSave\n ? (event: FocusEvent<HTMLDivElement>) => {\n if (skipBlurSaveRef.current) {\n skipBlurSaveRef.current = false;\n return;\n }\n // Focus moving into the toolbar doesn't count.\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {\n onSave();\n }\n }\n : undefined;\n\n return (\n <LexicalComposer initialConfig={initialConfig}>\n <ImageRendererProvider value={imageRenderer ?? null}>\n <div\n className={cn(\n !compact && 'tw:prose',\n // Without `tw:prose`, <p> gets the browser's `margin: 1em 0`; space only between paragraphs.\n compact && 'tw:[&_p]:m-0 tw:[&_p+p]:mt-2',\n // No fade: CSS can't gate one on overflow.\n clampDisplay && 'tw:[&:not(:focus-within)]:line-clamp-2',\n className,\n )}\n onBlur={handleBlur}\n >\n {showToolbar && editable && <ToolbarPlugin />}\n <div\n className={cn(\n 'tw:relative tw:rounded-md tw:transition-colors',\n // Compact: the negative margin cancels the padding, so the text stays aligned with static text.\n compact ? 'tw:px-1.5 tw:py-0.5 tw:-mx-1.5 tw:-my-0.5' : 'tw:p-2',\n editable &&\n 'tw:cursor-text tw:hover:bg-muted tw:focus-within:ring-2 tw:focus-within:ring-ring/40',\n )}\n >\n <RichTextPlugin\n contentEditable={\n <ContentEditable\n className={cn('tw:outline-hidden', useDefaultMinHeight && 'tw:min-h-[100px]')}\n style={customMinHeight}\n aria-placeholder={placeholder ?? ''}\n placeholder={\n placeholder ? (\n <div\n className={cn(\n 'tw:pointer-events-none tw:absolute tw:select-none tw:text-muted-foreground',\n compact\n ? 'tw:left-1.5 tw:top-0.5'\n : 'tw:left-2 tw:top-[calc(0.5rem+0.35em)]',\n )}\n >\n {placeholder}\n </div>\n ) : (\n <div />\n )\n }\n />\n }\n ErrorBoundary={LexicalErrorBoundary}\n />\n </div>\n <HistoryPlugin />\n <LinkPlugin />\n <ClickableLinkPlugin newTab />\n {!singleLine && <ListPlugin />}\n {!singleLine && <CheckListPlugin />}\n {!singleLine && <HorizontalRulePlugin />}\n <TabIndentationPlugin />\n <MarkdownShortcutPlugin transformers={transformers} />\n <MarkdownSyncPlugin\n value={value}\n editable={editable}\n onChange={onChange}\n transformers={transformers}\n singleLine={singleLine}\n />\n <ImagePastePlugin onImageUpload={onImageUpload} />\n <KeyboardPlugin\n onSave={onSave}\n onCancel={onCancel}\n singleLine={singleLine}\n blurOnEscape={singleLine || saveOnBlur}\n skipBlurSaveRef={skipBlurSaveRef}\n />\n {autoFocus && <AutoFocusPlugin />}\n </div>\n </ImageRendererProvider>\n </LexicalComposer>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"markdown-editor.js","names":["ListIcon","LinkIcon","ListIcon"],"sources":["../src/blocks/MarkdownEditor/context.ts","../src/blocks/MarkdownEditor/nodes/ImageNodeComponent.tsx","../src/blocks/MarkdownEditor/nodes/ImageNode.tsx","../src/blocks/MarkdownEditor/plugins/ImagePastePlugin.tsx","../src/blocks/MarkdownEditor/plugins/KeyboardPlugin.tsx","../src/blocks/MarkdownEditor/nodes/MermaidNodeComponent.tsx","../src/blocks/MarkdownEditor/nodes/MermaidNode.tsx","../src/blocks/MarkdownEditor/editorNodes.ts","../src/blocks/MarkdownEditor/bareUrls.ts","../src/blocks/MarkdownEditor/transformers.ts","../src/blocks/MarkdownEditor/plugins/MarkdownPastePlugin.tsx","../src/blocks/MarkdownEditor/plugins/MarkdownSyncPlugin.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/AlignmentDropdown.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/BlockTypeDropdown.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/ToolbarButton.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/LinkPanel.tsx","../src/blocks/MarkdownEditor/plugins/toolbar/ToolbarDivider.tsx","../src/blocks/MarkdownEditor/plugins/ToolbarPlugin.tsx","../src/blocks/MarkdownEditor/theme.ts","../src/blocks/MarkdownEditor/MarkdownEditor.tsx"],"sourcesContent":["import { createContext, use } from 'react';\nimport type { ReactNode } from 'react';\n\ntype ImageRenderer = (props: { src: string; alt: string }) => ReactNode;\n\nconst ImageRendererContext = createContext<ImageRenderer | null>(null);\n\nexport const ImageRendererProvider = ImageRendererContext;\n\nexport const useImageRenderer = (): ImageRenderer | null => use(ImageRendererContext);\n","import { useImageRenderer } from '../context';\n\nconst isPlaceholder = (src: string) => src.startsWith('upload-placeholder-');\n\nexport const ImageNodeComponent = ({ src, alt }: { src: string; alt: string }) => {\n const renderer = useImageRenderer();\n\n if (isPlaceholder(src)) {\n return (\n <span className=\"tw:inline-flex tw:items-center tw:gap-1 tw:rounded tw:bg-neutral-100 tw:px-2 tw:py-1 tw:text-xs tw:text-neutral-400\">\n Uploading image…\n </span>\n );\n }\n\n if (renderer) return <>{renderer({ src, alt })}</>;\n return <img src={src} alt={alt} />;\n};\n","/* eslint-disable react/only-export-components -- Lexical convention: $create/$is helpers co-locate with node */\nimport type { ReactNode } from 'react';\nimport type {\n DOMConversionMap,\n DOMExportOutput,\n EditorConfig,\n LexicalNode,\n NodeKey,\n SerializedLexicalNode,\n Spread,\n} from 'lexical';\nimport { DecoratorNode } from 'lexical';\n\nimport { ImageNodeComponent } from './ImageNodeComponent';\n\ntype SerializedImageNode = Spread<{ src: string; altText: string }, SerializedLexicalNode>;\n\nexport class ImageNode extends DecoratorNode<ReactNode> {\n __src: string;\n __altText: string;\n\n static override getType(): string {\n return 'image';\n }\n\n static override clone(node: ImageNode): ImageNode {\n return new ImageNode(node.__src, node.__altText, node.__key);\n }\n\n constructor(src: string, altText: string, key?: NodeKey) {\n super(key);\n this.__src = src;\n this.__altText = altText;\n }\n\n getSrc(): string {\n return this.__src;\n }\n\n getAlt(): string {\n return this.__altText;\n }\n\n setSrc(src: string): void {\n const writable = this.getWritable();\n writable.__src = src;\n }\n\n setAlt(altText: string): void {\n const writable = this.getWritable();\n writable.__altText = altText;\n }\n\n override createDOM(config: EditorConfig): HTMLElement {\n const span = document.createElement('span');\n const className = config.theme.image;\n if (typeof className === 'string') {\n span.className = className;\n }\n return span;\n }\n\n override updateDOM(): boolean {\n return false;\n }\n\n override decorate(): ReactNode {\n return <ImageNodeComponent src={this.__src} alt={this.__altText} />;\n }\n\n override isInline(): boolean {\n return true;\n }\n\n static override importJSON(serializedNode: SerializedImageNode): ImageNode {\n return $createImageNode(serializedNode.src, serializedNode.altText);\n }\n\n override exportJSON(): SerializedImageNode {\n return {\n type: 'image',\n version: 1,\n src: this.__src,\n altText: this.__altText,\n };\n }\n\n override exportDOM(): DOMExportOutput {\n const element = document.createElement('img');\n element.setAttribute('src', this.__src);\n element.setAttribute('alt', this.__altText);\n return { element };\n }\n\n static override importDOM(): DOMConversionMap | null {\n return {\n img: () => ({\n conversion: (domNode: HTMLElement) => {\n const src = domNode.getAttribute('src') || '';\n const alt = domNode.getAttribute('alt') || '';\n return { node: $createImageNode(src, alt) };\n },\n priority: 0,\n }),\n };\n }\n}\n\nexport const $createImageNode = (src: string, altText: string): ImageNode => {\n return new ImageNode(src, altText);\n};\n\nexport const $isImageNode = (node: LexicalNode | null | undefined): node is ImageNode => {\n return node instanceof ImageNode;\n};\n","import { useEffect } from 'react';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport type { NodeKey } from 'lexical';\nimport {\n $getNodeByKey,\n $insertNodes,\n COMMAND_PRIORITY_CRITICAL,\n DROP_COMMAND,\n PASTE_COMMAND,\n} from 'lexical';\n\nimport { toast } from '../../../components/Toast/toast';\nimport { useStableCallback } from '../../../hooks/useStableCallback';\nimport { $createImageNode, $isImageNode } from '../nodes/ImageNode';\n\nconst ACCEPTED_IMAGE_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n];\n\nconst MAX_IMAGE_SIZE = 10 * 1024 * 1024; // 10 MB\n\nconst PLACEHOLDER_PREFIX = 'upload-placeholder-';\n\nconst generatePlaceholderId = (): string => {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n};\n\nconst isAcceptedImageType = (type: string) => ACCEPTED_IMAGE_TYPES.includes(type);\n\nconst getImageFilesFromDataTransfer = (dataTransfer: DataTransfer | null): File[] => {\n if (!dataTransfer) return [];\n\n if (dataTransfer.items.length > 0) {\n const files: File[] = [];\n for (const item of dataTransfer.items) {\n if (item.kind === 'file' && isAcceptedImageType(item.type)) {\n const file = item.getAsFile();\n if (file) files.push(file);\n }\n }\n if (files.length > 0) return files;\n }\n\n return Array.from(dataTransfer.files).filter((file) => isAcceptedImageType(file.type));\n};\n\nconst escapeMarkdownAlt = (text: string) => text.replace(/[[\\]()]/g, '');\n\ntype ImagePastePluginProps = {\n onImageUpload?: (file: File) => Promise<{ url: string }>;\n};\n\nexport const ImagePastePlugin = ({ onImageUpload }: ImagePastePluginProps) => {\n const [editor] = useLexicalComposerContext();\n // Whether an uploader is configured at all — the commands below must decline\n // paste and drop when it isn't, so Lexical falls back to its default handling.\n // A boolean, so it only changes identity when the prop appears or disappears.\n const canUploadImages = onImageUpload != null;\n const uploadImage = useStableCallback((file: File) => onImageUpload?.(file));\n\n useEffect(() => {\n const uploadFile = (file: File) => {\n if (!canUploadImages) return;\n\n if (file.size > MAX_IMAGE_SIZE) {\n toast.error(`Image \"${file.name}\" is too large. Maximum size is 10 MB.`);\n return;\n }\n\n // Insert placeholder and start upload outside the command handler\n // to avoid nested editor.update() batching issues\n let nodeKey: NodeKey | null = null;\n\n editor.update(() => {\n const placeholderNode = $createImageNode(\n `${PLACEHOLDER_PREFIX}${generatePlaceholderId()}`,\n 'Uploading image\\u2026',\n );\n $insertNodes([placeholderNode]);\n nodeKey = placeholderNode.getKey();\n });\n\n if (!nodeKey) return;\n const capturedKey: NodeKey = nodeKey;\n\n uploadImage(file)\n ?.then(({ url }) => {\n editor.update(() => {\n const node = $getNodeByKey(capturedKey);\n if ($isImageNode(node)) {\n const altText = escapeMarkdownAlt(file.name.replace(/\\.[^.]+$/, '') || 'image');\n node.setSrc(url);\n node.setAlt(altText);\n }\n });\n })\n .catch((error: unknown) => {\n console.error('[MarkdownEditor] image upload failed', error);\n toast.error(`Failed to upload \"${file.name}\". Please try again.`);\n editor.update(() => {\n const node = $getNodeByKey(capturedKey);\n if (node) node.remove();\n });\n });\n };\n\n const removePaste = editor.registerCommand(\n PASTE_COMMAND,\n (event) => {\n if (!canUploadImages) return false;\n if (!(event instanceof ClipboardEvent)) return false;\n const files = getImageFilesFromDataTransfer(event.clipboardData);\n if (files.length === 0) return false;\n\n event.preventDefault();\n // Defer upload to next microtask to escape the command handler's update context\n Promise.resolve().then(() => files.forEach(uploadFile));\n return true;\n },\n COMMAND_PRIORITY_CRITICAL,\n );\n\n const removeDrop = editor.registerCommand(\n DROP_COMMAND,\n (event: DragEvent) => {\n if (!canUploadImages) return false;\n const files = getImageFilesFromDataTransfer(event.dataTransfer);\n if (files.length === 0) return false;\n\n event.preventDefault();\n // Defer upload to next microtask to escape the command handler's update context\n Promise.resolve().then(() => files.forEach(uploadFile));\n return true;\n },\n COMMAND_PRIORITY_CRITICAL,\n );\n\n return () => {\n removePaste();\n removeDrop();\n };\n }, [editor, canUploadImages, uploadImage]);\n\n return null;\n};\n","import { useEffect, useRef } from 'react';\nimport type { RefObject } from 'react';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { COMMAND_PRIORITY_HIGH, KEY_DOWN_COMMAND } from 'lexical';\n\nimport { useStableCallback } from '../../../hooks/useStableCallback';\n\ntype KeyboardPluginProps = {\n /** Invoked on Cmd/Ctrl+Enter, without blurring. */\n onSave?: () => void;\n /** Escape in inline-edit mode. Callers reset `value` to the last-committed state here. */\n onCancel?: () => void;\n /** Plain Enter blurs the editor instead of breaking the paragraph; Shift+Enter still breaks. */\n singleLine?: boolean;\n /** Escape blurs the editor. Inline-edit only; elsewhere a stray Esc must keep focus. */\n blurOnEscape?: boolean;\n /**\n * Set before the Escape blur so the blur handler skips `onSave` on the reverted value.\n * The consumer resets it on read.\n */\n skipBlurSaveRef?: RefObject<boolean>;\n};\n\nexport const KeyboardPlugin = ({\n onSave,\n onCancel,\n singleLine,\n blurOnEscape,\n skipBlurSaveRef,\n}: KeyboardPluginProps) => {\n const [editor] = useLexicalComposerContext();\n const handleSave = useStableCallback(() => onSave?.());\n const handleCancel = useStableCallback(() => onCancel?.());\n const singleLineRef = useRef(singleLine);\n singleLineRef.current = singleLine;\n const blurOnEscapeRef = useRef(blurOnEscape);\n blurOnEscapeRef.current = blurOnEscape;\n const skipBlurSaveExternalRef = skipBlurSaveRef;\n\n useEffect(() => {\n return editor.registerCommand(\n KEY_DOWN_COMMAND,\n (event: KeyboardEvent) => {\n if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {\n event.preventDefault();\n handleSave();\n return true;\n }\n if (event.key === 'Enter' && !event.shiftKey && !event.altKey && singleLineRef.current) {\n event.preventDefault();\n editor.getRootElement()?.blur();\n return true;\n }\n if (event.key === 'Escape' && blurOnEscapeRef.current) {\n if (skipBlurSaveExternalRef) skipBlurSaveExternalRef.current = true;\n handleCancel();\n editor.getRootElement()?.blur();\n return true;\n }\n return false;\n },\n COMMAND_PRIORITY_HIGH,\n );\n }, [editor, skipBlurSaveExternalRef, handleSave, handleCancel]);\n\n return null;\n};\n","import { lazy, Suspense } from 'react';\n\nimport { Skeleton } from '../../../components/Skeleton/Skeleton';\n\nconst MermaidDiagram = lazy(() =>\n import('../../../blocks/MermaidDiagram/MermaidDiagram').then(\n (m) => ({ default: m.MermaidDiagram }),\n (error: unknown) => {\n // Falling back to raw code on chunk-load failure (typically a stale tab after deploy).\n // Logging so we don't silently swap implementations.\n console.error('[MarkdownEditor] failed to load MermaidDiagram chunk', error);\n return {\n default: ({ code }: { code: string }) => (\n <pre>\n <code>{code}</code>\n </pre>\n ),\n };\n },\n ),\n);\n\nexport const MermaidNodeComponent = ({ code }: { code: string }) => {\n return (\n <Suspense\n fallback={\n <div className=\"tw:my-3 tw:overflow-hidden tw:rounded-card tw:border tw:border-neutral-150 tw:bg-neutral-50 tw:p-6\">\n <Skeleton className=\"tw:h-40\" />\n </div>\n }\n >\n <MermaidDiagram code={code} />\n </Suspense>\n );\n};\n","/* eslint-disable react/only-export-components -- Lexical convention: $create/$is helpers co-locate with node */\nimport type { ReactNode } from 'react';\nimport type { LexicalNode, NodeKey, SerializedLexicalNode, Spread } from 'lexical';\nimport { DecoratorNode } from 'lexical';\n\nimport { MermaidNodeComponent } from './MermaidNodeComponent';\n\ntype SerializedMermaidNode = Spread<{ code: string }, SerializedLexicalNode>;\n\nexport class MermaidNode extends DecoratorNode<ReactNode> {\n __code: string;\n\n static override getType(): string {\n return 'mermaid';\n }\n\n static override clone(node: MermaidNode): MermaidNode {\n return new MermaidNode(node.__code, node.__key);\n }\n\n constructor(code: string, key?: NodeKey) {\n super(key);\n this.__code = code;\n }\n\n getCode(): string {\n return this.__code;\n }\n\n setCode(code: string): void {\n const writable = this.getWritable();\n writable.__code = code;\n }\n\n override createDOM(): HTMLElement {\n const div = document.createElement('div');\n div.setAttribute('data-lexical-mermaid', 'true');\n return div;\n }\n\n override updateDOM(): boolean {\n return false;\n }\n\n override decorate(): ReactNode {\n return <MermaidNodeComponent code={this.__code} />;\n }\n\n override isInline(): boolean {\n return false;\n }\n\n static override importJSON(serializedNode: SerializedMermaidNode): MermaidNode {\n return $createMermaidNode(serializedNode.code);\n }\n\n override exportJSON(): SerializedMermaidNode {\n return {\n type: 'mermaid',\n version: 1,\n code: this.__code,\n };\n }\n}\n\nexport const $createMermaidNode = (code: string): MermaidNode => {\n return new MermaidNode(code);\n};\n\nexport const $isMermaidNode = (node: LexicalNode | null | undefined): node is MermaidNode => {\n return node instanceof MermaidNode;\n};\n","import { CodeNode } from '@lexical/code';\nimport { AutoLinkNode, LinkNode } from '@lexical/link';\nimport { ListItemNode, ListNode } from '@lexical/list';\nimport { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';\nimport { HeadingNode, QuoteNode } from '@lexical/rich-text';\n\nimport { ImageNode } from './nodes/ImageNode';\nimport { MermaidNode } from './nodes/MermaidNode';\n\n/**\n * Every node the editor registers, shared by the composer and the paste parser.\n *\n * - `AutoLinkNode` is registered always; only `autoLink` mounts the plugin that creates one.\n */\nexport const EDITOR_NODES = [\n ImageNode,\n MermaidNode,\n HeadingNode,\n QuoteNode,\n ListNode,\n ListItemNode,\n CodeNode,\n LinkNode,\n AutoLinkNode,\n HorizontalRuleNode,\n];\n","import type { LinkMatcher } from '@lexical/link';\n\n/** One bare URL or email address in a text: `text` is what GFM links, `url` its address. */\ntype BareUrl = { index: number; text: string; url: string };\n\n// The shapes of micromark-extension-gfm-autolink-literal, which `remark-gfm` runs.\nconst DOMAIN_CHAR = String.raw`(?:[^\\s\\p{P}\\p{S}]|-)`;\nconst DOMAIN = String.raw`${DOMAIN_CHAR}+(?:[._]${DOMAIN_CHAR}+)*`;\nconst URL_START = String.raw`(?:[hH][tT][tT][pP][sS]?:\\/\\/|[wW][wW][wW]\\.)`;\nconst URL_BODY = String.raw`${URL_START}${DOMAIN}[^\\s<]*`;\nconst EMAIL_BODY = String.raw`[\\w.+-]+@[\\w-]+(?:\\.[\\w-]+)+`;\n// Lookbehinds hold GFM's rule for the character before each kind, and keep the scan linear.\nconst CANDIDATE = new RegExp(\n String.raw`(?<![a-zA-Z])(?=[hH])${URL_BODY}|(?<=^|[\\s(*_[\\]~])(?=[wW])${URL_BODY}|(?<![\\w.+/-])${EMAIL_BODY}`,\n 'gu',\n);\nconst URL_DOMAIN = new RegExp(String.raw`^${URL_START}(${DOMAIN})`, 'u');\nconst TRAILING_PUNCTUATION = /[!\"'*,.:;?_~\\]]$/;\nconst TRAILING_ENTITY = /&[a-zA-Z][a-zA-Z0-9]*;$/;\n\nconst count = (text: string, char: string) => text.split(char).length - 1;\n\nconst trimTrailing = (candidate: string): string => {\n let text = candidate;\n for (;;) {\n const entity = TRAILING_ENTITY.exec(text);\n if (entity) text = text.slice(0, -entity[0].length);\n else if (TRAILING_PUNCTUATION.test(text)) text = text.slice(0, -1);\n else if (text.endsWith(')') && count(text, ')') > count(text, '(')) text = text.slice(0, -1);\n else return text;\n }\n};\n\n// GFM rejects a domain with `_` in either of its last two dot-separated segments.\nconst hasLinkableDomain = (url: string): boolean => {\n const domain = URL_DOMAIN.exec(url)?.[1];\n return (\n domain !== undefined &&\n !domain\n .split('.')\n .slice(-2)\n .some((part) => part.includes('_'))\n );\n};\n\n/**\n * The bare URLs and email addresses in `text`, as GFM's autolink extension finds them.\n *\n * - `http://`, `https://` or `www.` and a domain, then anything up to whitespace or `<`.\n * - Trailing `!\"'*,.:;?_~]`, an unbalanced `)` and an entity like `&amp;` stay outside.\n * - `http(s)://` starts after anything but a letter, `www.` only after whitespace or `(*_[]~`.\n * - An email ending in `-` or `_` is not one.\n */\nexport const findBareUrls = (text: string, limit = Infinity): BareUrl[] => {\n const found: BareUrl[] = [];\n for (const match of text.matchAll(CANDIDATE)) {\n const source = match[0];\n if (/^(?:https?:\\/\\/|www\\.)/i.test(source)) {\n const trimmed = trimTrailing(source);\n if (!hasLinkableDomain(trimmed)) continue;\n const url = /^www\\./i.test(trimmed) ? `https://${trimmed}` : trimmed;\n found.push({ index: match.index, text: trimmed, url });\n } else if (!/[-_]$/.test(source)) {\n found.push({ index: match.index, text: source, url: `mailto:${source}` });\n }\n if (found.length >= limit) break;\n }\n return found;\n};\n\n/**\n * Every stretch of `text` GFM starts scanning as a URL or email, linked in the end or not.\n *\n * - Export writes these raw: GFM scans the run before trimming its end, and an escape moves where\n * it ends a domain, so `https://a\\_b.c\\_d` is linked with its backslashes, `https://a_b.c_d` is not.\n */\nexport const findUrlRuns = (text: string) =>\n Array.from(text.matchAll(CANDIDATE), (match) => ({ index: match.index, source: match[0] }));\n\n/**\n * A `RegExp` whose `String#match` is the first URL `findBareUrls` finds, for Lexical's `importRegExp`.\n *\n * - Lexical's markdown import reads `importRegExp` only through `text.match(importRegExp)`.\n * - So a candidate GFM rejects (`https://a_b.c_d`) never hides a valid URL after it.\n */\nclass FirstBareUrl extends RegExp {\n override [Symbol.match](text: string): RegExpMatchArray | null {\n const [url] = findBareUrls(text, 1);\n if (!url) return null;\n const match: [string] = [url.text];\n return Object.assign(match, { index: url.index, input: text });\n }\n}\n\nexport const FIRST_BARE_URL = new FirstBareUrl(CANDIDATE.source, 'u');\n\n/** Lexical `AutoLinkPlugin` matcher: the first bare URL in the text, as `findBareUrls` reads it. */\nexport const matchBareUrl: LinkMatcher = (text) => {\n const [first] = findBareUrls(text, 1);\n return first\n ? { index: first.index, length: first.text.length, text: first.text, url: first.url }\n : null;\n};\n","import { $isAutoLinkNode, $isLinkNode } from '@lexical/link';\nimport type {\n ElementTransformer,\n MultilineElementTransformer,\n TextMatchTransformer,\n Transformer,\n} from '@lexical/markdown';\nimport { $convertFromMarkdownString, CHECK_LIST, TRANSFORMERS } from '@lexical/markdown';\nimport {\n $createHorizontalRuleNode,\n $isHorizontalRuleNode,\n HorizontalRuleNode,\n} from '@lexical/react/LexicalHorizontalRuleNode';\nimport { $createTextNode, $isTextNode } from 'lexical';\n\nimport { $createImageNode, $isImageNode, ImageNode } from './nodes/ImageNode';\nimport { $createMermaidNode, $isMermaidNode, MermaidNode } from './nodes/MermaidNode';\nimport { findUrlRuns, FIRST_BARE_URL } from './bareUrls';\n\n/** Markdown image: `![alt](src)` */\nconst IMAGE: TextMatchTransformer = {\n dependencies: [ImageNode],\n export: (node) => {\n if (!$isImageNode(node)) return null;\n return `![${node.getAlt()}](${node.getSrc()})`;\n },\n importRegExp: /!\\[([^\\]]*)\\]\\(([^)]+)\\)/,\n regExp: /!\\[([^\\]]*)\\]\\(([^)]+)\\)$/,\n replace: (textNode, match) => {\n const [, alt = '', src = ''] = match;\n const imageNode = $createImageNode(src, alt);\n textNode.replace(imageNode);\n },\n trigger: ')',\n type: 'text-match',\n};\n\n/** Horizontal rule: `---`, `***`, or `___` */\nconst HORIZONTAL_RULE: ElementTransformer = {\n dependencies: [HorizontalRuleNode],\n export: (node) => {\n return $isHorizontalRuleNode(node) ? '---' : null;\n },\n regExp: /^(---|\\*\\*\\*|___)$/,\n replace: (parentNode) => {\n const node = $createHorizontalRuleNode();\n parentNode.replace(node);\n },\n type: 'element',\n};\n\n/** Fenced mermaid block: ` ```mermaid ... ``` ` → MermaidNode (rendered as diagram) */\nconst MERMAID: MultilineElementTransformer = {\n dependencies: [MermaidNode],\n export: (node) => {\n if (!$isMermaidNode(node)) return null;\n return '```mermaid\\n' + node.getCode() + '\\n```';\n },\n regExpStart: /^[ \\t]*(`{3,})mermaid(?:\\s.*)?$/,\n regExpEnd: {\n optional: true,\n regExp: /^[ \\t]*`{3,}$/,\n },\n replace: (rootNode, _children, _startMatch, _endMatch, linesInBetween) => {\n if (!linesInBetween) return;\n const code = linesInBetween.join('\\n').trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n },\n handleImportAfterStartMatch: ({\n lines,\n rootNode,\n startLineIndex,\n startMatch,\n }): [boolean, number] => {\n const fence = startMatch[1];\n if (!fence) return [false, startLineIndex];\n const fenceLength = fence.trim().length;\n const endRegex = new RegExp(`^[ \\\\t]*\\`{${fenceLength},}$`);\n\n for (let i = startLineIndex + 1; i < lines.length; i++) {\n if (endRegex.test(lines[i] ?? '')) {\n const code = lines\n .slice(startLineIndex + 1, i)\n .join('\\n')\n .trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n return [true, i];\n }\n }\n\n // No closing fence — consume remaining lines\n const code = lines\n .slice(startLineIndex + 1)\n .join('\\n')\n .trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n return [true, lines.length - 1];\n },\n type: 'multiline-element',\n};\n\n/**\n * Our transformers plus Lexical's built-ins; order matters.\n *\n * - MERMAID precedes TRANSFORMERS, so it wins over the generic CODE transformer.\n * - IMAGE precedes LINK, so `![alt](url)` is not parsed as `!` + link.\n */\nexport const CUSTOM_TRANSFORMERS: Transformer[] = [\n IMAGE,\n HORIZONTAL_RULE,\n CHECK_LIST,\n MERMAID,\n ...TRANSFORMERS,\n];\n\n// Private-use code points: escaping and the whitespace trim in `exportFormat` leave them alone.\nconst urlPlaceholder = (index: number) => `\\uE000${index}\\uE001`;\nconst URL_PLACEHOLDER = /\\uE000(\\d+)\\uE001/g;\n\n/**\n * Bare URLs and email addresses stay literal on import and export as typed (`a_b`, not `a\\_b`).\n *\n * - Import: no emphasis inside one (`?a=*x*`), and Lexical's own escapes (`a\\_b`) are dropped.\n * - Export: an autolink's text and every `findUrlRuns` stretch are written raw, as is the text after\n * an autolink up to whitespace, which GFM scans as part of the same link.\n * - No `trigger`, so typing shortcuts skip it; `regExp` is required by the type and never matches.\n * - Inline code and the label of a `[text](url)` link keep the stock export.\n */\nconst BARE_URL: TextMatchTransformer = {\n dependencies: [],\n importRegExp: FIRST_BARE_URL,\n replace: (node) => {\n const literal = $createTextNode(unescapeMarkdownText(node.getTextContent()));\n literal.setFormat(node.getFormat());\n // A new node: Lexical unescapes the text node it started from once more, after this.\n node.replace(literal);\n },\n export: (node, _exportChildren, exportFormat) => {\n if (!$isTextNode(node) || node.hasFormat('code')) return null;\n const parent = node.getParent();\n if ($isLinkNode(parent) && !$isAutoLinkNode(parent)) return null;\n const text = node.getTextContent();\n if (text.includes('\\uE000')) return null;\n const afterAutoLink = $isAutoLinkNode(node.getPreviousSibling());\n const lead = afterAutoLink ? (/^[^\\s<]+/.exec(text)?.[0] ?? '') : '';\n const urls = $isAutoLinkNode(parent)\n ? [{ index: 0, source: text }]\n : [\n ...(lead ? [{ index: 0, source: lead }] : []),\n ...findUrlRuns(text).filter((url) => url.index >= lead.length),\n ];\n if (urls.length === 0) return null;\n let masked = '';\n let end = 0;\n urls.forEach((url, i) => {\n masked += text.slice(end, url.index) + urlPlaceholder(i);\n end = url.index + url.source.length;\n });\n masked += text.slice(end);\n return exportFormat(node, masked).replace(\n URL_PLACEHOLDER,\n (_, i) => urls[Number(i)]?.source ?? '',\n );\n },\n regExp: /(?!)/,\n type: 'text-match',\n};\n\n/** `CUSTOM_TRANSFORMERS` plus bare URLs, for `autoLink`. */\nexport const AUTO_LINK_TRANSFORMERS: Transformer[] = [BARE_URL, ...CUSTOM_TRANSFORMERS];\n\n/**\n * No transformers: `singleLine` mode edits plain-text entity names, not markdown.\n *\n * - Inline formatting would corrupt names like `a_b_c` (italics, then `\\_` on export).\n * - Pair with `unescapeMarkdownText` on export (see MarkdownSyncPlugin).\n */\nexport const SINGLE_LINE_TRANSFORMERS: Transformer[] = [];\n\n// GFM tables have no Lexical transformer: fenced on import, unfenced on export.\n\nconst TABLE_FENCE_LANG = '__kbc_table__';\n\nconst isTableLine = (line: string): boolean => {\n const trimmed = line.trim();\n return trimmed.startsWith('|') && trimmed.endsWith('|');\n};\n\nconst CODE_FENCE_REGEX = /^[ \\t]*`{3,}/;\n\n/** Wrap GFM tables in code fences so they survive Lexical's markdown round-trip. */\nexport const preprocessMarkdown = (markdown: string): string => {\n const lines = markdown.split('\\n');\n const result: string[] = [];\n let tableLines: string[] = [];\n let insideCodeFence = false;\n\n const flushTable = () => {\n if (tableLines.length >= 2) {\n result.push(`\\`\\`\\`${TABLE_FENCE_LANG}`);\n result.push(...tableLines);\n result.push('```');\n } else {\n // Single pipe line isn't a table — keep as-is\n result.push(...tableLines);\n }\n tableLines = [];\n };\n\n for (const line of lines) {\n if (CODE_FENCE_REGEX.test(line)) {\n if (tableLines.length > 0) flushTable();\n insideCodeFence = !insideCodeFence;\n result.push(line);\n continue;\n }\n\n if (insideCodeFence) {\n result.push(line);\n continue;\n }\n\n if (isTableLine(line)) {\n tableLines.push(line);\n } else {\n if (tableLines.length > 0) flushTable();\n result.push(line);\n }\n }\n if (tableLines.length > 0) flushTable();\n\n return result.join('\\n');\n};\n\n/** Replaces the root with `markdown`: the one import a load, a `value` change and a paste share. */\nexport const $importMarkdown = (markdown: string, transformers: Transformer[]) => {\n $convertFromMarkdownString(preprocessMarkdown(markdown), transformers);\n};\n\n/** Unwrap code-fenced tables back to raw GFM table markdown. */\nexport const postprocessMarkdown = (markdown: string): string => {\n const regex = new RegExp(`\\`\\`\\`${TABLE_FENCE_LANG}\\\\n([\\\\s\\\\S]*?)\\\\n\\`\\`\\``, 'g');\n return markdown.replace(regex, '$1');\n};\n\n/** Reverses Lexical's export escaping of `* _ ` ~ \\`, for `singleLine` plain-text names. */\nexport const unescapeMarkdownText = (markdown: string): string =>\n markdown.replace(/\\\\([*_`~\\\\])/g, '$1');\n","import { useEffect } from 'react';\nimport { $isCodeNode } from '@lexical/code';\nimport type { Transformer } from '@lexical/markdown';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { $findMatchingParent } from '@lexical/utils';\nimport type { LexicalNode, RangeSelection, SerializedLexicalNode } from 'lexical';\nimport {\n $addUpdateTag,\n $createParagraphNode,\n $getSelection,\n $isParagraphNode,\n $isRangeSelection,\n $parseSerializedNode,\n COMMAND_PRIORITY_LOW,\n createEditor,\n HISTORY_PUSH_TAG,\n PASTE_COMMAND,\n PASTE_TAG,\n} from 'lexical';\n\nimport { EDITOR_NODES } from '../editorNodes';\nimport { $importMarkdown } from '../transformers';\n\n/**\n * `markdown` as the top-level nodes the editor's own import makes of it.\n *\n * - Runs in a scratch editor: `$importMarkdown` replaces the root it imports into,\n * and only nodes attached to a root get their lines merged into one paragraph.\n */\nconst parseMarkdown = (markdown: string, transformers: Transformer[]): SerializedLexicalNode[] => {\n const scratch = createEditor({\n namespace: 'MarkdownEditorPaste',\n nodes: EDITOR_NODES,\n onError: (error: Error) => {\n throw error;\n },\n });\n scratch.update(\n () => {\n $importMarkdown(markdown, transformers);\n },\n { discrete: true },\n );\n return scratch.getEditorState().toJSON().root.children;\n};\n\n/**\n * Inserts parsed blocks at the selection, keeping a first or last block that is not a paragraph whole.\n *\n * - `insertNodes` merges the first block into a non-empty line and the rest of the line into the\n * last block, which would flatten a fence pasted after `Logs:` into plain text.\n * - An empty paragraph first is never merged, so the block after it goes in whole; it is then removed.\n * - An empty paragraph last takes the rest of the line, and is removed when there was none.\n */\nconst $insertBlocks = (selection: RangeSelection, nodes: LexicalNode[]) => {\n const first = nodes[0];\n const last = nodes.at(-1);\n if (!first || !last) return;\n const head = $isParagraphNode(first) ? null : $createParagraphNode();\n const tail = $isParagraphNode(last) ? null : $createParagraphNode();\n selection.insertNodes([head, ...nodes, tail].filter((node) => node !== null));\n head?.remove();\n if (!tail) return;\n if (tail.isEmpty()) {\n tail.remove();\n last.selectEnd();\n } else {\n tail.selectStart();\n }\n};\n\ntype MarkdownPastePluginProps = {\n /** The set the editor imports `value` with, so a paste reads like a load. */\n transformers: Transformer[];\n};\n\n/**\n * Parses a plain-text paste as markdown and inserts the result at the selection.\n *\n * - Only for a clipboard with `text/plain` and neither `text/html` nor files; those keep\n * Lexical's own paste, and files stay for the image uploader or the consumer.\n * - Inside a code block the text goes in literally, through the same fallback.\n * - One undo step: the update is tagged `history-push`.\n */\nexport const MarkdownPastePlugin = ({ transformers }: MarkdownPastePluginProps) => {\n const [editor] = useLexicalComposerContext();\n\n useEffect(() => {\n return editor.registerCommand(\n PASTE_COMMAND,\n (event) => {\n const data = 'clipboardData' in event ? event.clipboardData : null;\n if (!data || data.files.length > 0 || data.types.includes('text/html')) return false;\n const text = data.getData('text/plain').replace(/\\r\\n?/g, '\\n');\n if (!text) return false;\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return false;\n const inCode = [selection.anchor, selection.focus].some((point) =>\n $findMatchingParent(point.getNode(), $isCodeNode),\n );\n if (inCode) return false;\n\n event.preventDefault();\n $addUpdateTag(PASTE_TAG);\n $addUpdateTag(HISTORY_PUSH_TAG);\n $insertBlocks(selection, parseMarkdown(text, transformers).map($parseSerializedNode));\n return true;\n },\n COMMAND_PRIORITY_LOW,\n );\n }, [editor, transformers]);\n\n return null;\n};\n","import { useEffect, useRef } from 'react';\nimport type { Transformer } from '@lexical/markdown';\nimport { $convertToMarkdownString } from '@lexical/markdown';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\n\nimport { useStableCallback } from '../../../hooks/useStableCallback';\nimport {\n $importMarkdown,\n CUSTOM_TRANSFORMERS,\n postprocessMarkdown,\n unescapeMarkdownText,\n} from '../transformers';\n\nconst IMPORT_TAG = 'markdown-import';\n\ntype MarkdownSyncPluginProps = {\n value: string;\n editable: boolean;\n onChange?: (markdown: string) => void;\n transformers?: Transformer[];\n /**\n * Plain-text mode: export a bare entity name instead of markdown. Unescapes the punctuation\n * Lexical escapes on export (`\\_` → `_`), so names with underscores don't persist backslashes.\n */\n singleLine?: boolean;\n};\n\nexport const MarkdownSyncPlugin = ({\n value,\n editable,\n onChange,\n transformers = CUSTOM_TRANSFORMERS,\n singleLine = false,\n}: MarkdownSyncPluginProps) => {\n const [editor] = useLexicalComposerContext();\n const lastExportedRef = useRef(value);\n const handleChange = useStableCallback((markdown: string) => onChange?.(markdown));\n const transformersRef = useRef(transformers);\n transformersRef.current = transformers;\n const singleLineRef = useRef(singleLine);\n singleLineRef.current = singleLine;\n\n // Sync editable state — only when it actually changes\n useEffect(() => {\n editor.setEditable(editable);\n }, [editor, editable]);\n\n // Import: external value -> editor state\n useEffect(() => {\n if (value === lastExportedRef.current) return;\n lastExportedRef.current = value;\n\n editor.update(\n () => {\n $importMarkdown(value, transformersRef.current);\n },\n { tag: IMPORT_TAG },\n );\n }, [editor, value]);\n\n // Export: editor state -> onChange (subscription)\n useEffect(() => {\n return editor.registerUpdateListener(({ tags }) => {\n if (tags.has(IMPORT_TAG)) return;\n\n editor.getEditorState().read(() => {\n const raw = $convertToMarkdownString(transformersRef.current);\n const markdown = singleLineRef.current\n ? unescapeMarkdownText(raw)\n : postprocessMarkdown(raw);\n if (markdown !== lastExportedRef.current) {\n lastExportedRef.current = markdown;\n handleChange(markdown);\n }\n });\n });\n }, [editor, handleChange]);\n\n return null;\n};\n","import { useRef } from 'react';\nimport {\n $getSelection,\n $setSelection,\n type BaseSelection,\n type ElementFormatType,\n FORMAT_ELEMENT_COMMAND,\n type LexicalEditor,\n} from 'lexical';\n\nimport { DropdownMenu } from '../../../../components/DropdownMenu';\nimport { Tooltip } from '../../../../components/Tooltip';\nimport {\n AlignCenter,\n AlignJustify,\n AlignLeft,\n AlignRight,\n ChevronDown,\n type LucideIcon,\n} from '../../../../icons';\nimport { cn } from '../../../../utils';\n\nconst ALIGNMENT_OPTIONS: { value: ElementFormatType; label: string; icon: LucideIcon }[] = [\n { value: 'left', label: 'Left', icon: AlignLeft },\n { value: 'center', label: 'Center', icon: AlignCenter },\n { value: 'right', label: 'Right', icon: AlignRight },\n { value: 'justify', label: 'Justify', icon: AlignJustify },\n];\n\nconst ALIGNMENT_ICONS: Record<string, LucideIcon> = Object.fromEntries(\n ALIGNMENT_OPTIONS.map(({ value, icon }) => [value, icon]),\n);\n\nexport const AlignmentDropdown = ({\n editor,\n alignment,\n}: {\n editor: LexicalEditor;\n alignment: ElementFormatType;\n}) => {\n const savedSelectionRef = useRef<BaseSelection | null>(null);\n\n const handleOpenChange = (open: boolean) => {\n if (open) {\n editor.getEditorState().read(() => {\n const selection = $getSelection();\n savedSelectionRef.current = selection ? selection.clone() : null;\n });\n }\n };\n\n const handleSelect = (align: ElementFormatType) => {\n // Restore selection and dispatch within the same update so the command sees\n // the restored selection (otherwise dispatchCommand may race with the queued\n // $setSelection and apply the format to the wrong block).\n editor.update(() => {\n if (savedSelectionRef.current) {\n $setSelection(savedSelectionRef.current);\n }\n editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, align);\n });\n };\n\n const CurrentAlignmentIcon = ALIGNMENT_ICONS[alignment] ?? AlignLeft;\n\n return (\n <DropdownMenu onOpenChange={handleOpenChange}>\n <Tooltip tooltip=\"Text alignment\" placement=\"top\" triggerAsChild>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'tw:flex tw:h-7 tw:cursor-pointer tw:items-center tw:gap-1 tw:rounded tw:border-0 tw:bg-transparent tw:px-1.5 tw:text-xs tw:text-muted-foreground',\n 'tw:hover:bg-accent',\n )}\n >\n <CurrentAlignmentIcon className=\"tw:size-4\" />\n <ChevronDown className=\"tw:size-3\" />\n </button>\n </DropdownMenu.Trigger>\n </Tooltip>\n <DropdownMenu.Content align=\"start\" className=\"tw:min-w-32\">\n {ALIGNMENT_OPTIONS.map(({ value, label, icon: IconComp }) => (\n <DropdownMenu.Item\n key={value}\n onSelect={() => handleSelect(value)}\n className={cn(\n 'tw:flex tw:items-center tw:gap-2',\n alignment === value && 'tw:bg-secondary-50 tw:text-secondary-500',\n )}\n >\n <IconComp className=\"tw:size-4\" />\n {label}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu>\n );\n};\n","import { useRef } from 'react';\nimport { $createCodeNode } from '@lexical/code';\nimport { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list';\nimport { $createHeadingNode, $createQuoteNode } from '@lexical/rich-text';\nimport { $getNearestBlockElementAncestorOrThrow } from '@lexical/utils';\nimport {\n $createParagraphNode,\n $getSelection,\n $isRangeSelection,\n $setSelection,\n type BaseSelection,\n type LexicalEditor,\n} from 'lexical';\n\nimport { DropdownMenu } from '../../../../components/DropdownMenu';\nimport { Tooltip } from '../../../../components/Tooltip';\nimport {\n ChevronDown,\n Heading1,\n Heading2,\n Heading3,\n List as ListIcon,\n ListOrdered,\n type LucideIcon,\n Quote,\n SquareCode,\n Type,\n} from '../../../../icons';\nimport { cn } from '../../../../utils';\n\nconst BLOCK_TYPE_META = {\n paragraph: { label: 'Normal', icon: Type satisfies LucideIcon, selectable: true },\n h1: { label: 'Heading 1', icon: Heading1 satisfies LucideIcon, selectable: true },\n h2: { label: 'Heading 2', icon: Heading2 satisfies LucideIcon, selectable: true },\n h3: { label: 'Heading 3', icon: Heading3 satisfies LucideIcon, selectable: true },\n bullet: { label: 'Bullet List', icon: ListIcon satisfies LucideIcon, selectable: false },\n number: { label: 'Numbered List', icon: ListOrdered satisfies LucideIcon, selectable: false },\n quote: { label: 'Quote', icon: Quote satisfies LucideIcon, selectable: false },\n code: { label: 'Code Block', icon: SquareCode satisfies LucideIcon, selectable: false },\n} as const;\n\ntype BlockType = keyof typeof BLOCK_TYPE_META;\n\nconst BLOCK_TYPE_OPTIONS = (\n Object.entries(BLOCK_TYPE_META) as [BlockType, (typeof BLOCK_TYPE_META)[BlockType]][]\n)\n .filter(([, meta]) => meta.selectable)\n .map(([value, { label, icon }]) => ({ value, label, icon }));\n\nconst isBlockType = (value: string): value is BlockType =>\n Object.prototype.hasOwnProperty.call(BLOCK_TYPE_META, value);\n\nexport const BlockTypeDropdown = ({\n editor,\n blockType,\n}: {\n editor: LexicalEditor;\n blockType: string;\n}) => {\n const savedSelectionRef = useRef<BaseSelection | null>(null);\n const currentMeta = isBlockType(blockType) ? BLOCK_TYPE_META[blockType] : null;\n const CurrentBlockIcon = currentMeta?.icon ?? Type;\n\n const handleOpenChange = (open: boolean) => {\n if (open) {\n editor.getEditorState().read(() => {\n const selection = $getSelection();\n savedSelectionRef.current = selection ? selection.clone() : null;\n });\n }\n };\n\n const handleSelect = (type: BlockType) => {\n editor.update(() => {\n if (savedSelectionRef.current) {\n $setSelection(savedSelectionRef.current);\n }\n\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n\n if (type === 'bullet') {\n editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);\n return;\n }\n if (type === 'number') {\n editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);\n return;\n }\n\n const anchorNode = selection.anchor.getNode();\n const element = $getNearestBlockElementAncestorOrThrow(anchorNode);\n\n const newNode =\n type === 'h1' || type === 'h2' || type === 'h3'\n ? $createHeadingNode(type)\n : type === 'quote'\n ? $createQuoteNode()\n : type === 'code'\n ? $createCodeNode()\n : $createParagraphNode();\n\n element.getChildren().forEach((child) => newNode.append(child));\n element.replace(newNode);\n });\n };\n\n return (\n <DropdownMenu onOpenChange={handleOpenChange}>\n <Tooltip tooltip=\"Change block type\" placement=\"top\" triggerAsChild>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'tw:flex tw:h-7 tw:cursor-pointer tw:items-center tw:gap-1.5 tw:rounded tw:border-0 tw:bg-transparent tw:px-1.5 tw:text-xs tw:text-muted-foreground',\n 'tw:hover:bg-accent',\n )}\n >\n <CurrentBlockIcon className=\"tw:size-4\" />\n {currentMeta?.label ?? 'Normal'}\n <ChevronDown className=\"tw:size-3\" />\n </button>\n </DropdownMenu.Trigger>\n </Tooltip>\n <DropdownMenu.Content align=\"start\" className=\"tw:min-w-40\">\n {BLOCK_TYPE_OPTIONS.map(({ value, label, icon: IconComp }) => (\n <DropdownMenu.Item\n key={value}\n onSelect={() => handleSelect(value)}\n className={cn(\n 'tw:flex tw:items-center tw:gap-2',\n blockType === value && 'tw:bg-secondary-50 tw:text-secondary-500',\n )}\n >\n <IconComp className=\"tw:size-4\" />\n {label}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu>\n );\n};\n","import type { ReactNode } from 'react';\n\nimport { Tooltip } from '../../../../components/Tooltip';\nimport { cn } from '../../../../utils';\n\nexport const ToolbarButton = ({\n active,\n disabled,\n onClick,\n tooltip,\n children,\n className: extraClassName,\n}: {\n active?: boolean;\n disabled?: boolean;\n onClick: () => void;\n tooltip: ReactNode;\n children: ReactNode;\n className?: string;\n}) => (\n <Tooltip tooltip={tooltip} placement=\"top\" triggerAsChild>\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onClick}\n className={cn(\n 'tw:flex tw:h-7 tw:min-w-7 tw:cursor-pointer tw:items-center tw:justify-center tw:rounded tw:border-0 tw:bg-transparent tw:px-1 tw:text-xs tw:text-muted-foreground',\n 'tw:hover:bg-accent tw:disabled:cursor-not-allowed tw:disabled:opacity-30',\n active && 'tw:bg-secondary-100 tw:text-secondary-500',\n extraClassName,\n )}\n >\n {children}\n </button>\n </Tooltip>\n);\n","import { useRef, useState } from 'react';\nimport type { KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport { $createLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';\nimport {\n $createTextNode,\n $getSelection,\n $isRangeSelection,\n $setSelection,\n type BaseSelection,\n type LexicalEditor,\n} from 'lexical';\n\nimport { FormGroup } from '../../../../blocks/FormGroup';\nimport { TextInput } from '../../../../blocks/TextInput';\nimport { Button } from '../../../../components/Button';\nimport { ButtonGroup } from '../../../../components/ButtonGroup';\nimport { Label } from '../../../../components/Label';\nimport { Link as LinkIcon } from '../../../../icons';\n\nimport { ToolbarButton } from './ToolbarButton';\n\nconst insertLink = (\n editor: LexicalEditor,\n url: string,\n label: string,\n savedSelection: BaseSelection | null,\n) => {\n editor.update(() => {\n $setSelection(savedSelection);\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n const selectedText = selection.getTextContent();\n if (selectedText && label === selectedText) {\n editor.dispatchCommand(TOGGLE_LINK_COMMAND, url);\n return;\n }\n }\n\n const linkNode = $createLinkNode(url);\n const textNode = $createTextNode(label || url);\n linkNode.append(textNode);\n\n if ($isRangeSelection(selection)) {\n selection.insertNodes([linkNode]);\n }\n });\n};\n\nexport const LinkPanel = ({ editor, isLink }: { editor: LexicalEditor; isLink: boolean }) => {\n const [open, setOpen] = useState(false);\n const [url, setUrl] = useState('');\n const [label, setLabel] = useState('');\n const savedSelectionRef = useRef<BaseSelection | null>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n\n const handleOpen = () => {\n editor.getEditorState().read(() => {\n const selection = $getSelection();\n savedSelectionRef.current = selection ? selection.clone() : null;\n\n if ($isRangeSelection(selection)) {\n const text = selection.getTextContent();\n if (text) setLabel(text);\n }\n });\n setOpen(true);\n };\n\n const handleClose = () => {\n setOpen(false);\n setUrl('');\n setLabel('');\n savedSelectionRef.current = null;\n editor.focus();\n };\n\n const handleSubmit = () => {\n const trimmedUrl = url.trim();\n if (!trimmedUrl) return;\n\n insertLink(editor, trimmedUrl, label.trim(), savedSelectionRef.current);\n handleClose();\n };\n\n const handleKeyDown = (e: ReactKeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n handleSubmit();\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n handleClose();\n }\n };\n\n if (isLink) {\n return (\n <ToolbarButton\n active\n onClick={() => editor.dispatchCommand(TOGGLE_LINK_COMMAND, null)}\n tooltip=\"Remove Link\"\n >\n <LinkIcon className=\"tw:size-4\" />\n </ToolbarButton>\n );\n }\n\n return (\n <div className=\"tw:relative\">\n <ToolbarButton active={open} onClick={handleOpen} tooltip=\"Insert Link\">\n <LinkIcon className=\"tw:size-4\" />\n </ToolbarButton>\n {open && (\n <div\n ref={panelRef}\n className=\"tw:absolute tw:left-0 tw:top-full tw:z-50 tw:mt-1 tw:w-80 tw:rounded-md tw:border tw:border-border tw:bg-popover tw:p-3 tw:text-popover-foreground tw:shadow-lg\"\n >\n <div className=\"tw:flex tw:flex-col tw:gap-2\">\n <FormGroup>\n <Label htmlFor=\"link-label\" className=\"tw:mb-1 tw:text-xs\">\n Label\n </Label>\n <TextInput\n id=\"link-label\"\n autoFocus\n placeholder=\"Link text\"\n value={label}\n onValueChange={setLabel}\n onKeyDown={handleKeyDown}\n variant=\"secondary\"\n />\n </FormGroup>\n <FormGroup>\n <Label htmlFor=\"link-url\" className=\"tw:mb-1 tw:text-xs\">\n URL\n </Label>\n <TextInput\n id=\"link-url\"\n placeholder=\"https://…\"\n value={url}\n onValueChange={setUrl}\n onKeyDown={handleKeyDown}\n variant=\"secondary\"\n />\n </FormGroup>\n <ButtonGroup>\n <Button size=\"small\" variant=\"outline\" onClick={handleClose}>\n Cancel\n </Button>\n <Button size=\"small\" onClick={handleSubmit} disabled={!url.trim()}>\n Add link\n </Button>\n </ButtonGroup>\n </div>\n </div>\n )}\n </div>\n );\n};\n","export const ToolbarDivider = () => <div className=\"tw:mx-0.5 tw:h-5 tw:w-px tw:bg-border\" />;\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { $createCodeNode, $isCodeNode } from '@lexical/code';\nimport { $isLinkNode } from '@lexical/link';\nimport {\n $isListNode,\n INSERT_ORDERED_LIST_COMMAND,\n INSERT_UNORDERED_LIST_COMMAND,\n REMOVE_LIST_COMMAND,\n} from '@lexical/list';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { $createQuoteNode, $isHeadingNode, $isQuoteNode } from '@lexical/rich-text';\nimport { $getNearestBlockElementAncestorOrThrow } from '@lexical/utils';\nimport {\n $createParagraphNode,\n $getSelection,\n $isRangeSelection,\n type ElementFormatType,\n FORMAT_TEXT_COMMAND,\n} from 'lexical';\n\nimport {\n Bold,\n Code,\n Italic,\n List as ListIcon,\n ListOrdered,\n Quote,\n SquareCode,\n Strikethrough,\n Underline,\n} from '../../../icons';\nimport { cn } from '../../../utils';\n\nimport { AlignmentDropdown } from './toolbar/AlignmentDropdown';\nimport { BlockTypeDropdown } from './toolbar/BlockTypeDropdown';\nimport { LinkPanel } from './toolbar/LinkPanel';\nimport { ToolbarButton } from './toolbar/ToolbarButton';\nimport { ToolbarDivider } from './toolbar/ToolbarDivider';\n\nconst ELEMENT_FORMAT_TYPES = ['left', 'center', 'right', 'justify', 'start', 'end', ''] as const;\n\nconst isElementFormatType = (value: string): value is ElementFormatType =>\n (ELEMENT_FORMAT_TYPES as readonly string[]).includes(value);\n\nconst toElementFormatType = (value: string): ElementFormatType =>\n isElementFormatType(value) ? value : 'left';\n\n/**\n * How the toolbar is presented.\n *\n * - `floating`: a popup over the selection, portalled to `document.body`.\n * - `fixed`: a static bar at the top of the editor, visible with no selection.\n */\nexport type ToolbarMode = 'floating' | 'fixed';\n\nconst TOOLBAR_BASE_CLASS =\n 'tw:flex tw:items-center tw:gap-0.5 tw:rounded-lg tw:border tw:border-border tw:px-1.5 tw:py-1';\n\nexport const ToolbarPlugin = ({ mode = 'floating' }: { mode?: ToolbarMode }) => {\n const [editor] = useLexicalComposerContext();\n const [isBold, setIsBold] = useState(false);\n const [isItalic, setIsItalic] = useState(false);\n const [isUnderline, setIsUnderline] = useState(false);\n const [isStrikethrough, setIsStrikethrough] = useState(false);\n const [isCode, setIsCode] = useState(false);\n const [isLink, setIsLink] = useState(false);\n const [blockType, setBlockType] = useState<string>('paragraph');\n const [alignment, setAlignment] = useState<ElementFormatType>('left');\n const [isVisible, setIsVisible] = useState(false);\n const [position, setPosition] = useState<{ top: number; left: number } | null>(null);\n const toolbarRef = useRef<HTMLDivElement>(null);\n const isMouseDownRef = useRef(false);\n const hasSelectionRef = useRef(false);\n const isFloating = mode === 'floating';\n\n const updatePosition = useCallback(() => {\n const nativeSelection = window.getSelection();\n if (!nativeSelection || nativeSelection.rangeCount === 0) return;\n const range = nativeSelection.getRangeAt(0);\n const rect = range.getBoundingClientRect();\n if (rect.width > 0) {\n const toolbarWidth = toolbarRef.current?.offsetWidth ?? 300;\n setPosition({\n top: rect.top + window.scrollY - 8,\n left: Math.max(8, rect.left + window.scrollX + rect.width / 2 - toolbarWidth / 2),\n });\n }\n }, []);\n\n useEffect(() => {\n if (!isFloating) return;\n\n const handleMouseDown = () => {\n isMouseDownRef.current = true;\n };\n const handleMouseUp = () => {\n isMouseDownRef.current = false;\n if (hasSelectionRef.current) {\n setIsVisible(true);\n }\n };\n document.addEventListener('mousedown', handleMouseDown);\n document.addEventListener('mouseup', handleMouseUp);\n return () => {\n document.removeEventListener('mousedown', handleMouseDown);\n document.removeEventListener('mouseup', handleMouseUp);\n };\n }, [isFloating]);\n\n const updateToolbar = useCallback(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) {\n hasSelectionRef.current = false;\n setIsVisible(false);\n return;\n }\n\n const hasSelection = !selection.isCollapsed() && selection.getTextContent().length > 0;\n hasSelectionRef.current = hasSelection;\n\n if (!hasSelection) {\n setIsVisible(false);\n } else if (!isMouseDownRef.current) {\n setIsVisible(true);\n }\n\n if (hasSelection) {\n updatePosition();\n }\n\n setIsBold(selection.hasFormat('bold'));\n setIsItalic(selection.hasFormat('italic'));\n setIsUnderline(selection.hasFormat('underline'));\n setIsStrikethrough(selection.hasFormat('strikethrough'));\n setIsCode(selection.hasFormat('code'));\n\n const node = selection.anchor.getNode();\n const parent = node.getParent();\n setIsLink($isLinkNode(parent) || $isLinkNode(node));\n\n const blockElement = $getNearestBlockElementAncestorOrThrow(node);\n\n if ($isListNode(blockElement)) {\n const listType = blockElement.getListType();\n setBlockType(listType === 'number' ? 'number' : 'bullet');\n } else if ($isHeadingNode(blockElement)) {\n setBlockType(blockElement.getTag());\n } else if ($isCodeNode(blockElement)) {\n setBlockType('code');\n } else if ($isQuoteNode(blockElement)) {\n setBlockType('quote');\n } else {\n setBlockType('paragraph');\n }\n\n setAlignment(toElementFormatType(blockElement.getFormatType()));\n }, [updatePosition]);\n\n useEffect(() => {\n const unregisterUpdate = editor.registerUpdateListener(({ editorState }) => {\n editorState.read(() => {\n updateToolbar();\n });\n });\n\n return () => {\n unregisterUpdate();\n };\n }, [editor, updateToolbar]);\n\n if (isFloating && (!isVisible || !position)) return null;\n\n const buttons = (\n <>\n <BlockTypeDropdown editor={editor} blockType={blockType} />\n\n <ToolbarDivider />\n\n <ToolbarButton\n active={isBold}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold')}\n tooltip=\"Bold (Ctrl+B)\"\n >\n <Bold className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={isItalic}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic')}\n tooltip=\"Italic (Ctrl+I)\"\n >\n <Italic className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={isUnderline}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline')}\n tooltip=\"Underline (Ctrl+U)\"\n >\n <Underline className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={isStrikethrough}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough')}\n tooltip=\"Strikethrough\"\n >\n <Strikethrough className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={isCode}\n onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'code')}\n tooltip=\"Inline Code\"\n >\n <Code className=\"tw:size-4\" />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n <LinkPanel editor={editor} isLink={isLink} />\n\n <ToolbarDivider />\n\n <ToolbarButton\n active={blockType === 'bullet'}\n onClick={() => {\n if (blockType === 'bullet') {\n editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);\n } else {\n editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);\n }\n }}\n tooltip=\"Bullet List\"\n >\n <ListIcon className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={blockType === 'number'}\n onClick={() => {\n if (blockType === 'number') {\n editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);\n } else {\n editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);\n }\n }}\n tooltip=\"Numbered List\"\n >\n <ListOrdered className=\"tw:size-4\" />\n </ToolbarButton>\n\n <ToolbarDivider />\n\n <AlignmentDropdown editor={editor} alignment={alignment} />\n\n <ToolbarDivider />\n\n <ToolbarButton\n active={blockType === 'quote'}\n onClick={() => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n const anchorNode = selection.anchor.getNode();\n const element = $getNearestBlockElementAncestorOrThrow(anchorNode);\n const newNode = blockType === 'quote' ? $createParagraphNode() : $createQuoteNode();\n element.getChildren().forEach((child) => newNode.append(child));\n element.replace(newNode);\n });\n }}\n tooltip=\"Quote\"\n >\n <Quote className=\"tw:size-4\" />\n </ToolbarButton>\n <ToolbarButton\n active={blockType === 'code'}\n onClick={() => {\n editor.update(() => {\n const selection = $getSelection();\n if (!$isRangeSelection(selection)) return;\n const anchorNode = selection.anchor.getNode();\n const element = $getNearestBlockElementAncestorOrThrow(anchorNode);\n const newNode = blockType === 'code' ? $createParagraphNode() : $createCodeNode();\n element.getChildren().forEach((child) => newNode.append(child));\n element.replace(newNode);\n });\n }}\n tooltip=\"Code Block\"\n >\n <SquareCode className=\"tw:size-4\" />\n </ToolbarButton>\n </>\n );\n\n if (!isFloating) {\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Formatting options\"\n // The editor keeps focus (and its selection) when a button is pressed.\n onMouseDown={(event) => event.preventDefault()}\n className={cn(TOOLBAR_BASE_CLASS, 'tw:mb-1 tw:flex-wrap tw:bg-background')}\n >\n {buttons}\n </div>\n );\n }\n\n return createPortal(\n <div\n ref={toolbarRef}\n role=\"toolbar\"\n aria-label=\"Formatting options\"\n onMouseDown={(event) => event.preventDefault()}\n style={{ top: position?.top, left: position?.left }}\n className={cn(\n TOOLBAR_BASE_CLASS,\n 'tw:absolute tw:z-[1060] tw:-translate-y-full tw:bg-popover tw:text-popover-foreground tw:shadow-lg',\n )}\n >\n {buttons}\n </div>,\n document.body,\n );\n};\n","import type { EditorThemeClasses } from 'lexical';\n\n/**\n * Lexical editor theme — maps node types to CSS classes.\n * The editor container uses `tw:prose` so semantic elements (headings, lists, blockquotes, etc.)\n * are styled by Tailwind Typography. We only need explicit classes for text formatting\n * (bold, italic, etc.) because Lexical renders those as `<span>` elements.\n */\nexport const editorTheme: EditorThemeClasses = {\n link: 'tw:cursor-pointer tw:!text-primary tw:underline',\n text: {\n bold: 'tw:font-bold',\n italic: 'tw:italic',\n strikethrough: 'tw:line-through',\n underline: 'tw:underline',\n code: 'tw:rounded tw:bg-muted tw:px-1 tw:py-0.5 tw:font-mono tw:text-[0.85em]',\n },\n list: {\n ol: 'tw:!list-decimal',\n ul: 'tw:!list-disc',\n checklist: 'tw:!list-none tw:!pl-0',\n listitemChecked: [\n 'tw:relative tw:!pl-6 tw:list-none tw:outline-hidden tw:line-through tw:text-muted-foreground',\n 'tw:before:content-[\"\"] tw:before:absolute tw:before:left-0 tw:before:top-[3px]',\n 'tw:before:size-4 tw:before:rounded tw:before:border tw:before:border-solid',\n 'tw:before:bg-primary tw:before:border-primary tw:before:cursor-pointer',\n 'tw:after:content-[\"\"] tw:after:absolute tw:after:left-[5.5px] tw:after:top-[5.5px]',\n 'tw:after:w-1 tw:after:h-2 tw:after:border-primary-foreground tw:after:border-solid',\n 'tw:after:border-r-[1.5px] tw:after:border-b-[1.5px] tw:after:border-t-0 tw:after:border-l-0',\n 'tw:after:rotate-45',\n ].join(' '),\n listitemUnchecked: [\n 'tw:relative tw:!pl-6 tw:list-none tw:outline-hidden',\n 'tw:before:content-[\"\"] tw:before:absolute tw:before:left-0 tw:before:top-[3px]',\n 'tw:before:size-4 tw:before:rounded tw:before:border tw:before:border-solid',\n 'tw:before:border-input tw:before:bg-background tw:before:cursor-pointer',\n ].join(' '),\n },\n};\n","import { useRef, useState } from 'react';\nimport type { FocusEvent, ReactNode } from 'react';\nimport { $isCodeNode } from '@lexical/code';\nimport { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';\nimport { AutoLinkPlugin } from '@lexical/react/LexicalAutoLinkPlugin';\nimport { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin';\nimport { ClickableLinkPlugin } from '@lexical/react/LexicalClickableLinkPlugin';\nimport type { InitialConfigType } from '@lexical/react/LexicalComposer';\nimport { LexicalComposer } from '@lexical/react/LexicalComposer';\nimport { ContentEditable } from '@lexical/react/LexicalContentEditable';\nimport { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';\nimport { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';\nimport { HorizontalRulePlugin } from '@lexical/react/LexicalHorizontalRulePlugin';\nimport { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';\nimport { ListPlugin } from '@lexical/react/LexicalListPlugin';\nimport { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin';\nimport { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';\nimport { TabIndentationPlugin } from '@lexical/react/LexicalTabIndentationPlugin';\n\nimport { cn } from '../../utils';\n\nimport { ImagePastePlugin } from './plugins/ImagePastePlugin';\nimport { KeyboardPlugin } from './plugins/KeyboardPlugin';\nimport { MarkdownPastePlugin } from './plugins/MarkdownPastePlugin';\nimport { MarkdownSyncPlugin } from './plugins/MarkdownSyncPlugin';\nimport { type ToolbarMode, ToolbarPlugin } from './plugins/ToolbarPlugin';\nimport { matchBareUrl } from './bareUrls';\nimport { ImageRendererProvider } from './context';\nimport { EDITOR_NODES } from './editorNodes';\nimport { editorTheme } from './theme';\nimport {\n $importMarkdown,\n AUTO_LINK_TRANSFORMERS,\n CUSTOM_TRANSFORMERS,\n SINGLE_LINE_TRANSFORMERS,\n} from './transformers';\n\nexport type MarkdownEditorProps = {\n /** Markdown string (controlled) */\n value: string;\n onChange?: (markdown: string) => void;\n /** Permanent view-only (e.g. no edit permission). Hides the toolbar. */\n readOnly?: boolean;\n /** Temporary block (e.g. save in flight). Behaves like `readOnly`. */\n disabled?: boolean;\n placeholder?: string;\n autoFocus?: boolean;\n /** Invoked on Cmd/Ctrl+Enter. */\n onSave?: () => void;\n /**\n * Escape in inline-edit mode (`singleLine || saveOnBlur`).\n * Callers reset `value` to the last-committed state here.\n */\n onCancel?: () => void;\n /** The resolved URL becomes the image src in the markdown. */\n onImageUpload?: (file: File) => Promise<{ url: string }>;\n className?: string;\n imageRenderer?: (props: { src: string; alt: string }) => ReactNode;\n showToolbar?: boolean;\n /** How `showToolbar` presents the toolbar. Defaults to `floating`. */\n toolbarMode?: ToolbarMode;\n /**\n * No prose wrapper, min-height or padding — blends into surrounding text for inline editing.\n * Set typography via `className`.\n */\n compact?: boolean;\n /** Calls `onSave` when focus leaves the editor (the toolbar doesn't count). */\n saveOnBlur?: boolean;\n /**\n * No block-level markdown; Enter blurs the editor, Shift+Enter inserts a soft break.\n * Use for editable titles.\n */\n singleLine?: boolean;\n /** Clamps to 2 lines with an ellipsis while not focused; focus shows everything. */\n clampDisplay?: boolean;\n /**\n * Minimum height in lines; `0` removes the floor. Default ~4 lines.\n * Ignored in `compact` mode.\n */\n minRows?: number;\n /**\n * Typed and pasted URLs and emails become links, and export as typed (`a_b`, not `a\\_b`).\n * Ignored with `singleLine`.\n */\n autoLink?: boolean;\n /**\n * A plain-text paste is read as markdown (fences, lists, tables) instead of one paragraph per\n * line. HTML pastes are unchanged. Ignored with `singleLine`.\n */\n pasteMarkdown?: boolean;\n};\n\nconst AUTO_LINK_MATCHERS = [matchBareUrl];\nconst AUTO_LINK_EXCLUDED_PARENTS = [$isCodeNode];\n\nexport const MarkdownEditor = ({\n value,\n onChange,\n readOnly = false,\n placeholder,\n autoFocus = false,\n disabled = false,\n onSave,\n onCancel,\n onImageUpload,\n className,\n imageRenderer,\n showToolbar = false,\n toolbarMode = 'floating',\n compact = false,\n saveOnBlur = false,\n singleLine = false,\n clampDisplay = false,\n minRows,\n autoLink = false,\n pasteMarkdown = false,\n}: MarkdownEditorProps) => {\n const editable = !readOnly && !disabled;\n const linkify = autoLink && !singleLine;\n const markdownPaste = pasteMarkdown && !singleLine;\n const markdownTransformers = linkify ? AUTO_LINK_TRANSFORMERS : CUSTOM_TRANSFORMERS;\n const transformers = singleLine ? SINGLE_LINE_TRANSFORMERS : markdownTransformers;\n const useDefaultMinHeight = !compact && minRows === undefined;\n // One source for the content box's padding: the placeholder repeats it, so its text starts\n // exactly where the caret does.\n const contentPadding = compact ? 'tw:px-1.5 tw:py-0.5' : 'tw:p-2';\n const customMinHeight =\n !compact && minRows !== undefined ? { minHeight: `${minRows * 1.75}em` } : undefined;\n\n // Lexical reads editorState only on first render; later prop changes are applied by MarkdownSyncPlugin.\n const [initialConfig] = useState<InitialConfigType>(() => ({\n namespace: 'MarkdownEditor',\n theme: editorTheme,\n nodes: EDITOR_NODES,\n onError: (error: Error) => {\n console.error('[MarkdownEditor] uncaught editor error', error);\n },\n editable,\n editorState: () => {\n $importMarkdown(value, transformers);\n },\n }));\n\n // Set by KeyboardPlugin before its Escape blur, so the blur doesn't commit the reverted value.\n const skipBlurSaveRef = useRef(false);\n\n const handleBlur =\n saveOnBlur && onSave\n ? (event: FocusEvent<HTMLDivElement>) => {\n if (skipBlurSaveRef.current) {\n skipBlurSaveRef.current = false;\n return;\n }\n // Focus moving into the toolbar doesn't count.\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {\n onSave();\n }\n }\n : undefined;\n\n return (\n <LexicalComposer initialConfig={initialConfig}>\n <ImageRendererProvider value={imageRenderer ?? null}>\n <div\n className={cn(\n !compact && 'tw:prose',\n // Without `tw:prose`, <p> gets the browser's `margin: 1em 0`; space only between paragraphs.\n compact && 'tw:[&_p]:m-0 tw:[&_p+p]:mt-2',\n // No fade: CSS can't gate one on overflow.\n clampDisplay && 'tw:[&:not(:focus-within)]:line-clamp-2',\n className,\n )}\n onBlur={handleBlur}\n >\n {showToolbar && editable && <ToolbarPlugin mode={toolbarMode} />}\n <div\n className={cn(\n 'tw:relative tw:rounded-md tw:transition-colors',\n contentPadding,\n // Compact: the negative margin cancels the padding, so the text stays aligned with static text.\n compact && 'tw:-mx-1.5 tw:-my-0.5',\n editable &&\n 'tw:cursor-text tw:hover:bg-muted tw:focus-within:ring-2 tw:focus-within:ring-ring/40',\n )}\n >\n <RichTextPlugin\n contentEditable={\n <ContentEditable\n className={cn(\n 'tw:outline-hidden',\n // `tw:prose` only zeroes the margin of its own direct children, and the first\n // block sits two levels down — without this it starts 1.25em below the padding.\n !compact && 'tw:[&>*:first-child]:mt-0 tw:[&>*:last-child]:mb-0',\n useDefaultMinHeight && 'tw:min-h-[100px]',\n )}\n style={customMinHeight}\n aria-placeholder={placeholder ?? ''}\n placeholder={\n placeholder ? (\n <div\n data-testid=\"markdown-editor-placeholder\"\n className={cn(\n 'tw:pointer-events-none tw:absolute tw:inset-0 tw:select-none tw:text-muted-foreground',\n contentPadding,\n )}\n >\n {placeholder}\n </div>\n ) : (\n <div />\n )\n }\n />\n }\n ErrorBoundary={LexicalErrorBoundary}\n />\n </div>\n <HistoryPlugin />\n <LinkPlugin />\n <ClickableLinkPlugin newTab />\n {!singleLine && <ListPlugin />}\n {!singleLine && <CheckListPlugin />}\n {!singleLine && <HorizontalRulePlugin />}\n <TabIndentationPlugin />\n <MarkdownShortcutPlugin transformers={transformers} />\n <MarkdownSyncPlugin\n value={value}\n editable={editable}\n onChange={onChange}\n transformers={transformers}\n singleLine={singleLine}\n />\n <ImagePastePlugin onImageUpload={onImageUpload} />\n {linkify && (\n <AutoLinkPlugin\n matchers={AUTO_LINK_MATCHERS}\n excludeParents={AUTO_LINK_EXCLUDED_PARENTS}\n />\n )}\n {markdownPaste && <MarkdownPastePlugin transformers={transformers} />}\n <KeyboardPlugin\n onSave={onSave}\n onCancel={onCancel}\n singleLine={singleLine}\n blurOnEscape={singleLine || saveOnBlur}\n skipBlurSaveRef={skipBlurSaveRef}\n />\n {autoFocus && <AutoFocusPlugin />}\n </div>\n </ImageRendererProvider>\n </LexicalComposer>\n );\n};\n"],"mappings":"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"}
package/dist/rjsf.js CHANGED
@@ -16,7 +16,7 @@ import { PasswordInput } from "./internal/blocks/PasswordInput.js";
16
16
  import { Alert } from "./Alert-UI-CIs-1.js";
17
17
  import { CollapsiblePanel } from "./internal/components/CollapsiblePanel.js";
18
18
  import { Tabs, TabsContent } from "./Tabs-CTDmye1N.js";
19
- import { CodeEditor, isLanguageMode } from "./CodeEditor-jZMw1ioj.js";
19
+ import { CodeEditor, isLanguageMode } from "./CodeEditor-Df7VVx08.js";
20
20
  import { createContext, isValidElement, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
21
21
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
22
22
  import DOMPurify from "dompurify";