@keboola/design 11.4.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.
Files changed (173) hide show
  1. package/AGENTS.md +191 -1
  2. package/CHANGELOG.md +358 -0
  3. package/COMPONENT-API.md +68 -47
  4. package/dist/{AIKit-DDg5DBCG.js → AIKit-CNX6aiKm.js} +208 -62
  5. package/dist/AIKit-CNX6aiKm.js.map +1 -0
  6. package/dist/{Alert-DHJFrWnS.js → Alert-Ba5b2YPq.js} +2 -2
  7. package/dist/{Alert-DHJFrWnS.js.map → Alert-Ba5b2YPq.js.map} +1 -1
  8. package/dist/{Badge-Ch26CXoP.js → Badge-D0pXdekt.js} +2 -2
  9. package/dist/Badge-D0pXdekt.js.map +1 -0
  10. package/dist/{BrandEditor-Go7w8Zj2.js → BrandEditor-CSANsxUz.js} +6 -6
  11. package/dist/{BrandEditor-Go7w8Zj2.js.map → BrandEditor-CSANsxUz.js.map} +1 -1
  12. package/dist/{BrandLogo-Dmi7jo21.js → BrandLogo-CoKBk4MI.js} +4 -4
  13. package/dist/BrandLogo-CoKBk4MI.js.map +1 -0
  14. package/dist/{Breadcrumb-uEkM6adI.js → Breadcrumb-g_xn_-Nf.js} +2 -2
  15. package/dist/{Breadcrumb-uEkM6adI.js.map → Breadcrumb-g_xn_-Nf.js.map} +1 -1
  16. package/dist/{Checkbox-fC0BuO2B.js → Checkbox-CUIn2jap.js} +2 -2
  17. package/dist/{Checkbox-fC0BuO2B.js.map → Checkbox-CUIn2jap.js.map} +1 -1
  18. package/dist/{Clipboard-ChPdiUy3.js → Clipboard-BTW6C-b_.js} +2 -2
  19. package/dist/{Clipboard-ChPdiUy3.js.map → Clipboard-BTW6C-b_.js.map} +1 -1
  20. package/dist/{ClipboardButton-D9pDjgkB.js → ClipboardButton-CwZJdRaz.js} +2 -2
  21. package/dist/{ClipboardButton-D9pDjgkB.js.map → ClipboardButton-CwZJdRaz.js.map} +1 -1
  22. package/dist/{CodeEditor-Cxy3HnKH.js → CodeEditor-C9zy7PxK.js} +6 -6
  23. package/dist/{CodeEditor-Cxy3HnKH.js.map → CodeEditor-C9zy7PxK.js.map} +1 -1
  24. package/dist/{ColorInput-Bxj-1eLT.js → ColorInput-BZV-u_94.js} +3 -3
  25. package/dist/{ColorInput-Bxj-1eLT.js.map → ColorInput-BZV-u_94.js.map} +1 -1
  26. package/dist/{Combobox-Cs_1pj2q.js → Combobox-BfIfaVMA.js} +273 -104
  27. package/dist/Combobox-BfIfaVMA.js.map +1 -0
  28. package/dist/{Command-B7ML9YMv.js → Command-Bfa1kpbt.js} +2 -2
  29. package/dist/{Command-B7ML9YMv.js.map → Command-Bfa1kpbt.js.map} +1 -1
  30. package/dist/{CopyField-BO_sh-HO.js → CopyField-DpT0Ngz1.js} +2 -2
  31. package/dist/{CopyField-BO_sh-HO.js.map → CopyField-DpT0Ngz1.js.map} +1 -1
  32. package/dist/{DateInput-ZdaMQo5i.js → DateInput-DiEd5uCL.js} +3 -3
  33. package/dist/{DateInput-ZdaMQo5i.js.map → DateInput-DiEd5uCL.js.map} +1 -1
  34. package/dist/{DateRangeInput-DkvNh_sT.js → DateRangeInput-DPfVYchl.js} +3 -3
  35. package/dist/{DateRangeInput-DkvNh_sT.js.map → DateRangeInput-DPfVYchl.js.map} +1 -1
  36. package/dist/{FieldItem-CCd9-xnp.js → FieldItem-B7XMmZSz.js} +3 -3
  37. package/dist/{FieldItem-CCd9-xnp.js.map → FieldItem-B7XMmZSz.js.map} +1 -1
  38. package/dist/{Form-k6PH-em3.js → Form-CsttTHn4.js} +7 -7
  39. package/dist/Form-CsttTHn4.js.map +1 -0
  40. package/dist/{FormGroup-DbcDtrgU.js → FormGroup-DHvTFdno.js} +3 -3
  41. package/dist/{FormGroup-DbcDtrgU.js.map → FormGroup-DHvTFdno.js.map} +1 -1
  42. package/dist/{InputGroup-BnLHY0eq.js → InputGroup-DcZRlVnN.js} +22 -14
  43. package/dist/InputGroup-DcZRlVnN.js.map +1 -0
  44. package/dist/{Kbd-CvSM3D3-.js → Kbd-Cvvt91Q8.js} +14 -4
  45. package/dist/Kbd-Cvvt91Q8.js.map +1 -0
  46. package/dist/{MermaidDiagram-WkonYErO.js → MermaidDiagram-CXG5tC6J.js} +19 -18
  47. package/dist/MermaidDiagram-CXG5tC6J.js.map +1 -0
  48. package/dist/{MultiActionButtonGroup-CxWH7yWK.js → MultiActionButtonGroup-DokHbPgM.js} +2 -2
  49. package/dist/{MultiActionButtonGroup-CxWH7yWK.js.map → MultiActionButtonGroup-DokHbPgM.js.map} +1 -1
  50. package/dist/{Navbar-B2UsolVU.js → Navbar-Liy1TPI7.js} +6 -6
  51. package/dist/{Navbar-B2UsolVU.js.map → Navbar-Liy1TPI7.js.map} +1 -1
  52. package/dist/PageHeader-Q3IpCnQd.js.map +1 -1
  53. package/dist/{PageToolbar-DnbFt14Q.js → PageToolbar-DExqEYGl.js} +2 -2
  54. package/dist/{PageToolbar-DnbFt14Q.js.map → PageToolbar-DExqEYGl.js.map} +1 -1
  55. package/dist/{Popconfirm-CILjmzKI.js → Popconfirm-5pBzT_HQ.js} +10 -11
  56. package/dist/{Popconfirm-CILjmzKI.js.map → Popconfirm-5pBzT_HQ.js.map} +1 -1
  57. package/dist/{RadioGroup-XFzFd1ti.js → RadioGroup-DXPbSj8P.js} +2 -2
  58. package/dist/{RadioGroup-XFzFd1ti.js.map → RadioGroup-DXPbSj8P.js.map} +1 -1
  59. package/dist/{Search-4Bxtt8hS.js → Search-5uQAiNIP.js} +2 -2
  60. package/dist/{Search-4Bxtt8hS.js.map → Search-5uQAiNIP.js.map} +1 -1
  61. package/dist/{SearchInput-f_oY9T4Z.js → SearchInput-D4UgAXJK.js} +3 -3
  62. package/dist/{SearchInput-f_oY9T4Z.js.map → SearchInput-D4UgAXJK.js.map} +1 -1
  63. package/dist/{SectionNav-BpJlisbT.js → SectionNav-OkKCjSA-.js} +3 -3
  64. package/dist/{SectionNav-BpJlisbT.js.map → SectionNav-OkKCjSA-.js.map} +1 -1
  65. package/dist/{Select-DpcgKqKB.js → Select-DV3Hak_l.js} +3 -4
  66. package/dist/Select-DV3Hak_l.js.map +1 -0
  67. package/dist/{Sidebar-Cm6I4dE1.js → Sidebar-D3cY1kha.js} +44 -20
  68. package/dist/Sidebar-D3cY1kha.js.map +1 -0
  69. package/dist/{Slider-pPC_3gz9.js → Slider-CRf-bB4y.js} +2 -2
  70. package/dist/{Slider-pPC_3gz9.js.map → Slider-CRf-bB4y.js.map} +1 -1
  71. package/dist/{Switch-ChfPKcTE.js → Switch-B0WdGSjz.js} +7 -7
  72. package/dist/{Switch-ChfPKcTE.js.map → Switch-B0WdGSjz.js.map} +1 -1
  73. package/dist/{TextInput-DHM6dHmn.js → TextInput-DH5SkbsE.js} +3 -3
  74. package/dist/{TextInput-DHM6dHmn.js.map → TextInput-DH5SkbsE.js.map} +1 -1
  75. package/dist/{ThemeProvider-DrQJtzpd.js → ThemeProvider-2RMdVGxO.js} +17 -12
  76. package/dist/{ThemeProvider-DrQJtzpd.js.map → ThemeProvider-2RMdVGxO.js.map} +1 -1
  77. package/dist/{Timeline-6btyJl4D.js → Timeline-BG5Xogxh.js} +11 -11
  78. package/dist/{Timeline-6btyJl4D.js.map → Timeline-BG5Xogxh.js.map} +1 -1
  79. package/dist/{Workbench-BzE-Vvd9.js → Workbench-UR2FBC7I.js} +3 -1
  80. package/dist/Workbench-UR2FBC7I.js.map +1 -0
  81. package/dist/{ZoomableSvg-BWnDkR61.js → ZoomableSvg-pooPb1Cu.js} +3 -3
  82. package/dist/{ZoomableSvg-BWnDkR61.js.map → ZoomableSvg-pooPb1Cu.js.map} +1 -1
  83. package/dist/editors.js +4 -4
  84. package/dist/flint.js +134 -8
  85. package/dist/flint.js.map +1 -1
  86. package/dist/index.d.ts +537 -135
  87. package/dist/index.js +40 -39
  88. package/dist/internal/blocks/AIKit.js +2 -2
  89. package/dist/internal/blocks/AuthLayout.js +118 -0
  90. package/dist/internal/blocks/AuthLayout.js.map +1 -0
  91. package/dist/internal/blocks/BrandEditor.js +1 -1
  92. package/dist/internal/blocks/ClipboardButton.js +1 -1
  93. package/dist/internal/blocks/ColorInput.js +1 -1
  94. package/dist/internal/blocks/Command.js +1 -1
  95. package/dist/internal/blocks/CopyField.js +1 -1
  96. package/dist/internal/blocks/DateInput.js +1 -1
  97. package/dist/internal/blocks/DateRangeInput.js +1 -1
  98. package/dist/internal/blocks/ExportMenu.js +1 -1
  99. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
  100. package/dist/internal/blocks/Form.js +1 -1
  101. package/dist/internal/blocks/FormGroup.js +1 -1
  102. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
  103. package/dist/internal/blocks/MultiCombobox.js +107 -48
  104. package/dist/internal/blocks/MultiCombobox.js.map +1 -1
  105. package/dist/internal/blocks/NumberInput.js +1 -1
  106. package/dist/internal/blocks/PageToolbar.js +1 -1
  107. package/dist/internal/blocks/PasswordInput.js +2 -2
  108. package/dist/internal/blocks/SearchInput.js +1 -1
  109. package/dist/internal/blocks/SearchInputWithNavigation.js +2 -2
  110. package/dist/internal/blocks/SectionNav.js +1 -1
  111. package/dist/internal/blocks/TextInput.js +1 -1
  112. package/dist/internal/blocks/Textarea.js +1 -1
  113. package/dist/internal/blocks/TimeInput.js +2 -2
  114. package/dist/internal/components/Alert.js +1 -1
  115. package/dist/internal/components/Avatar.js +1 -1
  116. package/dist/internal/components/Badge.js +1 -1
  117. package/dist/internal/components/BrandLogo.js +1 -1
  118. package/dist/internal/components/Breadcrumb.js +1 -1
  119. package/dist/internal/components/Checkbox.js +1 -1
  120. package/dist/internal/components/Clipboard.js +1 -1
  121. package/dist/internal/components/CollapsiblePanel.js +1 -1
  122. package/dist/internal/components/Combobox.js +2 -2
  123. package/dist/internal/components/InputGroup.js +1 -1
  124. package/dist/internal/components/Kbd.js +1 -1
  125. package/dist/internal/components/Navbar.js +1 -1
  126. package/dist/internal/components/Popconfirm.js +1 -1
  127. package/dist/internal/components/RadioGroup.js +1 -1
  128. package/dist/internal/components/Search.js +1 -1
  129. package/dist/internal/components/Select.js +1 -1
  130. package/dist/internal/components/Sidebar.js +1 -1
  131. package/dist/internal/components/Slider.js +1 -1
  132. package/dist/internal/components/Switch.js +1 -1
  133. package/dist/internal/components/ThemeProvider.js +1 -1
  134. package/dist/internal/components/Timeline.js +1 -1
  135. package/dist/internal/components/Tooltip.js +1 -1
  136. package/dist/internal/components/Truncated.js +1 -1
  137. package/dist/internal/components/Workbench.js +1 -1
  138. package/dist/internal/components/ZoomableSvg.js +1 -1
  139. package/dist/internal/utils.js +2 -2
  140. package/dist/markdown-editor.js +29 -23
  141. package/dist/markdown-editor.js.map +1 -1
  142. package/dist/mermaid.js +1 -1
  143. package/dist/rjsf.js +22 -23
  144. package/dist/rjsf.js.map +1 -1
  145. package/dist/styles.css +1 -1
  146. package/dist/testing.js +1 -1
  147. package/dist/{useColorSchemeState-klihG9-i.js → themeScopeContext-D7fSyb06.js} +16 -3
  148. package/dist/themeScopeContext-D7fSyb06.js.map +1 -0
  149. package/dist/{themeTokens-D70HeNVF.js → themeTokens-qP1-55O7.js} +37 -10
  150. package/dist/themeTokens-qP1-55O7.js.map +1 -0
  151. package/dist/{utils-B5Z52hYs.js → utils-DSvrhU8E.js} +6 -2
  152. package/dist/{utils-B5Z52hYs.js.map → utils-DSvrhU8E.js.map} +1 -1
  153. package/dist/vega.d.ts +1 -1
  154. package/dist/vega.js +3 -3
  155. package/dist/vega.js.map +1 -1
  156. package/dist/{vegaTheme-DfoEQhOy.js → vegaTheme-CSvFEMBl.js} +6 -6
  157. package/dist/vegaTheme-CSvFEMBl.js.map +1 -0
  158. package/package.json +12 -10
  159. package/src/styles.css +3 -0
  160. package/dist/AIKit-DDg5DBCG.js.map +0 -1
  161. package/dist/Badge-Ch26CXoP.js.map +0 -1
  162. package/dist/BrandLogo-Dmi7jo21.js.map +0 -1
  163. package/dist/Combobox-Cs_1pj2q.js.map +0 -1
  164. package/dist/Form-k6PH-em3.js.map +0 -1
  165. package/dist/InputGroup-BnLHY0eq.js.map +0 -1
  166. package/dist/Kbd-CvSM3D3-.js.map +0 -1
  167. package/dist/MermaidDiagram-WkonYErO.js.map +0 -1
  168. package/dist/Select-DpcgKqKB.js.map +0 -1
  169. package/dist/Sidebar-Cm6I4dE1.js.map +0 -1
  170. package/dist/Workbench-BzE-Vvd9.js.map +0 -1
  171. package/dist/themeTokens-D70HeNVF.js.map +0 -1
  172. package/dist/useColorSchemeState-klihG9-i.js.map +0 -1
  173. package/dist/vegaTheme-DfoEQhOy.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { cn } from "../classNames-BzrkDnOD.js";
2
- import { copyToClipboard, createChangeInputEvent, createPrefixedString, debounce, isMac, noop, useSHA256, withHiddenFullscreen, withTooltipProvider } from "../utils-B5Z52hYs.js";
2
+ import { copyToClipboard, createChangeInputEvent, createPrefixedString, debounce, isMac, noop, useSHA256, withHiddenFullscreen, withTooltipProvider, withVisualSettle } from "../utils-DSvrhU8E.js";
3
3
  import { findLiteralMatches, findLiteralTermMatches, hasLiteralMatch } from "../findLiteralMatches-BGBw8Vbl.js";
4
4
  import { mergeRefs } from "./utils/mergeRefs.js";
5
- export { cn, copyToClipboard, createChangeInputEvent, createPrefixedString, debounce, findLiteralMatches, findLiteralTermMatches, hasLiteralMatch, isMac, mergeRefs, noop, useSHA256, withHiddenFullscreen, withTooltipProvider };
5
+ export { cn, copyToClipboard, createChangeInputEvent, createPrefixedString, debounce, findLiteralMatches, findLiteralTermMatches, hasLiteralMatch, isMac, mergeRefs, noop, useSHA256, withHiddenFullscreen, withTooltipProvider, withVisualSettle };
@@ -1,12 +1,13 @@
1
1
  import { cn } from "./classNames-BzrkDnOD.js";
2
- import { Tooltip } from "./utils-B5Z52hYs.js";
2
+ import { Tooltip } from "./utils-DSvrhU8E.js";
3
3
  import { AlignCenter, AlignJustify, AlignLeft, AlignRight, Bold, ChevronDown, Code, Heading1, Heading2, Heading3, Italic, Link, List, ListOrdered, Quote, SquareCode, Strikethrough, Type, Underline } from "./icons-Cek151jC.js";
4
4
  import { Button } from "./Button-DsRrU5F1.js";
5
5
  import { ButtonGroup } from "./internal/components/ButtonGroup.js";
6
6
  import { DropdownMenu } from "./DropdownMenu-CASr-jgl.js";
7
7
  import { Label } from "./internal/components/Label.js";
8
- import { TextInput } from "./TextInput-DHM6dHmn.js";
9
- import { FormGroup } from "./FormGroup-DbcDtrgU.js";
8
+ import { useStableCallback } from "./internal/hooks/useStableCallback.js";
9
+ import { TextInput } from "./TextInput-DH5SkbsE.js";
10
+ import { FormGroup } from "./FormGroup-DHvTFdno.js";
10
11
  import { Skeleton } from "./internal/components/Skeleton/Skeleton.js";
11
12
  import { toast } from "./toast-DIC0iNRf.js";
12
13
  import { Suspense, createContext, lazy, use, useCallback, useEffect, useRef, useState } from "react";
@@ -140,7 +141,7 @@ const $isImageNode = (node) => {
140
141
  };
141
142
  //#endregion
142
143
  //#region src/blocks/MarkdownEditor/nodes/MermaidNodeComponent.tsx
143
- const MermaidDiagram = lazy(() => import("./MermaidDiagram-WkonYErO.js").then((n) => n.MermaidDiagram_exports).then((m) => ({ default: m.MermaidDiagram }), (error) => {
144
+ const MermaidDiagram = lazy(() => import("./MermaidDiagram-CXG5tC6J.js").then((n) => n.MermaidDiagram_exports).then((m) => ({ default: m.MermaidDiagram }), (error) => {
144
145
  console.error("[MarkdownEditor] failed to load MermaidDiagram chunk", error);
145
146
  return { default: ({ code }) => /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: code }) }) };
146
147
  }));
@@ -236,12 +237,11 @@ const getImageFilesFromDataTransfer = (dataTransfer) => {
236
237
  const escapeMarkdownAlt = (text) => text.replace(/[[\]()]/g, "");
237
238
  const ImagePastePlugin = ({ onImageUpload }) => {
238
239
  const [editor] = useLexicalComposerContext();
239
- const onImageUploadRef = useRef(onImageUpload);
240
- onImageUploadRef.current = onImageUpload;
240
+ const canUploadImages = onImageUpload != null;
241
+ const uploadImage = useStableCallback((file) => onImageUpload?.(file));
241
242
  useEffect(() => {
242
243
  const uploadFile = (file) => {
243
- const upload = onImageUploadRef.current;
244
- if (!upload) return;
244
+ if (!canUploadImages) return;
245
245
  if (file.size > MAX_IMAGE_SIZE) {
246
246
  toast.error(`Image "${file.name}" is too large. Maximum size is 10 MB.`);
247
247
  return;
@@ -254,7 +254,7 @@ const ImagePastePlugin = ({ onImageUpload }) => {
254
254
  });
255
255
  if (!nodeKey) return;
256
256
  const capturedKey = nodeKey;
257
- upload(file).then(({ url }) => {
257
+ uploadImage(file)?.then(({ url }) => {
258
258
  editor.update(() => {
259
259
  const node = $getNodeByKey(capturedKey);
260
260
  if ($isImageNode(node)) {
@@ -273,7 +273,7 @@ const ImagePastePlugin = ({ onImageUpload }) => {
273
273
  });
274
274
  };
275
275
  const removePaste = editor.registerCommand(PASTE_COMMAND, (event) => {
276
- if (!onImageUploadRef.current) return false;
276
+ if (!canUploadImages) return false;
277
277
  if (!(event instanceof ClipboardEvent)) return false;
278
278
  const files = getImageFilesFromDataTransfer(event.clipboardData);
279
279
  if (files.length === 0) return false;
@@ -282,7 +282,7 @@ const ImagePastePlugin = ({ onImageUpload }) => {
282
282
  return true;
283
283
  }, COMMAND_PRIORITY_CRITICAL);
284
284
  const removeDrop = editor.registerCommand(DROP_COMMAND, (event) => {
285
- if (!onImageUploadRef.current) return false;
285
+ if (!canUploadImages) return false;
286
286
  const files = getImageFilesFromDataTransfer(event.dataTransfer);
287
287
  if (files.length === 0) return false;
288
288
  event.preventDefault();
@@ -293,17 +293,19 @@ const ImagePastePlugin = ({ onImageUpload }) => {
293
293
  removePaste();
294
294
  removeDrop();
295
295
  };
296
- }, [editor]);
296
+ }, [
297
+ editor,
298
+ canUploadImages,
299
+ uploadImage
300
+ ]);
297
301
  return null;
298
302
  };
299
303
  //#endregion
300
304
  //#region src/blocks/MarkdownEditor/plugins/KeyboardPlugin.tsx
301
305
  const KeyboardPlugin = ({ onSave, onCancel, singleLine, blurOnEscape, skipBlurSaveRef }) => {
302
306
  const [editor] = useLexicalComposerContext();
303
- const onSaveRef = useRef(onSave);
304
- onSaveRef.current = onSave;
305
- const onCancelRef = useRef(onCancel);
306
- onCancelRef.current = onCancel;
307
+ const handleSave = useStableCallback(() => onSave?.());
308
+ const handleCancel = useStableCallback(() => onCancel?.());
307
309
  const singleLineRef = useRef(singleLine);
308
310
  singleLineRef.current = singleLine;
309
311
  const blurOnEscapeRef = useRef(blurOnEscape);
@@ -313,7 +315,7 @@ const KeyboardPlugin = ({ onSave, onCancel, singleLine, blurOnEscape, skipBlurSa
313
315
  return editor.registerCommand(KEY_DOWN_COMMAND, (event) => {
314
316
  if (event.key === "Enter" && (event.ctrlKey || event.metaKey)) {
315
317
  event.preventDefault();
316
- onSaveRef.current?.();
318
+ handleSave();
317
319
  return true;
318
320
  }
319
321
  if (event.key === "Enter" && !event.shiftKey && !event.altKey && singleLineRef.current) {
@@ -323,13 +325,18 @@ const KeyboardPlugin = ({ onSave, onCancel, singleLine, blurOnEscape, skipBlurSa
323
325
  }
324
326
  if (event.key === "Escape" && blurOnEscapeRef.current) {
325
327
  if (skipBlurSaveExternalRef) skipBlurSaveExternalRef.current = true;
326
- onCancelRef.current?.();
328
+ handleCancel();
327
329
  editor.getRootElement()?.blur();
328
330
  return true;
329
331
  }
330
332
  return false;
331
333
  }, COMMAND_PRIORITY_HIGH);
332
- }, [editor, skipBlurSaveExternalRef]);
334
+ }, [
335
+ editor,
336
+ skipBlurSaveExternalRef,
337
+ handleSave,
338
+ handleCancel
339
+ ]);
333
340
  return null;
334
341
  };
335
342
  /**
@@ -468,8 +475,7 @@ const IMPORT_TAG = "markdown-import";
468
475
  const MarkdownSyncPlugin = ({ value, editable, onChange, transformers = CUSTOM_TRANSFORMERS, singleLine = false }) => {
469
476
  const [editor] = useLexicalComposerContext();
470
477
  const lastExportedRef = useRef(value);
471
- const onChangeRef = useRef(onChange);
472
- onChangeRef.current = onChange;
478
+ const handleChange = useStableCallback((markdown) => onChange?.(markdown));
473
479
  const transformersRef = useRef(transformers);
474
480
  transformersRef.current = transformers;
475
481
  const singleLineRef = useRef(singleLine);
@@ -492,11 +498,11 @@ const MarkdownSyncPlugin = ({ value, editable, onChange, transformers = CUSTOM_T
492
498
  const markdown = singleLineRef.current ? unescapeMarkdownText(raw) : postprocessMarkdown(raw);
493
499
  if (markdown !== lastExportedRef.current) {
494
500
  lastExportedRef.current = markdown;
495
- onChangeRef.current?.(markdown);
501
+ handleChange(markdown);
496
502
  }
497
503
  });
498
504
  });
499
- }, [editor]);
505
+ }, [editor, handleChange]);
500
506
  return null;
501
507
  };
502
508
  //#endregion
@@ -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: `![alt](src)` */\nconst IMAGE: TextMatchTransformer = {\n dependencies: [ImageNode],\n export: (node) => {\n if (!$isImageNode(node)) return null;\n return `![${node.getAlt()}](${node.getSrc()})`;\n },\n importRegExp: /!\\[([^\\]]*)\\]\\(([^)]+)\\)/,\n regExp: /!\\[([^\\]]*)\\]\\(([^)]+)\\)$/,\n replace: (textNode, match) => {\n const [, alt = '', src = ''] = match;\n const imageNode = $createImageNode(src, alt);\n textNode.replace(imageNode);\n },\n trigger: ')',\n type: 'text-match',\n};\n\n/** Horizontal rule: `---`, `***`, or `___` */\nconst HORIZONTAL_RULE: ElementTransformer = {\n dependencies: [HorizontalRuleNode],\n export: (node) => {\n return $isHorizontalRuleNode(node) ? '---' : null;\n },\n regExp: /^(---|\\*\\*\\*|___)$/,\n replace: (parentNode) => {\n const node = $createHorizontalRuleNode();\n parentNode.replace(node);\n },\n type: 'element',\n};\n\n/** Fenced mermaid block: ` ```mermaid ... ``` ` → MermaidNode (rendered as diagram) */\nconst MERMAID: MultilineElementTransformer = {\n dependencies: [MermaidNode],\n export: (node) => {\n if (!$isMermaidNode(node)) return null;\n return '```mermaid\\n' + node.getCode() + '\\n```';\n },\n regExpStart: /^[ \\t]*(`{3,})mermaid(?:\\s.*)?$/,\n regExpEnd: {\n optional: true,\n regExp: /^[ \\t]*`{3,}$/,\n },\n replace: (rootNode, _children, _startMatch, _endMatch, linesInBetween) => {\n if (!linesInBetween) return;\n const code = linesInBetween.join('\\n').trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n },\n handleImportAfterStartMatch: ({\n lines,\n rootNode,\n startLineIndex,\n startMatch,\n }): [boolean, number] => {\n const fence = startMatch[1];\n if (!fence) return [false, startLineIndex];\n const fenceLength = fence.trim().length;\n const endRegex = new RegExp(`^[ \\\\t]*\\`{${fenceLength},}$`);\n\n for (let i = startLineIndex + 1; i < lines.length; i++) {\n if (endRegex.test(lines[i] ?? '')) {\n const code = lines\n .slice(startLineIndex + 1, i)\n .join('\\n')\n .trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n return [true, i];\n }\n }\n\n // No closing fence — consume remaining lines\n const code = lines\n .slice(startLineIndex + 1)\n .join('\\n')\n .trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n return [true, lines.length - 1];\n },\n type: 'multiline-element',\n};\n\n/**\n * 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 `![alt](url)` 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 * (`![alt](url)` 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: `![alt](src)` */\nconst IMAGE: TextMatchTransformer = {\n dependencies: [ImageNode],\n export: (node) => {\n if (!$isImageNode(node)) return null;\n return `![${node.getAlt()}](${node.getSrc()})`;\n },\n importRegExp: /!\\[([^\\]]*)\\]\\(([^)]+)\\)/,\n regExp: /!\\[([^\\]]*)\\]\\(([^)]+)\\)$/,\n replace: (textNode, match) => {\n const [, alt = '', src = ''] = match;\n const imageNode = $createImageNode(src, alt);\n textNode.replace(imageNode);\n },\n trigger: ')',\n type: 'text-match',\n};\n\n/** Horizontal rule: `---`, `***`, or `___` */\nconst HORIZONTAL_RULE: ElementTransformer = {\n dependencies: [HorizontalRuleNode],\n export: (node) => {\n return $isHorizontalRuleNode(node) ? '---' : null;\n },\n regExp: /^(---|\\*\\*\\*|___)$/,\n replace: (parentNode) => {\n const node = $createHorizontalRuleNode();\n parentNode.replace(node);\n },\n type: 'element',\n};\n\n/** Fenced mermaid block: ` ```mermaid ... ``` ` → MermaidNode (rendered as diagram) */\nconst MERMAID: MultilineElementTransformer = {\n dependencies: [MermaidNode],\n export: (node) => {\n if (!$isMermaidNode(node)) return null;\n return '```mermaid\\n' + node.getCode() + '\\n```';\n },\n regExpStart: /^[ \\t]*(`{3,})mermaid(?:\\s.*)?$/,\n regExpEnd: {\n optional: true,\n regExp: /^[ \\t]*`{3,}$/,\n },\n replace: (rootNode, _children, _startMatch, _endMatch, linesInBetween) => {\n if (!linesInBetween) return;\n const code = linesInBetween.join('\\n').trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n },\n handleImportAfterStartMatch: ({\n lines,\n rootNode,\n startLineIndex,\n startMatch,\n }): [boolean, number] => {\n const fence = startMatch[1];\n if (!fence) return [false, startLineIndex];\n const fenceLength = fence.trim().length;\n const endRegex = new RegExp(`^[ \\\\t]*\\`{${fenceLength},}$`);\n\n for (let i = startLineIndex + 1; i < lines.length; i++) {\n if (endRegex.test(lines[i] ?? '')) {\n const code = lines\n .slice(startLineIndex + 1, i)\n .join('\\n')\n .trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n return [true, i];\n }\n }\n\n // No closing fence — consume remaining lines\n const code = lines\n .slice(startLineIndex + 1)\n .join('\\n')\n .trim();\n if (code) {\n rootNode.append($createMermaidNode(code));\n }\n return [true, lines.length - 1];\n },\n type: 'multiline-element',\n};\n\n/**\n * 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 `![alt](url)` 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 * (`![alt](url)` 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-WkonYErO.js";
1
+ import { MermaidDiagram } from "./MermaidDiagram-CXG5tC6J.js";
2
2
  export { MermaidDiagram };