@keboola/design 11.3.0 → 11.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +208 -1
- package/CHANGELOG.md +528 -0
- package/COMPONENT-API.md +68 -46
- package/dist/{AIKit-DaFT7p92.js → AIKit-CNX6aiKm.js} +338 -113
- package/dist/AIKit-CNX6aiKm.js.map +1 -0
- package/dist/{Alert-CseY3yAj.js → Alert-Ba5b2YPq.js} +3 -3
- package/dist/{Alert-CseY3yAj.js.map → Alert-Ba5b2YPq.js.map} +1 -1
- package/dist/{AlertModal-DQAGpsEy.js → AlertModal-BGJdaRRj.js} +3 -3
- package/dist/{AlertModal-DQAGpsEy.js.map → AlertModal-BGJdaRRj.js.map} +1 -1
- package/dist/{AppShell-BUoxM3fv.js → AppShell-DRgJxpXW.js} +2 -2
- package/dist/{AppShell-BUoxM3fv.js.map → AppShell-DRgJxpXW.js.map} +1 -1
- package/dist/{Badge-Ch26CXoP.js → Badge-D0pXdekt.js} +2 -2
- package/dist/Badge-D0pXdekt.js.map +1 -0
- package/dist/{BrandEditor-BnTLMRMp.js → BrandEditor-CSANsxUz.js} +8 -8
- package/dist/{BrandEditor-BnTLMRMp.js.map → BrandEditor-CSANsxUz.js.map} +1 -1
- package/dist/{BrandLogo-V2pRUAeO.js → BrandLogo-CoKBk4MI.js} +5 -5
- package/dist/BrandLogo-CoKBk4MI.js.map +1 -0
- package/dist/{Breadcrumb-CQTPn_KB.js → Breadcrumb-g_xn_-Nf.js} +3 -3
- package/dist/{Breadcrumb-CQTPn_KB.js.map → Breadcrumb-g_xn_-Nf.js.map} +1 -1
- package/dist/{Button-CPsEQuTN.js → Button-DsRrU5F1.js} +6 -5
- package/dist/Button-DsRrU5F1.js.map +1 -0
- package/dist/{Card-Cd5HSBmv.js → Card-Dyo7055Q.js} +2 -2
- package/dist/{Card-Cd5HSBmv.js.map → Card-Dyo7055Q.js.map} +1 -1
- package/dist/{Checkbox-5VNCcV7E.js → Checkbox-CUIn2jap.js} +3 -3
- package/dist/{Checkbox-5VNCcV7E.js.map → Checkbox-CUIn2jap.js.map} +1 -1
- package/dist/{Clipboard-B7rckqV_.js → Clipboard-BTW6C-b_.js} +2 -2
- package/dist/{Clipboard-B7rckqV_.js.map → Clipboard-BTW6C-b_.js.map} +1 -1
- package/dist/{ClipboardButton-CQ6Aewpg.js → ClipboardButton-CwZJdRaz.js} +3 -3
- package/dist/{ClipboardButton-CQ6Aewpg.js.map → ClipboardButton-CwZJdRaz.js.map} +1 -1
- package/dist/{CodeEditor-CUse8znx.js → CodeEditor-C9zy7PxK.js} +16 -27
- package/dist/CodeEditor-C9zy7PxK.js.map +1 -0
- package/dist/{ColorInput-Q1D9Vcc_.js → ColorInput-BZV-u_94.js} +3 -3
- package/dist/{ColorInput-Q1D9Vcc_.js.map → ColorInput-BZV-u_94.js.map} +1 -1
- package/dist/{ColorModeSwitch-B5PXCVqB.js → ColorModeSwitch-CsWLiTBX.js} +3 -3
- package/dist/{ColorModeSwitch-B5PXCVqB.js.map → ColorModeSwitch-CsWLiTBX.js.map} +1 -1
- package/dist/{Combobox-CyoRA7oY.js → Combobox-BfIfaVMA.js} +285 -109
- package/dist/Combobox-BfIfaVMA.js.map +1 -0
- package/dist/{Command-Ds68v2rX.js → Command-Bfa1kpbt.js} +6 -6
- package/dist/{Command-Ds68v2rX.js.map → Command-Bfa1kpbt.js.map} +1 -1
- package/dist/{CopyField-DI66uY_g.js → CopyField-DpT0Ngz1.js} +2 -2
- package/dist/{CopyField-DI66uY_g.js.map → CopyField-DpT0Ngz1.js.map} +1 -1
- package/dist/{DateInput-BPj2pzsn.js → DateInput-DiEd5uCL.js} +4 -4
- package/dist/{DateInput-BPj2pzsn.js.map → DateInput-DiEd5uCL.js.map} +1 -1
- package/dist/{DatePicker-DyEGuW9m.js → DatePicker-nA8YdE84.js} +2 -2
- package/dist/{DatePicker-DyEGuW9m.js.map → DatePicker-nA8YdE84.js.map} +1 -1
- package/dist/{DateRangeInput-u9DxNbHW.js → DateRangeInput-DPfVYchl.js} +4 -4
- package/dist/{DateRangeInput-u9DxNbHW.js.map → DateRangeInput-DPfVYchl.js.map} +1 -1
- package/dist/{DateRangePicker-CYYhX6S7.js → DateRangePicker-DjSUFjh4.js} +5 -5
- package/dist/{DateRangePicker-CYYhX6S7.js.map → DateRangePicker-DjSUFjh4.js.map} +1 -1
- package/dist/{DropdownMenu-DpMEcyCq.js → DropdownMenu-CASr-jgl.js} +2 -2
- package/dist/{DropdownMenu-DpMEcyCq.js.map → DropdownMenu-CASr-jgl.js.map} +1 -1
- package/dist/{FieldItem-qQKGU9lF.js → FieldItem-B7XMmZSz.js} +3 -3
- package/dist/{FieldItem-qQKGU9lF.js.map → FieldItem-B7XMmZSz.js.map} +1 -1
- package/dist/{FileUpload-C336MVnU.js → FileUpload-ABThVZyg.js} +2 -2
- package/dist/{FileUpload-C336MVnU.js.map → FileUpload-ABThVZyg.js.map} +1 -1
- package/dist/{Form-CTygENDc.js → Form-CsttTHn4.js} +8 -8
- package/dist/Form-CsttTHn4.js.map +1 -0
- package/dist/{FormGroup-BnwP0jNu.js → FormGroup-DHvTFdno.js} +3 -3
- package/dist/{FormGroup-BnwP0jNu.js.map → FormGroup-DHvTFdno.js.map} +1 -1
- package/dist/{FullScreenModal-j-M4aPFd.js → FullScreenModal-BvPuYibe.js} +3 -3
- package/dist/{FullScreenModal-j-M4aPFd.js.map → FullScreenModal-BvPuYibe.js.map} +1 -1
- package/dist/{HoverCard-yQq-O49c.js → HoverCard-B9ZMJxjn.js} +2 -2
- package/dist/{HoverCard-yQq-O49c.js.map → HoverCard-B9ZMJxjn.js.map} +1 -1
- package/dist/{InputGroup-D7zlmqPB.js → InputGroup-DcZRlVnN.js} +24 -16
- package/dist/InputGroup-DcZRlVnN.js.map +1 -0
- package/dist/{Kbd-D6LpR7G2.js → Kbd-Cvvt91Q8.js} +14 -4
- package/dist/Kbd-Cvvt91Q8.js.map +1 -0
- package/dist/MarkedText-DNGEUVWc.js +67 -0
- package/dist/MarkedText-DNGEUVWc.js.map +1 -0
- package/dist/{MermaidDiagram-JlvuGcY-.js → MermaidDiagram-CXG5tC6J.js} +19 -18
- package/dist/MermaidDiagram-CXG5tC6J.js.map +1 -0
- package/dist/{Modal-o4ATIexE.js → Modal-Coj-H02o.js} +16 -4
- package/dist/Modal-Coj-H02o.js.map +1 -0
- package/dist/{MultiActionButtonGroup-GTeFk-L8.js → MultiActionButtonGroup-DokHbPgM.js} +3 -3
- package/dist/{MultiActionButtonGroup-GTeFk-L8.js.map → MultiActionButtonGroup-DokHbPgM.js.map} +1 -1
- package/dist/{Navbar-CAQs4BZz.js → Navbar-Liy1TPI7.js} +7 -7
- package/dist/{Navbar-CAQs4BZz.js.map → Navbar-Liy1TPI7.js.map} +1 -1
- package/dist/PageHeader-Q3IpCnQd.js.map +1 -1
- package/dist/{PageToolbar-bG2YtSa3.js → PageToolbar-DExqEYGl.js} +4 -4
- package/dist/{PageToolbar-bG2YtSa3.js.map → PageToolbar-DExqEYGl.js.map} +1 -1
- package/dist/{Pagination-BB3X7ooY.js → Pagination-C_b7Xhey.js} +2 -2
- package/dist/{Pagination-BB3X7ooY.js.map → Pagination-C_b7Xhey.js.map} +1 -1
- package/dist/{Popconfirm-C2Ky5hJO.js → Popconfirm-5pBzT_HQ.js} +12 -13
- package/dist/{Popconfirm-C2Ky5hJO.js.map → Popconfirm-5pBzT_HQ.js.map} +1 -1
- package/dist/{Popover-DsbI2HKu.js → Popover-BEbQrC_P.js} +22 -19
- package/dist/Popover-BEbQrC_P.js.map +1 -0
- package/dist/{RadioGroup-BMxuZEbT.js → RadioGroup-DXPbSj8P.js} +3 -3
- package/dist/{RadioGroup-BMxuZEbT.js.map → RadioGroup-DXPbSj8P.js.map} +1 -1
- package/dist/{Search-DFeECt5D.js → Search-5uQAiNIP.js} +2 -2
- package/dist/{Search-DFeECt5D.js.map → Search-5uQAiNIP.js.map} +1 -1
- package/dist/{SearchInput-CCpdUego.js → SearchInput-D4UgAXJK.js} +3 -3
- package/dist/{SearchInput-CCpdUego.js.map → SearchInput-D4UgAXJK.js.map} +1 -1
- package/dist/{SectionNav-Bw_MVL0_.js → SectionNav-OkKCjSA-.js} +5 -5
- package/dist/{SectionNav-Bw_MVL0_.js.map → SectionNav-OkKCjSA-.js.map} +1 -1
- package/dist/{Select-D6IZVvwL.js → Select-DV3Hak_l.js} +31 -21
- package/dist/Select-DV3Hak_l.js.map +1 -0
- package/dist/{Sheet-BIzs2K2H.js → Sheet-Chf0kX1E.js} +3 -3
- package/dist/{Sheet-BIzs2K2H.js.map → Sheet-Chf0kX1E.js.map} +1 -1
- package/dist/{Sidebar-r1TW4g_b.js → Sidebar-D3cY1kha.js} +48 -22
- package/dist/Sidebar-D3cY1kha.js.map +1 -0
- package/dist/{Slider-CjxyfEty.js → Slider-CRf-bB4y.js} +3 -3
- package/dist/{Slider-CjxyfEty.js.map → Slider-CRf-bB4y.js.map} +1 -1
- package/dist/{Switch-BueTV03C.js → Switch-B0WdGSjz.js} +8 -8
- package/dist/{Switch-BueTV03C.js.map → Switch-B0WdGSjz.js.map} +1 -1
- package/dist/{Tabs-l72-WuhK.js → Tabs-eB974xJf.js} +2 -2
- package/dist/{Tabs-l72-WuhK.js.map → Tabs-eB974xJf.js.map} +1 -1
- package/dist/{TextInput-DhdRk8qm.js → TextInput-DH5SkbsE.js} +3 -3
- package/dist/{TextInput-DhdRk8qm.js.map → TextInput-DH5SkbsE.js.map} +1 -1
- package/dist/{ThemeProvider-DZfGdf1v.js → ThemeProvider-2RMdVGxO.js} +95 -15
- package/dist/ThemeProvider-2RMdVGxO.js.map +1 -0
- package/dist/{TimePicker-B6d2rAbX.js → TimePicker-BGeqc-Ed.js} +2 -2
- package/dist/{TimePicker-B6d2rAbX.js.map → TimePicker-BGeqc-Ed.js.map} +1 -1
- package/dist/{Timeline-6btyJl4D.js → Timeline-BG5Xogxh.js} +11 -11
- package/dist/{Timeline-6btyJl4D.js.map → Timeline-BG5Xogxh.js.map} +1 -1
- package/dist/{Toast-CxXUulYN.js → Toast-Dr6Uw7ao.js} +2 -2
- package/dist/{Toast-CxXUulYN.js.map → Toast-Dr6Uw7ao.js.map} +1 -1
- package/dist/{Workbench-BzE-Vvd9.js → Workbench-UR2FBC7I.js} +3 -1
- package/dist/Workbench-UR2FBC7I.js.map +1 -0
- package/dist/{ZoomableSvg-CNIzRHKH.js → ZoomableSvg-pooPb1Cu.js} +4 -4
- package/dist/{ZoomableSvg-CNIzRHKH.js.map → ZoomableSvg-pooPb1Cu.js.map} +1 -1
- package/dist/{context-BrNtMc1H.js → context-D7X470dy.js} +4 -3
- package/dist/context-D7X470dy.js.map +1 -0
- package/dist/{defaults-CTfvj2KB.js → defaults-i_xG2F_1.js} +2 -4
- package/dist/defaults-i_xG2F_1.js.map +1 -0
- package/dist/editors.js +5 -5
- package/dist/findLiteralMatches-BGBw8Vbl.js +62 -0
- package/dist/findLiteralMatches-BGBw8Vbl.js.map +1 -0
- package/dist/flint.js +134 -8
- package/dist/flint.js.map +1 -1
- package/dist/index.d.ts +1118 -566
- package/dist/index.js +64 -62
- package/dist/internal/blocks/AIKit.js +2 -2
- package/dist/internal/blocks/AppShell.js +1 -1
- package/dist/internal/blocks/AuthLayout.js +118 -0
- package/dist/internal/blocks/AuthLayout.js.map +1 -0
- package/dist/internal/blocks/BrandEditor.js +1 -1
- package/dist/internal/blocks/ChartPanel.js +1 -1
- package/dist/internal/blocks/ClipboardButton.js +1 -1
- package/dist/internal/blocks/ColorInput.js +1 -1
- package/dist/internal/blocks/ColorModeSwitch.js +1 -1
- package/dist/internal/blocks/Command.js +1 -1
- package/dist/internal/blocks/CopyField.js +1 -1
- package/dist/internal/blocks/DateInput.js +1 -1
- package/dist/internal/blocks/DateRangeInput.js +1 -1
- package/dist/internal/blocks/EmptyConfigurationActionCard.js +1 -1
- package/dist/internal/blocks/ErrorState.js +1 -1
- package/dist/internal/blocks/ExportMenu.js +5 -5
- package/dist/internal/blocks/ExportMenu.js.map +1 -1
- package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
- package/dist/internal/blocks/Form.js +1 -1
- package/dist/internal/blocks/FormGroup.js +1 -1
- package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
- package/dist/internal/blocks/MultiCombobox.js +116 -54
- package/dist/internal/blocks/MultiCombobox.js.map +1 -1
- package/dist/internal/blocks/NumberInput.js +1 -1
- package/dist/internal/blocks/PageToolbar.js +1 -1
- package/dist/internal/blocks/PasswordInput.js +2 -2
- package/dist/internal/blocks/SearchInput.js +1 -1
- package/dist/internal/blocks/SearchInputWithNavigation.js +3 -3
- package/dist/internal/blocks/SectionNav.js +1 -1
- package/dist/internal/blocks/SplitButton.js +2 -2
- package/dist/internal/blocks/StatCard.js +1 -1
- package/dist/internal/blocks/TextInput.js +1 -1
- package/dist/internal/blocks/Textarea.js +1 -1
- package/dist/internal/blocks/TimeInput.js +3 -3
- package/dist/internal/components/Alert.js +1 -1
- package/dist/internal/components/AlertModal.js +1 -1
- package/dist/internal/components/Avatar.js +1 -1
- package/dist/internal/components/Badge.js +1 -1
- package/dist/internal/components/BrandLogo.js +1 -1
- package/dist/internal/components/Breadcrumb.js +1 -1
- package/dist/internal/components/Button.js +1 -1
- package/dist/internal/components/Card.js +1 -1
- package/dist/internal/components/Checkbox.js +1 -1
- package/dist/internal/components/Clipboard.js +1 -1
- package/dist/internal/components/CollapsiblePanel.js +1 -1
- package/dist/internal/components/Combobox.js +2 -2
- package/dist/internal/components/DatePicker.js +1 -1
- package/dist/internal/components/DateRangePicker.js +1 -1
- package/dist/internal/components/DropdownMenu.js +1 -1
- package/dist/internal/components/FileUpload.js +1 -1
- package/dist/internal/components/FullScreenModal.js +1 -1
- package/dist/internal/components/HoverCard.js +1 -1
- package/dist/internal/components/InputGroup.js +1 -1
- package/dist/internal/components/Kbd.js +1 -1
- package/dist/internal/components/MarkedText.js +1 -1
- package/dist/internal/components/Modal.js +1 -1
- package/dist/internal/components/Navbar.js +1 -1
- package/dist/internal/components/Pagination.js +1 -1
- package/dist/internal/components/Popconfirm.js +1 -1
- package/dist/internal/components/Popover.js +1 -1
- package/dist/internal/components/RadioGroup.js +1 -1
- package/dist/internal/components/Search.js +1 -1
- package/dist/internal/components/Select.js +1 -1
- package/dist/internal/components/Sheet.js +1 -1
- package/dist/internal/components/Sidebar.js +1 -1
- package/dist/internal/components/Slider.js +1 -1
- package/dist/internal/components/Switch.js +1 -1
- package/dist/internal/components/Tabs.js +1 -1
- package/dist/internal/components/ThemeProvider.js +4 -4
- package/dist/internal/components/TimePicker.js +1 -1
- package/dist/internal/components/Timeline.js +1 -1
- package/dist/internal/components/Toast.js +2 -2
- package/dist/internal/components/Toggle.js +3 -3
- package/dist/internal/components/Toggle.js.map +1 -1
- package/dist/internal/components/Tooltip.js +1 -1
- package/dist/internal/components/Truncated.js +1 -1
- package/dist/internal/components/Workbench.js +1 -1
- package/dist/internal/components/ZoomableSvg.js +1 -1
- package/dist/internal/utils.js +3 -3
- package/dist/markdown-editor.js +32 -26
- package/dist/markdown-editor.js.map +1 -1
- package/dist/mermaid.js +1 -1
- package/dist/rjsf.js +24 -25
- package/dist/rjsf.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/testing.js +4 -4
- package/dist/testing.js.map +1 -1
- package/dist/{useColorSchemeState-BJEk6esG.js → themeScopeContext-D7fSyb06.js} +17 -4
- package/dist/themeScopeContext-D7fSyb06.js.map +1 -0
- package/dist/{themeTokens-7T1AFLhq.js → themeTokens-qP1-55O7.js} +38 -11
- package/dist/themeTokens-qP1-55O7.js.map +1 -0
- package/dist/{toast-BweSoKn3.js → toast-DIC0iNRf.js} +2 -2
- package/dist/{toast-BweSoKn3.js.map → toast-DIC0iNRf.js.map} +1 -1
- package/dist/{utils-B-g7d_Jb.js → utils-DSvrhU8E.js} +7 -3
- package/dist/{utils-B-g7d_Jb.js.map → utils-DSvrhU8E.js.map} +1 -1
- package/dist/vega.d.ts +1 -1
- package/dist/vega.js +3 -3
- package/dist/vega.js.map +1 -1
- package/dist/{vegaTheme-FBXgAdHK.js → vegaTheme-CSvFEMBl.js} +6 -6
- package/dist/vegaTheme-CSvFEMBl.js.map +1 -0
- package/package.json +12 -10
- package/src/styles.css +3 -0
- package/dist/AIKit-DaFT7p92.js.map +0 -1
- package/dist/Badge-Ch26CXoP.js.map +0 -1
- package/dist/BrandLogo-V2pRUAeO.js.map +0 -1
- package/dist/Button-CPsEQuTN.js.map +0 -1
- package/dist/CodeEditor-CUse8znx.js.map +0 -1
- package/dist/Combobox-CyoRA7oY.js.map +0 -1
- package/dist/Form-CTygENDc.js.map +0 -1
- package/dist/InputGroup-D7zlmqPB.js.map +0 -1
- package/dist/Kbd-D6LpR7G2.js.map +0 -1
- package/dist/MarkedText-Ckbft5mw.js +0 -44
- package/dist/MarkedText-Ckbft5mw.js.map +0 -1
- package/dist/MermaidDiagram-JlvuGcY-.js.map +0 -1
- package/dist/Modal-o4ATIexE.js.map +0 -1
- package/dist/Popover-DsbI2HKu.js.map +0 -1
- package/dist/Select-D6IZVvwL.js.map +0 -1
- package/dist/Sidebar-r1TW4g_b.js.map +0 -1
- package/dist/ThemeProvider-DZfGdf1v.js.map +0 -1
- package/dist/Workbench-BzE-Vvd9.js.map +0 -1
- package/dist/context-BrNtMc1H.js.map +0 -1
- package/dist/defaults-CTfvj2KB.js.map +0 -1
- package/dist/escapeStringRegexp-8MxP2knR.js +0 -6
- package/dist/escapeStringRegexp-8MxP2knR.js.map +0 -1
- package/dist/themeTokens-7T1AFLhq.js.map +0 -1
- package/dist/useColorSchemeState-BJEk6esG.js.map +0 -1
- package/dist/vegaTheme-FBXgAdHK.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, useRef } 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 { $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 const onImageUploadRef = useRef(onImageUpload);\n onImageUploadRef.current = onImageUpload;\n\n useEffect(() => {\n const uploadFile = (file: File) => {\n const upload = onImageUploadRef.current;\n if (!upload) 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 upload(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 (!onImageUploadRef.current) 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 (!onImageUploadRef.current) 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]);\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\ntype KeyboardPluginProps = {\n /** Invoked directly on Cmd/Ctrl+Enter (explicit commit shortcut, no blur). */\n onSave?: () => void;\n /**\n * Invoked on Escape in inline-edit mode. Per the inline-editable-text pattern spec\n * (evviku/design-system-docs), Escape reverts the in-progress edit — callers reset\n * `value` to the last-committed state inside this handler.\n */\n onCancel?: () => void;\n /**\n * When true, plain Enter blurs the editor instead of inserting a paragraph break.\n * For `saveOnBlur` callers this commits via blur; for non-saveOnBlur callers Enter\n * just exits edit mode. Shift+Enter still inserts a soft line break.\n */\n singleLine?: boolean;\n /**\n * When true, Escape blurs the editor (exits edit mode). Enable only for inline-edit\n * patterns (`singleLine` or `saveOnBlur`); in full-toolbar mode Esc stays a no-op so\n * existing call sites don't lose focus on a stray keypress.\n */\n blurOnEscape?: boolean;\n /**\n * Set to `true` before the plugin programmatically blurs on Escape so the wrapper's\n * blur handler can skip its `onSave` — otherwise blur-after-cancel would commit the\n * value we just reverted. Reset by the consumer 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 onSaveRef = useRef(onSave);\n onSaveRef.current = onSave;\n const onCancelRef = useRef(onCancel);\n onCancelRef.current = 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 onSaveRef.current?.();\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 // Suppress blur-driven onSave so the post-blur save doesn't commit the value we just reverted.\n if (skipBlurSaveExternalRef) skipBlurSaveExternalRef.current = true;\n onCancelRef.current?.();\n editor.getRootElement()?.blur();\n return true;\n }\n return false;\n },\n COMMAND_PRIORITY_HIGH,\n );\n }, [editor, skipBlurSaveExternalRef]);\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: `` */\nconst IMAGE: TextMatchTransformer = {\n dependencies: [ImageNode],\n export: (node) => {\n if (!$isImageNode(node)) return null;\n return `})`;\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 * Custom transformers = our additions + built-in Lexical transformers.\n * MERMAID is placed before TRANSFORMERS so it intercepts ` ```mermaid ``` ` before the generic CODE transformer.\n * IMAGE is placed before built-in LINK to prevent `` from being 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 = plain text. `singleLine` mode edits entity names / titles, which are\n * plain text, not markdown. Parsing inline formatting here corrupts ordinary names: e.g.\n * `staging_chargebee_invoices` would render the `_chargebee_` span as italics, and Lexical\n * escapes the underscores on export (`\\_`) to prevent exactly that — but those backslashes\n * then leak into the persisted name. Dropping every transformer keeps `_`, `*`, `` ` ``, `~`\n * literal on both import and export; pair the empty set with `unescapeMarkdownText` on export\n * to strip Lexical's escaping (see MarkdownSyncPlugin).\n */\nexport const SINGLE_LINE_TRANSFORMERS: Transformer[] = [];\n\n// --- Table pre/post-processing ---\n// GFM tables can't round-trip through Lexical's markdown (no built-in table transformer).\n// We wrap them in fenced code blocks on import and unwrap on export to preserve them exactly.\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/**\n * Reverses the backslash-escaping Lexical applies to markdown punctuation (`* _ ` ~ \\`) when\n * exporting text nodes. Used for `singleLine` (plain-text) mode, where the export value is a\n * bare entity name — the escaping would otherwise persist as literal backslashes in the name.\n */\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 {\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 onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\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 onChangeRef.current?.(markdown);\n }\n });\n });\n }, [editor]);\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 /**\n * Renders content but never accepts input. Use for permanent view-only contexts\n * (e.g. a current user lacks edit permission). Toolbar is hidden.\n */\n readOnly?: boolean;\n /**\n * Temporarily blocks input but signals intent to re-enable\n * (e.g. while a save is in flight). Functionally identical to `readOnly` today.\n */\n disabled?: boolean;\n placeholder?: string;\n autoFocus?: boolean;\n /** Invoked on Cmd/Ctrl+Enter — typically used to commit a form. */\n onSave?: () => void;\n /**\n * Invoked on Escape in inline-edit mode (`singleLine || saveOnBlur`). Per the\n * inline-editable-text pattern spec, Esc reverts the in-progress edit — callers\n * reset `value` to the last-committed state inside this handler.\n */\n onCancel?: () => void;\n /**\n * Async image upload. Resolved URL is embedded as the image src\n * (`` in the underlying markdown).\n */\n onImageUpload?: (file: File) => Promise<{ url: string }>;\n className?: string;\n imageRenderer?: (props: { src: string; alt: string }) => ReactNode;\n showToolbar?: boolean;\n /**\n * Strips the prose typography wrapper, removes the min-height, and tightens padding so\n * the editor visually blends with surrounding text. Use for inline / Linear-style edit\n * affordances inside headings, list rows, or table cells. Pair with `className` to set\n * the caller's typography.\n */\n compact?: boolean;\n /**\n * Calls `onSave` when focus leaves the editor (and is not moved into the toolbar).\n * `onChange` already keeps the caller's value in sync — `onSave` is the \"commit\" signal.\n */\n saveOnBlur?: boolean;\n /**\n * Disables block-level markdown (lists, headings, code blocks, HR) and makes a plain\n * Enter press trigger `onSave` and blur the editor. Shift+Enter still inserts a soft\n * line break. Use for editable titles.\n */\n singleLine?: boolean;\n /**\n * Clamps content to 2 lines (truncating with an ellipsis) in the display (not-focused)\n * state; focus expands the editor to full height (no clamp). `line-clamp` is self-gating,\n * so short/empty content renders fully with no truncation. Per the inline-editable-text\n * pattern spec for description-style slots.\n */\n clampDisplay?: boolean;\n /**\n * Minimum visible height in lines. `1` renders as a single line that grows with\n * content (Linear/Slack/GitHub-PR-comment pattern); `0` removes the floor entirely.\n * Omit to keep the default ~4-line floor. Ignored in `compact` mode (which has no floor).\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 to `true` by KeyboardPlugin before it programmatically blurs on Escape so the\n // blur handler can skip its `onSave` — otherwise blur-after-cancel would commit the\n // value we just reverted. Reset on read inside handleBlur.\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 // Only fire when focus leaves the editor wrapper entirely (not when moving into the toolbar).\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 // Compact mode drops `tw:prose`, so Lexical's <p> wrappers fall back to the browser\n // default `margin: 1em 0` — visually huge at heading sizes. Zero them, and use the\n // adjacent-sibling selector for paragraph spacing so single-paragraph blocks (titles,\n // short descriptions) stay tight while multi-paragraph blocks still breathe.\n compact && 'tw:[&_p]:m-0 tw:[&_p+p]:mt-2',\n // Display-state clamp: 2 lines, dropped in focus-within so editing expands to full\n // height. line-clamp is self-gating (no effect below 3 lines), so short/empty content\n // renders clean; a CSS fade can't gate on overflow without JS, so it's omitted.\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 // In compact mode the padding lets the hover bg / focus ring extend past the text,\n // but a matching negative margin shifts the wrapper outward so the text itself stays\n // aligned with the parent's content edge (i.e. with where static text would render).\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/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 directly on Cmd/Ctrl+Enter (explicit commit shortcut, no blur). */\n onSave?: () => void;\n /**\n * Invoked on Escape in inline-edit mode. Per the inline-editable-text pattern spec\n * (evviku/design-system-docs), Escape reverts the in-progress edit — callers reset\n * `value` to the last-committed state inside this handler.\n */\n onCancel?: () => void;\n /**\n * When true, plain Enter blurs the editor instead of inserting a paragraph break.\n * For `saveOnBlur` callers this commits via blur; for non-saveOnBlur callers Enter\n * just exits edit mode. Shift+Enter still inserts a soft line break.\n */\n singleLine?: boolean;\n /**\n * When true, Escape blurs the editor (exits edit mode). Enable only for inline-edit\n * patterns (`singleLine` or `saveOnBlur`); in full-toolbar mode Esc stays a no-op so\n * existing call sites don't lose focus on a stray keypress.\n */\n blurOnEscape?: boolean;\n /**\n * Set to `true` before the plugin programmatically blurs on Escape so the wrapper's\n * blur handler can skip its `onSave` — otherwise blur-after-cancel would commit the\n * value we just reverted. Reset by the consumer 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 // Suppress blur-driven onSave so the post-blur save doesn't commit the value we just reverted.\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: `` */\nconst IMAGE: TextMatchTransformer = {\n dependencies: [ImageNode],\n export: (node) => {\n if (!$isImageNode(node)) return null;\n return `})`;\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 * Custom transformers = our additions + built-in Lexical transformers.\n * MERMAID is placed before TRANSFORMERS so it intercepts ` ```mermaid ``` ` before the generic CODE transformer.\n * IMAGE is placed before built-in LINK to prevent `` from being 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 = plain text. `singleLine` mode edits entity names / titles, which are\n * plain text, not markdown. Parsing inline formatting here corrupts ordinary names: e.g.\n * `staging_chargebee_invoices` would render the `_chargebee_` span as italics, and Lexical\n * escapes the underscores on export (`\\_`) to prevent exactly that — but those backslashes\n * then leak into the persisted name. Dropping every transformer keeps `_`, `*`, `` ` ``, `~`\n * literal on both import and export; pair the empty set with `unescapeMarkdownText` on export\n * to strip Lexical's escaping (see MarkdownSyncPlugin).\n */\nexport const SINGLE_LINE_TRANSFORMERS: Transformer[] = [];\n\n// --- Table pre/post-processing ---\n// GFM tables can't round-trip through Lexical's markdown (no built-in table transformer).\n// We wrap them in fenced code blocks on import and unwrap on export to preserve them exactly.\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/**\n * Reverses the backslash-escaping Lexical applies to markdown punctuation (`* _ ` ~ \\`) when\n * exporting text nodes. Used for `singleLine` (plain-text) mode, where the export value is a\n * bare entity name — the escaping would otherwise persist as literal backslashes in the name.\n */\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 /**\n * Renders content but never accepts input. Use for permanent view-only contexts\n * (e.g. a current user lacks edit permission). Toolbar is hidden.\n */\n readOnly?: boolean;\n /**\n * Temporarily blocks input but signals intent to re-enable\n * (e.g. while a save is in flight). Functionally identical to `readOnly` today.\n */\n disabled?: boolean;\n placeholder?: string;\n autoFocus?: boolean;\n /** Invoked on Cmd/Ctrl+Enter — typically used to commit a form. */\n onSave?: () => void;\n /**\n * Invoked on Escape in inline-edit mode (`singleLine || saveOnBlur`). Per the\n * inline-editable-text pattern spec, Esc reverts the in-progress edit — callers\n * reset `value` to the last-committed state inside this handler.\n */\n onCancel?: () => void;\n /**\n * Async image upload. Resolved URL is embedded as the image src\n * (`` in the underlying markdown).\n */\n onImageUpload?: (file: File) => Promise<{ url: string }>;\n className?: string;\n imageRenderer?: (props: { src: string; alt: string }) => ReactNode;\n showToolbar?: boolean;\n /**\n * Strips the prose typography wrapper, removes the min-height, and tightens padding so\n * the editor visually blends with surrounding text. Use for inline / Linear-style edit\n * affordances inside headings, list rows, or table cells. Pair with `className` to set\n * the caller's typography.\n */\n compact?: boolean;\n /**\n * Calls `onSave` when focus leaves the editor (and is not moved into the toolbar).\n * `onChange` already keeps the caller's value in sync — `onSave` is the \"commit\" signal.\n */\n saveOnBlur?: boolean;\n /**\n * Disables block-level markdown (lists, headings, code blocks, HR) and makes a plain\n * Enter press trigger `onSave` and blur the editor. Shift+Enter still inserts a soft\n * line break. Use for editable titles.\n */\n singleLine?: boolean;\n /**\n * Clamps content to 2 lines (truncating with an ellipsis) in the display (not-focused)\n * state; focus expands the editor to full height (no clamp). `line-clamp` is self-gating,\n * so short/empty content renders fully with no truncation. Per the inline-editable-text\n * pattern spec for description-style slots.\n */\n clampDisplay?: boolean;\n /**\n * Minimum visible height in lines. `1` renders as a single line that grows with\n * content (Linear/Slack/GitHub-PR-comment pattern); `0` removes the floor entirely.\n * Omit to keep the default ~4-line floor. Ignored in `compact` mode (which has no floor).\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 to `true` by KeyboardPlugin before it programmatically blurs on Escape so the\n // blur handler can skip its `onSave` — otherwise blur-after-cancel would commit the\n // value we just reverted. Reset on read inside handleBlur.\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 // Only fire when focus leaves the editor wrapper entirely (not when moving into the toolbar).\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 // Compact mode drops `tw:prose`, so Lexical's <p> wrappers fall back to the browser\n // default `margin: 1em 0` — visually huge at heading sizes. Zero them, and use the\n // adjacent-sibling selector for paragraph spacing so single-paragraph blocks (titles,\n // short descriptions) stay tight while multi-paragraph blocks still breathe.\n compact && 'tw:[&_p]:m-0 tw:[&_p+p]:mt-2',\n // Display-state clamp: 2 lines, dropped in focus-within so editing expands to full\n // height. line-clamp is self-gating (no effect below 3 lines), so short/empty content\n // renders clean; a CSS fade can't gate on overflow without JS, so it's omitted.\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 // In compact mode the padding lets the hover bg / focus ring extend past the text,\n // but a matching negative margin shifts the wrapper outward so the text itself stays\n // aligned with the parent's content edge (i.e. with where static text would render).\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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"}
|
package/dist/mermaid.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { MermaidDiagram } from "./MermaidDiagram-
|
|
1
|
+
import { MermaidDiagram } from "./MermaidDiagram-CXG5tC6J.js";
|
|
2
2
|
export { MermaidDiagram };
|
package/dist/rjsf.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { Tooltip, debounce } from "./utils-
|
|
1
|
+
import { Tooltip, debounce } from "./utils-DSvrhU8E.js";
|
|
2
2
|
import { BookOpen, Info, Trash2 } from "./icons-Cek151jC.js";
|
|
3
|
-
import { Button } from "./Button-
|
|
3
|
+
import { Button } from "./Button-DsRrU5F1.js";
|
|
4
4
|
import { Label } from "./internal/components/Label.js";
|
|
5
5
|
import { Link } from "./internal/components/Link.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { useStableCallback } from "./internal/hooks/useStableCallback.js";
|
|
7
|
+
import { TextInput } from "./TextInput-DH5SkbsE.js";
|
|
8
|
+
import { RadioGroup } from "./RadioGroup-DXPbSj8P.js";
|
|
9
|
+
import { Checkbox } from "./Checkbox-CUIn2jap.js";
|
|
10
|
+
import { Combobox } from "./Combobox-BfIfaVMA.js";
|
|
11
|
+
import { FormGroup } from "./FormGroup-DHvTFdno.js";
|
|
11
12
|
import { NumberInput } from "./internal/blocks/NumberInput.js";
|
|
12
13
|
import { Textarea } from "./internal/blocks/Textarea.js";
|
|
13
|
-
import { DateInput } from "./DateInput-
|
|
14
|
+
import { DateInput } from "./DateInput-DiEd5uCL.js";
|
|
14
15
|
import { PasswordInput } from "./internal/blocks/PasswordInput.js";
|
|
15
|
-
import { Alert } from "./Alert-
|
|
16
|
+
import { Alert } from "./Alert-Ba5b2YPq.js";
|
|
16
17
|
import { CollapsiblePanel } from "./internal/components/CollapsiblePanel.js";
|
|
17
|
-
import { Tabs, TabsContent } from "./Tabs-
|
|
18
|
-
import { CodeEditor, isLanguageMode } from "./CodeEditor-
|
|
18
|
+
import { Tabs, TabsContent } from "./Tabs-eB974xJf.js";
|
|
19
|
+
import { CodeEditor, isLanguageMode } from "./CodeEditor-C9zy7PxK.js";
|
|
19
20
|
import { createContext, isValidElement, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
20
21
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
21
22
|
import DOMPurify from "dompurify";
|
|
@@ -920,7 +921,7 @@ const DateWidget = ({ id, value, onChange, onBlur, onFocus, disabled, readonly,
|
|
|
920
921
|
* Widget for fields using json-editor's enumSource/watch pattern.
|
|
921
922
|
* Reads options dynamically from the root form data based on watched paths.
|
|
922
923
|
*/
|
|
923
|
-
const DynamicSelectWidget = ({ value, onChange, disabled, readonly, options: widgetOptions }) => {
|
|
924
|
+
const DynamicSelectWidget = ({ id, value, onChange, disabled, readonly, options: widgetOptions, required }) => {
|
|
924
925
|
const data = useRootFormData();
|
|
925
926
|
const watch = widgetOptions.watch;
|
|
926
927
|
const enumSource = widgetOptions.enumSource;
|
|
@@ -934,9 +935,11 @@ const DynamicSelectWidget = ({ value, onChange, disabled, readonly, options: wid
|
|
|
934
935
|
const selectedItem = matched ?? fallbackItem;
|
|
935
936
|
const items = fallbackItem ? [fallbackItem, ...dynamicItems] : dynamicItems;
|
|
936
937
|
return /* @__PURE__ */ jsx(Combobox, {
|
|
938
|
+
id,
|
|
937
939
|
variant: "secondary",
|
|
938
940
|
items,
|
|
939
941
|
value: selectedItem,
|
|
942
|
+
allowClear: !required,
|
|
940
943
|
disabled: disabled || readonly,
|
|
941
944
|
onValueChange: (selected) => onChange(selected?.value ?? "")
|
|
942
945
|
});
|
|
@@ -993,7 +996,7 @@ const RadioWidget = ({ id, value, onChange, disabled, readonly, options }) => {
|
|
|
993
996
|
};
|
|
994
997
|
//#endregion
|
|
995
998
|
//#region src/blocks/RjsfSchemaEditor/widgets/SelectWidget.tsx
|
|
996
|
-
const SelectWidget = ({ value, schema, onChange, disabled, readonly, options, placeholder, required }) => {
|
|
999
|
+
const SelectWidget = ({ id, value, schema, onChange, disabled, readonly, options, placeholder, required }) => {
|
|
997
1000
|
const enumOptions = options.enumOptions ?? [];
|
|
998
1001
|
const isBoolean = schema.type === "boolean";
|
|
999
1002
|
const items = enumOptions.map((o) => ({
|
|
@@ -1002,6 +1005,7 @@ const SelectWidget = ({ value, schema, onChange, disabled, readonly, options, pl
|
|
|
1002
1005
|
}));
|
|
1003
1006
|
const selectedItem = items.find((item) => item.value === (value == null ? "" : String(value)));
|
|
1004
1007
|
return /* @__PURE__ */ jsx(Combobox, {
|
|
1008
|
+
id,
|
|
1005
1009
|
variant: "secondary",
|
|
1006
1010
|
items,
|
|
1007
1011
|
value: selectedItem ?? null,
|
|
@@ -1539,8 +1543,7 @@ const RjsfSchemaEditor = ({ schema, value, onChange, readOnly, inForm, globalCon
|
|
|
1539
1543
|
useEffect(() => {
|
|
1540
1544
|
isInitialMountRef.current = false;
|
|
1541
1545
|
}, [formKey]);
|
|
1542
|
-
const
|
|
1543
|
-
onChangeRef.current = onChange;
|
|
1546
|
+
const handleValueChange = useStableCallback(onChange);
|
|
1544
1547
|
const valueRef = useRef(value);
|
|
1545
1548
|
valueRef.current = value;
|
|
1546
1549
|
const lastSentJsonRef = useRef(null);
|
|
@@ -1549,9 +1552,9 @@ const RjsfSchemaEditor = ({ schema, value, onChange, readOnly, inForm, globalCon
|
|
|
1549
1552
|
if (dataJson !== stableStringify(valueRef.current)) {
|
|
1550
1553
|
if (lastSentJsonRef.current === null && mountedFormDataJsonRef.current && dataJson === mountedFormDataJsonRef.current) return;
|
|
1551
1554
|
lastSentJsonRef.current = dataJson;
|
|
1552
|
-
|
|
1555
|
+
handleValueChange(data);
|
|
1553
1556
|
}
|
|
1554
|
-
}, 100), []);
|
|
1557
|
+
}, 100), [handleValueChange]);
|
|
1555
1558
|
useEffect(() => () => debouncedOnChange.cancel(), [debouncedOnChange]);
|
|
1556
1559
|
const [prevValue, setPrevValue] = useState(value);
|
|
1557
1560
|
if (value !== prevValue) {
|
|
@@ -1580,10 +1583,6 @@ const RjsfSchemaEditor = ({ schema, value, onChange, readOnly, inForm, globalCon
|
|
|
1580
1583
|
}
|
|
1581
1584
|
debouncedOnChange(e.formData);
|
|
1582
1585
|
}, [debouncedOnChange]);
|
|
1583
|
-
const debouncedOnChangeRef = useRef(debouncedOnChange);
|
|
1584
|
-
debouncedOnChangeRef.current = debouncedOnChange;
|
|
1585
|
-
const setRootFormDataRef = useRef(setRootFormData);
|
|
1586
|
-
setRootFormDataRef.current = setRootFormData;
|
|
1587
1586
|
const formContext = useMemo(() => ({
|
|
1588
1587
|
setFormData: (data) => {
|
|
1589
1588
|
const merged = {
|
|
@@ -1592,16 +1591,16 @@ const RjsfSchemaEditor = ({ schema, value, onChange, readOnly, inForm, globalCon
|
|
|
1592
1591
|
};
|
|
1593
1592
|
initialDataRef.current = merged;
|
|
1594
1593
|
formDataRef.current = merged;
|
|
1595
|
-
|
|
1596
|
-
|
|
1594
|
+
setRootFormData(merged);
|
|
1595
|
+
debouncedOnChange.cancel();
|
|
1597
1596
|
lastSentJsonRef.current = stableStringify(merged);
|
|
1598
|
-
|
|
1597
|
+
handleValueChange(merged);
|
|
1599
1598
|
isInitialMountRef.current = true;
|
|
1600
1599
|
mountedFormDataJsonRef.current = null;
|
|
1601
1600
|
setFormKey((k) => k + 1);
|
|
1602
1601
|
},
|
|
1603
1602
|
getFormData: () => formDataRef.current
|
|
1604
|
-
}), []);
|
|
1603
|
+
}), [debouncedOnChange, handleValueChange]);
|
|
1605
1604
|
const formRef = useRef(null);
|
|
1606
1605
|
useEffect(() => {
|
|
1607
1606
|
if (onRegisterValidate) onRegisterValidate(() => {
|