noteloom 0.3.2 → 0.4.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 (104) hide show
  1. package/README.md +344 -53
  2. package/bin/noteloom.mjs +139 -0
  3. package/dist/canvas.cjs +2 -0
  4. package/dist/canvas.cjs.map +1 -0
  5. package/dist/canvas.d.ts +2 -0
  6. package/dist/canvas.js +5 -0
  7. package/dist/canvas.js.map +1 -0
  8. package/dist/collab.cjs +2 -0
  9. package/dist/collab.cjs.map +1 -0
  10. package/dist/collab.d.ts +19 -0
  11. package/dist/collab.js +379 -0
  12. package/dist/collab.js.map +1 -0
  13. package/dist/comments.cjs +2 -0
  14. package/dist/comments.cjs.map +1 -0
  15. package/dist/comments.d.ts +17 -0
  16. package/dist/comments.js +19 -0
  17. package/dist/comments.js.map +1 -0
  18. package/dist/index.cjs +2 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.ts +392 -32
  21. package/dist/index.js +3983 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/persistence.cjs +2 -0
  24. package/dist/persistence.cjs.map +1 -0
  25. package/dist/persistence.d.ts +11 -0
  26. package/dist/persistence.js +12 -0
  27. package/dist/persistence.js.map +1 -0
  28. package/dist/shared/CommentAvatar-TKqsM8vG.js +53 -0
  29. package/dist/shared/CommentAvatar-TKqsM8vG.js.map +1 -0
  30. package/dist/shared/CommentAvatar-V457IgoQ.cjs +2 -0
  31. package/dist/shared/CommentAvatar-V457IgoQ.cjs.map +1 -0
  32. package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs +2 -0
  33. package/dist/shared/CommentThreadCard-CAJ3oPdr.cjs.map +1 -0
  34. package/dist/shared/CommentThreadCard-Cxf8GwHJ.js +213 -0
  35. package/dist/shared/CommentThreadCard-Cxf8GwHJ.js.map +1 -0
  36. package/dist/shared/CommentsPanel-BwVVyMOC.js +76 -0
  37. package/dist/shared/CommentsPanel-BwVVyMOC.js.map +1 -0
  38. package/dist/shared/CommentsPanel-CES4uzye.cjs +2 -0
  39. package/dist/shared/CommentsPanel-CES4uzye.cjs.map +1 -0
  40. package/dist/shared/VersionHistory-Bg6fufP5.js +1120 -0
  41. package/dist/shared/VersionHistory-Bg6fufP5.js.map +1 -0
  42. package/dist/shared/VersionHistory-DELa2Wbq.cjs +12 -0
  43. package/dist/shared/VersionHistory-DELa2Wbq.cjs.map +1 -0
  44. package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js +338 -0
  45. package/dist/shared/VoiceListeningIndicator-BOfVmLK0.js.map +1 -0
  46. package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs +2 -0
  47. package/dist/shared/VoiceListeningIndicator-DNX8JlQM.cjs.map +1 -0
  48. package/dist/shared/fieldRegistry-BoYyW3GH.cjs +2 -0
  49. package/dist/shared/fieldRegistry-BoYyW3GH.cjs.map +1 -0
  50. package/dist/shared/fieldRegistry-PjJWXFoB.js +223 -0
  51. package/dist/shared/fieldRegistry-PjJWXFoB.js.map +1 -0
  52. package/dist/shared/icons-C1_s0jKK.js +4269 -0
  53. package/dist/shared/icons-C1_s0jKK.js.map +1 -0
  54. package/dist/shared/icons-DtCsXuU6.cjs +3531 -0
  55. package/dist/shared/icons-DtCsXuU6.cjs.map +1 -0
  56. package/dist/shared/index-B9jyyL8u.js +2145 -0
  57. package/dist/shared/index-B9jyyL8u.js.map +1 -0
  58. package/dist/shared/index-D9WEXpYM.cjs +2 -0
  59. package/dist/shared/index-D9WEXpYM.cjs.map +1 -0
  60. package/dist/shared/indexedDbPersistence-BKlGPFTP.js +112 -0
  61. package/dist/shared/indexedDbPersistence-BKlGPFTP.js.map +1 -0
  62. package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs +2 -0
  63. package/dist/shared/indexedDbPersistence-BWJ1h5Vp.cjs.map +1 -0
  64. package/dist/shared/leafBlockFactory-A9eUhSe-.js +335 -0
  65. package/dist/shared/leafBlockFactory-A9eUhSe-.js.map +1 -0
  66. package/dist/shared/leafBlockFactory-Dp382eP8.cjs +2 -0
  67. package/dist/shared/leafBlockFactory-Dp382eP8.cjs.map +1 -0
  68. package/dist/shared/serialize-DWEfk0vU.cjs +3 -0
  69. package/dist/shared/serialize-DWEfk0vU.cjs.map +1 -0
  70. package/dist/shared/serialize-T9Odwx24.js +86 -0
  71. package/dist/shared/serialize-T9Odwx24.js.map +1 -0
  72. package/dist/shared/starter-kit-CY5wzYDf.js +4980 -0
  73. package/dist/shared/starter-kit-CY5wzYDf.js.map +1 -0
  74. package/dist/shared/starter-kit-lPN-NpJ5.cjs +27 -0
  75. package/dist/shared/starter-kit-lPN-NpJ5.cjs.map +1 -0
  76. package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs +2 -0
  77. package/dist/shared/usePopoverEdgeClamp-CDG26jBM.cjs.map +1 -0
  78. package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js +109 -0
  79. package/dist/shared/usePopoverEdgeClamp-gmFm0CnI.js.map +1 -0
  80. package/dist/shared/useServiceWorkerUpdate-BduabXv6.js +94 -0
  81. package/dist/shared/useServiceWorkerUpdate-BduabXv6.js.map +1 -0
  82. package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs +2 -0
  83. package/dist/shared/useServiceWorkerUpdate-DQboGesi.cjs.map +1 -0
  84. package/dist/starter-kit.cjs +2 -0
  85. package/dist/starter-kit.cjs.map +1 -0
  86. package/dist/starter-kit.d.ts +9 -0
  87. package/dist/starter-kit.js +10 -0
  88. package/dist/starter-kit.js.map +1 -0
  89. package/dist/style.css +3529 -3200
  90. package/dist/versions.cjs +2 -0
  91. package/dist/versions.cjs.map +1 -0
  92. package/dist/versions.d.ts +11 -0
  93. package/dist/versions.js +13 -0
  94. package/dist/versions.js.map +1 -0
  95. package/dist/voice.cjs +2 -0
  96. package/dist/voice.cjs.map +1 -0
  97. package/dist/voice.d.ts +7 -0
  98. package/dist/voice.js +8 -0
  99. package/dist/voice.js.map +1 -0
  100. package/package.json +159 -92
  101. package/dist/noteloom.cjs +0 -3209
  102. package/dist/noteloom.cjs.map +0 -1
  103. package/dist/noteloom.es.js +0 -14622
  104. package/dist/noteloom.es.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"noteloom.cjs","sources":["../src/store/operations.js","../src/crdt/clock.js","../src/crdt/listCrdt.js","../src/crdt/fieldRegistry.js","../src/crdt/textDiff.js","../src/utils/idGen.js","../src/store/EditorStore.js","../src/store/history.js","../src/crdt/gc.js","../src/sync/syncProtocol.js","../src/sync/peerConnection.js","../src/sync/CollabSession.js","../src/sync/websocketSignaling.js","../src/persistence/indexedDbPersistence.js","../src/persistence/autoPersist.js","../src/clipboard/serialize.js","../src/templates/blockTemplates.js","../src/react/useTemplates.js","../src/react/TemplatePicker.jsx","../src/clipboard/exportDocument.js","../src/versions/autoVersionHistory.js","../src/versions/diffVersions.js","../src/react/useDocumentVersions.js","../src/style.css?raw","../src/react/injectDefaultStyles.js","../src/react/EditorProvider.jsx","../src/react/commentFormatting.js","../src/react/CommentAvatar.jsx","../src/react/icons.jsx","../src/react/VersionHistory.jsx","../src/comments/commentMarks.js","../src/comments/comments.js","../src/react/useComments.js","../src/react/CommentComposer.jsx","../src/react/CommentThreadCard.jsx","../src/react/CommentsPanel.jsx","../src/registry/blockRegistry.js","../src/registry/inlineRegistry.js","../src/react/useBlock.js","../src/react/domRunSync.js","../src/blocks/shared/blockEmpty.js","../src/blocks/shared/contentless.js","../src/react/focusRun.js","../src/react/Modal.jsx","../src/react/LinkEditModal.jsx","../src/react/popoverPosition.js","../src/react/useAutoAdjustedPosition.js","../src/react/LinkHoverCard.jsx","../src/react/CommentPopoverHeader.jsx","../src/react/CommentPopover.jsx","../src/react/EditableBlockContent.jsx","../src/blocks/shared/navigationCommands.js","../src/react/selectionResolve.js","../src/blocks/shared/blockCommands.js","../src/blocks/shared/leafBlockFactory.js","../src/blocks/shared/ensureRootNonEmpty.js","../src/blocks/shared/mergeCommands.js","../src/blocks/shared/focusAfterMerge.js","../src/blocks/shared/resolveBlockDir.js","../src/blocks/shared/convertBlockType.js","../src/blocks/paragraph/markdownShortcuts.js","../src/blocks/paragraph/ParagraphBlock.jsx","../src/inline/marks.js","../src/inline/runOps.js","../src/blocks/paragraph/index.js","../src/blocks/heading/HeadingBlock.jsx","../src/blocks/heading/index.js","../src/react/useBlockChildren.js","../src/react/BlockErrorBoundary.jsx","../src/react/BlockRenderer.jsx","../src/react/useOutsideClickAndEscape.js","../src/react/useMenuKeyboardNav.js","../src/react/liveAnnouncer.js","../src/blocks/callout/createCalloutBlock.js","../src/blocks/shared/turnInto.js","../src/react/TurnIntoSubmenu.jsx","../src/blocks/shared/blockActions.js","../src/react/BlockGutterRow.jsx","../src/react/BlockChildren.jsx","../src/blocks/listItem/listMarkers.js","../src/blocks/listItem/createListItemBlock.js","../src/blocks/listItem/indentCommands.js","../src/blocks/listItem/mergeCommands.js","../src/blocks/listItem/exitListItem.js","../src/blocks/listItem/ListItemBlock.jsx","../src/blocks/listItem/index.js","../src/blocks/table/tableColumns.js","../src/blocks/table/tableEditCommands.js","../src/react/usePopoverEdgeClamp.js","../src/react/useVirtualKeyboardInset.js","../src/react/Select.jsx","../src/blocks/table/tagColors.js","../src/blocks/table/TableHeaderRow.jsx","../src/blocks/table/TableBlock.jsx","../src/blocks/table/TableRowBlock.jsx","../src/blocks/table/tableNavigation.js","../src/blocks/table/TableCellBlock.jsx","../src/blocks/table/createTableBlock.js","../src/blocks/table/index.js","../src/blocks/layout/LayoutBlock.jsx","../src/blocks/layout/LayoutColumnBlock.jsx","../src/blocks/layout/createLayoutBlock.js","../src/blocks/layout/index.js","../src/blocks/divider/DividerBlock.jsx","../src/blocks/divider/index.js","../src/blocks/callout/CalloutBlock.jsx","../src/blocks/callout/index.js","../src/blocks/blockquote/BlockquoteBlock.jsx","../src/blocks/blockquote/index.js","../src/blocks/code/CodeBlock.jsx","../src/blocks/code/index.js","../src/blocks/toggleHeading/mergeCommands.js","../src/blocks/toggleHeading/ToggleHeadingBlock.jsx","../src/blocks/toggleHeading/createToggleHeadingBlock.js","../src/blocks/toggleHeading/index.js","../src/blocks/button/ButtonEditModal.jsx","../src/blocks/button/ButtonBlock.jsx","../src/blocks/button/createButtonBlock.js","../src/blocks/button/index.js","../src/blocks/embed/EmbedBlock.jsx","../src/blocks/embed/createEmbedBlock.js","../src/blocks/embed/index.js","../src/blocks/canvas/strokeOutline.js","../src/blocks/canvas/canvasGeometry.js","../src/blocks/canvas/shapeGeometry.js","../src/blocks/shared/useDragResize.js","../src/blocks/canvas/createCanvasBlock.js","../src/blocks/canvas/zOrder.js","../src/blocks/canvas/exportSvg.js","../src/blocks/canvas/CanvasBlock.jsx","../src/blocks/canvas/index.js","../src/blocks/index.js","../src/inlineTypes/select/SelectInlineNode.jsx","../src/inlineTypes/shared/insertInlineRun.js","../src/inlineTypes/select/index.js","../src/inlineTypes/date/DateInlineNode.jsx","../src/inlineTypes/date/index.js","../src/inlineTypes/checkbox/CheckboxInlineNode.jsx","../src/inlineTypes/checkbox/index.js","../src/inlineTypes/tableSelect/TableSelectInlineNode.jsx","../src/inlineTypes/tableSelect/index.js","../src/inlineTypes/emoji/index.js","../src/inlineTypes/index.js","../src/react/useEditor.js","../src/react/EditorTrailingSpace.jsx","../src/clipboard/copyBlockRange.js","../src/blocks/shared/blockRangeActions.js","../src/react/BlockRangeActionMenu.jsx","../src/clipboard/mimeType.js","../src/clipboard/domWalk.js","../src/clipboard/deserialize.js","../src/inline/deleteCommands.js","../src/react/useClipboardHandlers.js","../src/inline/markCommands.js","../src/react/selectAllCommand.js","../src/blocks/shared/deleteSelectedBlock.js","../src/react/restoreHistorySelection.js","../src/react/useEditorKeyboardShortcuts.js","../src/react/useBlockRangeDrag.js","../src/commands/SlashMenu.jsx","../src/commands/useTriggerMenu.js","../src/commands/useSlashMenuTrigger.js","../src/inlineTypes/emoji/emojiList.js","../src/inlineTypes/shared/insertPlainText.js","../src/inlineTypes/emoji/emojiCommands.js","../src/commands/useEmojiMenuTrigger.js","../src/commands/useAtMenuTrigger.js","../src/commands/useTextFormattingActions.js","../src/react/useCoarsePointer.js","../src/commands/FloatingToolbar.jsx","../src/commands/useFloatingToolbarTrigger.js","../src/react/NoteloomEditor.jsx","../src/react/useFieldTypes.js","../src/react/useHistory.js","../src/react/usePersistedDocument.js","../src/react/usePresence.js","../src/react/useServiceWorkerUpdate.js","../src/voice/voiceCommands.js","../src/voice/applyVoiceAction.js","../src/react/useVoiceTyping.js","../src/react/VoicePermissionModal.jsx","../src/react/useCaretRect.js","../src/react/VoiceListeningIndicator.jsx","../src/react/MobileBlockPickerSheet.jsx","../src/react/MobileBlockOptionsSheet.jsx","../src/react/MobileActionBar.jsx","../src/clipboard/simpleFormat.js","../src/react/DocumentExportButton.jsx","../src/inlineTypes/customSelect/CustomSelectInlineNode.jsx","../src/inlineTypes/customSelect/createSelectFieldType.jsx","../src/inlineTypes/customSelect/registerStoredFieldTypes.js","../src/inlineTypes/customSelect/useRegisterFieldTypes.js","../src/inlineTypes/customSelect/FieldTypeEditorModal.jsx"],"sourcesContent":["export const OP = {\r\n INSERT_BLOCK: 'insertBlock',\r\n REMOVE_BLOCK: 'removeBlock',\r\n MOVE_BLOCK: 'moveBlock',\r\n CHANGE_BLOCK_TYPE: 'changeBlockType',\r\n UPDATE_BLOCK_PROPS: 'updateBlockProps',\r\n UPDATE_RUN: 'updateRun',\r\n SET_BLOCK_CONTENT_IDS: 'setBlockContentIds',\r\n REPLACE_RUN_SPAN: 'replaceRunSpan',\r\n SET_BLOCK_RUNS: 'setBlockRuns',\r\n EDIT_RUN_CHARS: 'editRunChars',\r\n ADD_FIELD_TYPE: 'addFieldType',\r\n UPDATE_FIELD_TYPE: 'updateFieldType',\r\n REMOVE_FIELD_TYPE: 'removeFieldType',\r\n ADD_COMMENT_THREAD: 'addCommentThread',\r\n REMOVE_COMMENT_THREAD: 'removeCommentThread',\r\n ADD_COMMENT_REPLY: 'addCommentReply',\r\n REMOVE_COMMENT_REPLY: 'removeCommentReply',\r\n RESOLVE_COMMENT: 'resolveComment',\r\n};\r\n\r\nexport function insertBlock(block, parentId, index, subtree) {\r\n return { type: OP.INSERT_BLOCK, block, parentId, index, subtree };\r\n}\r\n\r\nexport function removeBlock(id) {\r\n return { type: OP.REMOVE_BLOCK, id };\r\n}\r\n\r\nexport function moveBlock(id, toParentId, toIndex) {\r\n return { type: OP.MOVE_BLOCK, id, toParentId, toIndex };\r\n}\r\n\r\nexport function updateBlockProps(id, patch) {\r\n return { type: OP.UPDATE_BLOCK_PROPS, id, patch };\r\n}\r\n\r\n/**\r\n * Changes a block's own `type` and wholesale-replaces its `props`, keeping\r\n * its id (and therefore its parentId/contentIds/subscribers) exactly as\r\n * they are — the in-place counterpart to \"delete the old block, insert a\r\n * new one of a different type.\" Keeping the id stable is what lets a CRDT\r\n * merge concurrent type-conversions of the same block as one field-level\r\n * conflict (last-write-wins) instead of two unrelated structural edits.\r\n * `blockType` (not `type`) to avoid colliding with the operation envelope's\r\n * own `type` key.\r\n */\r\nexport function changeBlockType(id, blockType, props) {\r\n return { type: OP.CHANGE_BLOCK_TYPE, id, blockType, props };\r\n}\r\n\r\nexport function updateRun(id, patch) {\r\n return { type: OP.UPDATE_RUN, id, patch };\r\n}\r\n\r\n/**\r\n * Tombstones `tombstoneIds` and restores `restoreIds` within a run's own\r\n * character CRDT (see EditorStore's `_getRunOrder`/`_editRunText`) — the\r\n * precise undo/redo counterpart to a text `updateRun`, used instead of a\r\n * whole-value replace so undoing your own edit only ever touches the\r\n * character ids YOU inserted/deleted, never a peer's concurrent edit to\r\n * the same run. Deliberately self-inverting: applying this op's own\r\n * returned inverse is just this same op with the two arrays swapped, which\r\n * is what makes undo/redo of a text edit cycle correctly back and forth.\r\n *\r\n * `previousValue`, when given, is a cosmetic-only plain-string snapshot of\r\n * the run's value right before the edit this is the inverse of — used\r\n * exclusively by History's caret-restoration (`computeEntrySelection`) and\r\n * opt-in change log (`getChangeLog`), never for undo's actual data\r\n * correctness (that's the tombstone/restore ids above).\r\n */\r\nexport function editRunChars(id, tombstoneIds, restoreIds, previousValue) {\r\n return { type: OP.EDIT_RUN_CHARS, id, tombstoneIds, restoreIds, previousValue };\r\n}\r\n\r\n/** Directly reassigns a block's contentIds array (e.g. merging one block's runs into another). */\r\nexport function setBlockContentIds(blockId, contentIds) {\r\n return { type: OP.SET_BLOCK_CONTENT_IDS, blockId, contentIds };\r\n}\r\n\r\n/**\r\n * Replaces a contiguous span of existing run ids within a leaf block's\r\n * contentIds with a new set of run objects — e.g. splitting one run into\r\n * before/formatted-middle/after when toggling a mark on part of its text.\r\n * `oldRunIds` must be contiguous in the block's current contentIds.\r\n */\r\nexport function replaceRunSpan(blockId, oldRunIds, newRuns) {\r\n return { type: OP.REPLACE_RUN_SPAN, blockId, oldRunIds, newRuns };\r\n}\r\n\r\n/**\r\n * Wholesale replaces a leaf block's entire run list (and their order) —\r\n * the \"I don't know exactly what changed structurally, just resync\r\n * everything\" escape hatch used when reconciling arbitrary DOM mutations\r\n * (paste-into-contentEditable, IME composition boundaries) back into the\r\n * store. Prefer per-run `updateRun` when only text values changed — this\r\n * op is coarser-grained for undo (one step for the whole resync).\r\n */\r\nexport function setBlockRuns(blockId, runs) {\r\n return { type: OP.SET_BLOCK_RUNS, blockId, runs };\r\n}\r\n\r\n/**\r\n * Persists a user-created custom select field type (see\r\n * createSelectFieldType / registerStoredFieldTypes) — `fieldType` is\r\n * `{ id, label, placeholder, variant, options: [{value,label,color?}] }`.\r\n * Only ever used for STATIC, in-editor-authored types; code-registered\r\n * (developer-defined, possibly dynamic/DB-backed) field types never go\r\n * through the store at all.\r\n */\r\nexport function addFieldType(fieldType) {\r\n return { type: OP.ADD_FIELD_TYPE, fieldType };\r\n}\r\n\r\nexport function updateFieldType(id, patch) {\r\n return { type: OP.UPDATE_FIELD_TYPE, id, patch };\r\n}\r\n\r\nexport function removeFieldType(id) {\r\n return { type: OP.REMOVE_FIELD_TYPE, id };\r\n}\r\n\r\n/**\r\n * Adds a comment thread — `thread` is `{ id, blockId, anchorRunIds,\r\n * resolved, messages }` (see src/comments/comments.js's addComment, which\r\n * is the documented entry point; this raw op is exposed for advanced use\r\n * the same way editRunChars is). Unlike ADD_FIELD_TYPE/UPDATE_FIELD_TYPE/\r\n * REMOVE_FIELD_TYPE (which are local-only in collaboration today), comment\r\n * thread ops DO set a wire envelope and DO have an applyRemoteOperation\r\n * case — see EditorStore.\r\n */\r\nexport function addCommentThread(thread) {\r\n return { type: OP.ADD_COMMENT_THREAD, thread };\r\n}\r\n\r\nexport function removeCommentThread(commentId) {\r\n return { type: OP.REMOVE_COMMENT_THREAD, commentId };\r\n}\r\n\r\n/** Appends `message` ({ id, authorId, text, createdAt }) to an existing thread's messages. */\r\nexport function addCommentReply(commentId, message) {\r\n return { type: OP.ADD_COMMENT_REPLY, commentId, message };\r\n}\r\n\r\n/** The precise inverse of addCommentReply — removes one reply by its own id (not the whole thread). */\r\nexport function removeCommentReply(commentId, messageId) {\r\n return { type: OP.REMOVE_COMMENT_REPLY, commentId, messageId };\r\n}\r\n\r\nexport function resolveComment(commentId, resolved) {\r\n return { type: OP.RESOLVE_COMMENT, commentId, resolved };\r\n}\r\n","/**\n * Hybrid Logical Clock — a (wallTime, counter, peerId) timestamp used to\n * totally order concurrent edits across peers without a central server.\n * wallTime keeps timestamps meaningful as real time (e.g. \"edited 2 min\n * ago\"); counter breaks ties when multiple local events share a wallTime;\n * peerId breaks ties deterministically when both wallTime and counter\n * match across peers.\n */\nexport class HLC {\n constructor(peerId) {\n this.peerId = peerId;\n this.wallTime = 0;\n this.counter = 0;\n }\n\n /** Local event (a user's own edit). Returns the stamped timestamp. */\n tick() {\n const now = Date.now();\n if (now > this.wallTime) {\n this.wallTime = now;\n this.counter = 0;\n } else {\n this.counter += 1;\n }\n return { wallTime: this.wallTime, counter: this.counter, peerId: this.peerId };\n }\n\n /**\n * Merges in a timestamp observed from a remote peer, advancing this\n * clock so subsequent local ticks are guaranteed to sort after\n * anything just received.\n */\n receive(remote) {\n const now = Date.now();\n const maxWall = Math.max(now, this.wallTime, remote.wallTime);\n if (maxWall === this.wallTime && maxWall === remote.wallTime) {\n this.counter = Math.max(this.counter, remote.counter) + 1;\n } else if (maxWall === this.wallTime) {\n this.counter += 1;\n } else if (maxWall === remote.wallTime) {\n this.counter = remote.counter + 1;\n } else {\n this.counter = 0;\n }\n this.wallTime = maxWall;\n return { wallTime: this.wallTime, counter: this.counter, peerId: this.peerId };\n }\n\n /** Total order: wallTime, then counter, then peerId. */\n static compare(a, b) {\n if (a.wallTime !== b.wallTime) return a.wallTime - b.wallTime;\n if (a.counter !== b.counter) return a.counter - b.counter;\n if (a.peerId === b.peerId) return 0;\n return a.peerId < b.peerId ? -1 : 1;\n }\n}\n\nexport function genPeerId() {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `peer-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n","import { HLC } from './clock.js';\n\n/**\n * Replicated ordered list, keyed by externally-owned stable ids (Noteloom's\n * existing block/run ids — this module never generates ids, only orders\n * and tombstones the ones it's given). Each item's position is defined\n * relative to a neighbor id (\"insert after X\"), not an array index, so\n * concurrent inserts/deletes at different local positions merge\n * deterministically regardless of what order the operations are applied\n * in on a given peer.\n *\n * Concurrent inserts anchored to the exact same origin are ordered\n * newest-first (by clock, then peerId) so a live edit lands as close to\n * its anchor as possible. Sequential inserts from one peer/batch (each\n * anchored to the id it just inserted, not re-anchored to the original\n * origin — the natural way typing and multi-block paste already work)\n * are never split apart by a concurrent peer's insert at the same\n * origin. A concurrent *non-chained* multi-item insert at the same\n * anchor by two peers can still interleave with this simpler\n * (RGA-style) scheme; convergence still holds, only interleave-avoidance\n * is partial rather than the full Fugue tree guarantee.\n */\nexport class ListCrdtState {\n constructor() {\n this.slots = new Map();\n }\n\n /** Builds CRDT state from an existing plain-array order (e.g. loading a v1 document with no CRDT history). */\n static fromArray(ids, { peerId = 'legacy' } = {}) {\n const state = new ListCrdtState();\n let prev = null;\n for (const id of ids) {\n state.slots.set(id, {\n id,\n originId: prev,\n peerId,\n clock: { wallTime: 0, counter: 0, peerId },\n deleted: false,\n });\n prev = id;\n }\n return state;\n }\n\n has(id) {\n return this.slots.has(id);\n }\n\n /** The raw slot for `id` ({id, originId, peerId, clock, deleted}), or undefined — used to build a wire envelope for a change that was just made. */\n getSlot(id) {\n return this.slots.get(id);\n }\n\n isDeleted(id) {\n const slot = this.slots.get(id);\n return !slot || slot.deleted;\n }\n\n /**\n * Inserts `id` immediately after `afterId` (null = at the very start).\n * Idempotent: re-inserting an id that already has a slot is a no-op,\n * which guards against duplicate delivery over an unreliable transport.\n */\n insert(id, afterId, clock, peerId) {\n if (this.slots.has(id)) return;\n this.slots.set(id, { id, originId: afterId, peerId, clock, deleted: false });\n }\n\n /**\n * `clock` records WHEN the delete happened (used by pruneTombstones to\n * judge tombstone age) — deliberately a separate value from whatever\n * clock the slot already had from insertion/move, which recorded a\n * different thing (when its POSITION was last established). Without\n * this, an old-but-just-deleted slot would look ancient from the\n * moment it's deleted (inheriting its original insertion time, however\n * long ago that was) and become immediately GC-eligible.\n */\n delete(id, clock) {\n const slot = this.slots.get(id);\n if (!slot) return;\n slot.deleted = true;\n if (clock) slot.deletedClock = clock;\n }\n\n /** Undoes a local delete in place, preserving the slot's original position. */\n restore(id) {\n const slot = this.slots.get(id);\n if (!slot) return;\n slot.deleted = false;\n }\n\n /**\n * Repositions an existing slot to a new anchor in place, rather than\n * tombstoning it and creating a new one — there is only ever one slot\n * per id in a given list, so a same-list reorder (or moving a block\n * back to a parent it was in before) must reuse it. Local-only for now:\n * concurrent moves of the same id by two peers have no defined merge\n * rule yet (last local move simply wins), since there's no remote path\n * exercising this until the transport layer exists.\n *\n * Splices the slot out of the chain BEFORE re-anchoring it: anything\n * currently anchored directly after `id` gets reparented to `id`'s old\n * origin first. Without this, moving a node to an anchor that's\n * currently one of its own (transitive) successors creates a cycle —\n * e.g. a->b->c, \"move a to after c\" naively sets a.originId='c', but\n * c.originId is (transitively) 'a', so the walk from the list start can\n * no longer reach any of them. Splicing `id` out first means whatever\n * anchor is chosen can never depend on `id` still being where it was.\n */\n move(id, afterId, clock, peerId) {\n if (afterId === id) return;\n const slot = this.slots.get(id);\n if (!slot) return;\n const oldOriginId = slot.originId;\n for (const other of this.slots.values()) {\n if (other.originId === id) other.originId = oldOriginId;\n }\n slot.originId = afterId;\n slot.peerId = peerId;\n slot.clock = clock;\n slot.deleted = false;\n }\n\n /**\n * Merges another peer's slot set into this one. Safe to call with\n * slots in any order, any number of times — idempotent, commutative,\n * and associative — which is what makes convergence hold regardless\n * of network delivery order.\n */\n merge(remoteSlots) {\n for (const remote of remoteSlots) {\n const local = this.slots.get(remote.id);\n if (!local) {\n this.slots.set(remote.id, { ...remote });\n } else if (remote.deleted && !local.deleted) {\n local.deleted = true;\n }\n // originId/peerId/clock never change after a slot is created —\n // a slot's structural identity is fixed at insert time; `deleted`\n // is the only field that can change, and only monotonically\n // (existence-wins: once deleted, always deleted).\n }\n }\n\n /** Every slot as a plain array, for persistence/transport. */\n toSlotArray() {\n return Array.from(this.slots.values());\n }\n\n /** How many tombstoned (deleted but still retained) slots this list is currently carrying — for deciding whether GC is worth running, or just observing growth. */\n tombstoneCount() {\n let count = 0;\n for (const slot of this.slots.values()) {\n if (slot.deleted) count += 1;\n }\n return count;\n }\n\n /**\n * Permanently removes tombstoned slots whose delete happened before\n * `beforeClock` — the actual fix for the \"deleted content is never\n * garbage-collected\" limitation. Splices each removed slot out of the\n * chain first (children reparented to its own origin, same technique\n * as `move()`) so removal never orphans a slot anchored to it. Returns\n * the number of slots actually removed.\n *\n * Safety of this is specifically tied to how this package's transport\n * layer reconnects: `CollabSession` resyncs a reconnecting peer via a\n * full document snapshot (see syncResponse in CollabSession.js), never\n * by replaying a log of historical ops — so a peer that was offline\n * longer than any reasonable GC threshold never needs an old tombstone\n * to resolve a stale anchor; it just adopts the current state directly.\n * The one theoretical residual risk is a single already-open connection\n * somehow stalling for exactly as long as the GC threshold and then\n * delivering an old queued message afterward — vanishingly unlikely for\n * a live, ordered, reliable data channel (which disconnects long before\n * that under any real network interruption), but not mathematically\n * impossible, which is why this is opt-in rather than automatic.\n */\n pruneTombstones(beforeClock) {\n let removed = 0;\n for (const [id, slot] of this.slots) {\n if (!slot.deleted) continue;\n // deletedClock (when it was actually deleted) is what age means\n // here -- falling back to the slot's own clock (when its position\n // was established) only for a slot deleted before this field\n // existed, which otherwise has no recorded deletion time at all.\n const age = slot.deletedClock ?? slot.clock;\n if (HLC.compare(age, beforeClock) >= 0) continue; // not old enough yet\n for (const other of this.slots.values()) {\n if (other.originId === id) other.originId = slot.originId;\n }\n this.slots.delete(id);\n removed += 1;\n }\n return removed;\n }\n\n /**\n * Materializes the currently-visible order as a plain array of ids\n * (tombstoned ids excluded) — this is what gets projected onto\n * Block.contentIds after every structural change.\n */\n toArray() {\n const childrenByOrigin = new Map();\n for (const slot of this.slots.values()) {\n const bucket = childrenByOrigin.get(slot.originId);\n if (bucket) bucket.push(slot);\n else childrenByOrigin.set(slot.originId, [slot]);\n }\n for (const bucket of childrenByOrigin.values()) {\n bucket.sort((a, b) => HLC.compare(b.clock, a.clock));\n }\n\n const result = [];\n // Explicit-stack depth-first walk — a naive recursive walk's depth\n // equals the list length on a long simple chain (the common case for\n // typed/sequential content), which risks a stack overflow on large\n // documents.\n const stack = [...(childrenByOrigin.get(null) ?? [])].reverse();\n while (stack.length > 0) {\n const slot = stack.pop();\n if (!slot.deleted) result.push(slot.id);\n const children = childrenByOrigin.get(slot.id);\n if (children) {\n for (let i = children.length - 1; i >= 0; i -= 1) stack.push(children[i]);\n }\n }\n return result;\n }\n}\n","import { HLC } from './clock.js';\n\n/**\n * Tracks the logical-clock high-water mark for individual mutable fields\n * (a block's type, one prop key, a run's value, ...) so that when a\n * remote peer's write arrives it's only applied if it's actually newer\n * than whatever's already there — last-write-wins, scoped per field\n * rather than per whole block/run, so unrelated concurrent edits (peer A\n * changes the type, peer B changes a prop) both survive.\n */\nexport class FieldClockRegistry {\n constructor() {\n this.clocks = new Map();\n }\n\n static compositeKey(id, field) {\n return `${id}:${field}`;\n }\n\n get(id, field) {\n return this.clocks.get(FieldClockRegistry.compositeKey(id, field)) ?? null;\n }\n\n /** Local write: always wins outright — it just happened, nothing to compare against. */\n recordLocal(id, field, clock) {\n this.clocks.set(FieldClockRegistry.compositeKey(id, field), clock);\n }\n\n /**\n * Whether a remote write to this field should be applied. Callers must\n * check this before mutating so a stale remote write can be discarded\n * without ever touching local state.\n */\n shouldApplyRemote(id, field, remoteClock) {\n const current = this.get(id, field);\n if (!current) return true;\n return HLC.compare(remoteClock, current) > 0;\n }\n\n recordRemote(id, field, remoteClock) {\n this.clocks.set(FieldClockRegistry.compositeKey(id, field), remoteClock);\n }\n}\n","/**\n * Finds the common-prefix/common-suffix boundary between two strings,\n * operating on Unicode code points (via `Array.from`) rather than raw\n * UTF-16 units, so a surrogate pair can never be split across two\n * character-CRDT slots. Returns the changed region as code-point indices:\n * `oldChars[start, oldEnd)` was removed, `newChars[start, newEnd)` was\n * inserted in its place — everything outside `[start, max(oldEnd,newEnd))`\n * is unchanged. Same algorithm as History's own `diffValueOffsets` (used\n * there purely for caret-position cosmetics on a UTF-16 string), reused\n * here for the actual data-merge boundary, which is why it needs to be\n * code-point aware rather than just close enough.\n */\nexport function diffCodePoints(oldValue, newValue) {\n const oldChars = Array.from(oldValue ?? '');\n const newChars = Array.from(newValue ?? '');\n let start = 0;\n const maxStart = Math.min(oldChars.length, newChars.length);\n while (start < maxStart && oldChars[start] === newChars[start]) start += 1;\n\n let oldEnd = oldChars.length;\n let newEnd = newChars.length;\n while (oldEnd > start && newEnd > start && oldChars[oldEnd - 1] === newChars[newEnd - 1]) {\n oldEnd -= 1;\n newEnd -= 1;\n }\n\n return { start, oldEnd, newEnd, oldChars, newChars };\n}\n","export function genId() {\r\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n return crypto.randomUUID();\r\n }\r\n return `id-${Date.now()}-${Math.random().toString(36).slice(2)}`;\r\n}\r\n","import {\r\n OP,\r\n insertBlock,\r\n removeBlock,\r\n moveBlock,\r\n changeBlockType,\r\n updateBlockProps,\r\n updateRun,\r\n editRunChars,\r\n setBlockContentIds,\r\n replaceRunSpan,\r\n setBlockRuns,\r\n addFieldType,\r\n updateFieldType,\r\n removeFieldType,\r\n addCommentThread,\r\n removeCommentThread,\r\n addCommentReply,\r\n removeCommentReply,\r\n resolveComment,\r\n} from './operations.js';\r\nimport { ListCrdtState } from '../crdt/listCrdt.js';\r\nimport { HLC, genPeerId } from '../crdt/clock.js';\r\nimport { FieldClockRegistry } from '../crdt/fieldRegistry.js';\r\nimport { diffCodePoints } from '../crdt/textDiff.js';\r\nimport { genId } from '../utils/idGen.js';\r\n\r\n/** Sentinel subscribe/notify key for \"the fieldTypes collection changed\" — see useFieldTypes. */\r\nconst FIELD_TYPES_KEY = '$fieldTypes';\r\n\r\n/** Sentinel subscribe/notify key for \"the comments collection changed\" — see useComments. */\r\nconst COMMENTS_KEY = '$comments';\r\n\r\n/**\r\n * Flat, normalized document store with per-id pub-sub.\r\n *\r\n * Every write replaces only the object(s) whose data actually changed, so\r\n * `getBlock(id)`/`getRun(id)` return a referentially stable value across any\r\n * update that doesn't touch that exact id. That stability is what lets\r\n * `useSyncExternalStore` (in the React bindings) skip re-rendering anything\r\n * that wasn't part of a given operation.\r\n *\r\n * Whether a given child id in `contentIds` refers to another Block or to a\r\n * Run is never encoded on the store — it's discovered by membership (ids are\r\n * unique across both maps), which keeps the store decoupled from the block\r\n * type registry.\r\n */\r\nexport class EditorStore {\r\n constructor(doc) {\r\n this.blocks = new Map((doc?.blocks ?? []).map((b) => [b.id, b]));\r\n this.runs = new Map((doc?.runs ?? []).map((r) => [r.id, r]));\r\n this.rootId = doc?.rootId ?? null;\r\n this.fieldTypes = new Map((doc?.fieldTypes ?? []).map((f) => [f.id, f]));\r\n this._fieldTypesSnapshot = null; // invalidated (set to null) on every fieldTypes mutation — see getFieldTypes\r\n this.comments = new Map((doc?.comments ?? []).map((c) => [c.id, c]));\r\n this._commentsSnapshot = null; // invalidated (set to null) on every comments mutation — see getComments\r\n this._listeners = new Map(); // id -> Set<() => void>\r\n this._globalListeners = new Set(); // fired on every mutation regardless of which id(s) changed -- see subscribeAll\r\n\r\n // Collaborative-editing merge state. Not yet reachable from any remote\r\n // transport (that's a later phase) -- for now this only tracks logical\r\n // clocks and CRDT-safe ordering locally, so `type`/props/run edits and\r\n // block insert/remove/move are all merge-ready without changing any\r\n // observable behavior for a single local user. Session-scoped: not\r\n // persisted by toJSON/fromJSON, since there's no remote peer yet that\r\n // could need it to survive a reload.\r\n this._peerId = genPeerId();\r\n this._clock = new HLC(this._peerId);\r\n this._fieldClocks = new FieldClockRegistry();\r\n this._orders = new Map(); // parent block id -> ListCrdtState over its contentIds, lazily seeded on first touch — see _getOrder\r\n\r\n // Character-level text merge state — same lazy-seed-from-existing-data\r\n // relationship to `runs` that `_orders` has to `blocks`. `_runOrders`\r\n // orders a run's characters (ListCrdtState is fully generic over\r\n // whatever ids it's given, so it's reused as-is here, just one\r\n // instance per RUN instead of per parent BLOCK); `_runChars` holds the\r\n // actual character payload for each slot (ListCrdtState's slots carry\r\n // no value of their own); `_runValueSnapshots` memoizes the\r\n // materialized string per run (see _materializeRunValue), the same\r\n // invalidate-on-mutation convention `getFieldTypes()` already uses for\r\n // `_fieldTypesSnapshot`.\r\n this._runOrders = new Map();\r\n this._runChars = new Map();\r\n this._runValueSnapshots = new Map();\r\n }\r\n\r\n /** Lazily seeds a block's ordering CRDT state from its current (plain-array) contentIds the first time it's touched. */\r\n _getOrder(parentId) {\r\n let order = this._orders.get(parentId);\r\n if (!order) {\r\n const block = this.blocks.get(parentId);\r\n order = ListCrdtState.fromArray(block?.contentIds ?? [], { peerId: 'legacy' });\r\n this._orders.set(parentId, order);\r\n }\r\n return order;\r\n }\r\n\r\n /**\r\n * Lazily seeds a run's character-ordering CRDT state from its current\r\n * (plain-string) value the first time it's touched. Unlike blocks,\r\n * individual characters have no pre-existing stable id of their own —\r\n * BUT a fresh *random* one (genId()) can't be minted here the way\r\n * `_getRunOrder`'s block equivalent doesn't need to, because a block's\r\n * seed ids (its real `.id`s) are already identical on every peer (the\r\n * document itself was already synced); a run's *characters* aren't\r\n * separately synced at all, only its plain `value` string is. Two peers\r\n * independently lazy-seeding the same pre-existing text with random ids\r\n * would each invent a DIFFERENT id for \"the same\" character, so a\r\n * remote edit's `afterId` (anchored to the sender's random id) would\r\n * never resolve on the receiving side. Fix: ids for this initial seed\r\n * are DETERMINISTIC — `` `${runId}:legacyChar:${index}` `` — so any peer\r\n * seeding from the same starting string (guaranteed, since a peer only\r\n * ever needs to seed a run it has already received the full document\r\n * for) always mints the identical ids independently, with no\r\n * coordination required. Only ever used for this one-time seed; every\r\n * character inserted after that (by typing, on any peer) gets a real\r\n * `genId()`.\r\n */\r\n _getRunOrder(runId) {\r\n let order = this._runOrders.get(runId);\r\n if (!order) {\r\n const run = this.runs.get(runId);\r\n const chars = new Map();\r\n order = new ListCrdtState();\r\n let prev = null;\r\n let index = 0;\r\n for (const ch of Array.from(run?.value ?? '')) {\r\n const charId = `${runId}:legacyChar:${index}`;\r\n chars.set(charId, ch);\r\n order.insert(charId, prev, { wallTime: 0, counter: 0, peerId: 'legacy' }, 'legacy');\r\n prev = charId;\r\n index += 1;\r\n }\r\n this._runOrders.set(runId, order);\r\n this._runChars.set(runId, chars);\r\n }\r\n return order;\r\n }\r\n\r\n /** Materializes a run's current text from its character CRDT, memoized until that run's char order next changes. */\r\n _materializeRunValue(runId) {\r\n let value = this._runValueSnapshots.get(runId);\r\n if (value === undefined) {\r\n const order = this._getRunOrder(runId);\r\n const chars = this._runChars.get(runId);\r\n value = order.toArray().map((charId) => chars.get(charId)).join('');\r\n this._runValueSnapshots.set(runId, value);\r\n }\r\n return value;\r\n }\r\n\r\n /**\r\n * Diffs `newValue` against the run's current materialized value (common\r\n * prefix/suffix, code-point aware — see diffCodePoints) and translates\r\n * only the changed region into character-CRDT insert/delete ops. One\r\n * shared clock covers the whole edit — matching how a single\r\n * INSERT_BLOCK/REMOVE_BLOCK op already uses one tick() each — since\r\n * these characters are never independently reordered relative to each\r\n * other regardless of how many ticks they'd otherwise get.\r\n */\r\n _editRunText(runId, newValue) {\r\n const oldValue = this._materializeRunValue(runId);\r\n const { start, oldEnd, newEnd, newChars } = diffCodePoints(oldValue, newValue);\r\n const order = this._getRunOrder(runId);\r\n const chars = this._runChars.get(runId);\r\n const currentIds = order.toArray();\r\n const clock = this._clock.tick();\r\n\r\n const deletedCharIds = [];\r\n for (let i = start; i < oldEnd; i += 1) {\r\n const id = currentIds[i];\r\n order.delete(id, clock);\r\n deletedCharIds.push({ id, clock });\r\n }\r\n\r\n const insertedChars = [];\r\n let afterId = start > 0 ? currentIds[start - 1] : null;\r\n for (let i = start; i < newEnd; i += 1) {\r\n const id = genId();\r\n const ch = newChars[i];\r\n chars.set(id, ch);\r\n order.insert(id, afterId, clock, this._peerId);\r\n insertedChars.push({ id, char: ch, afterId, clock });\r\n afterId = id;\r\n }\r\n\r\n this._runValueSnapshots.delete(runId);\r\n return { oldValue, insertedChars, deletedCharIds, clock };\r\n }\r\n\r\n /**\r\n * Replays a previously-resolved text edit's EXACT character ids (from\r\n * `op._charEdit`, cached on first application — see the UPDATE_RUN case)\r\n * instead of re-diffing and minting fresh ones. Needed for `History`'s\r\n * redo, which replays the same op OBJECT a second time: re-diffing would\r\n * mint a brand-new set of ids rather than restoring the ones the\r\n * matching undo had only tombstoned, breaking a subsequent undo/redo\r\n * cycle (mirrors how INSERT_BLOCK's own handler restores an existing\r\n * slot via `order.restore()` on redo instead of creating a new one,\r\n * since a block's id is already stable across replay — characters have\r\n * no such built-in stable id, so this cache is what gives them one).\r\n */\r\n _replayRunTextEdit(runId, charEdit) {\r\n const order = this._getRunOrder(runId);\r\n const chars = this._runChars.get(runId);\r\n for (const c of charEdit.insertedChars) {\r\n if (order.has(c.id)) order.restore(c.id);\r\n else {\r\n chars.set(c.id, c.char);\r\n order.insert(c.id, c.afterId, c.clock, this._peerId);\r\n }\r\n }\r\n for (const d of charEdit.deletedCharIds) order.delete(d.id, d.clock);\r\n this._runValueSnapshots.delete(runId);\r\n }\r\n\r\n getBlock(id) {\r\n return this.blocks.get(id);\r\n }\r\n\r\n getRun(id) {\r\n return this.runs.get(id);\r\n }\r\n\r\n /**\r\n * Persisted, user-created custom select field types (static only) —\r\n * insertion order. Returns the SAME array reference across calls unless\r\n * a fieldTypes op ran in between — required for useSyncExternalStore\r\n * (see useFieldTypes), same reference-stability contract as\r\n * getBlock/getRun.\r\n */\r\n getFieldTypes() {\r\n if (!this._fieldTypesSnapshot) this._fieldTypesSnapshot = [...this.fieldTypes.values()];\r\n return this._fieldTypesSnapshot;\r\n }\r\n\r\n getFieldType(id) {\r\n return this.fieldTypes.get(id);\r\n }\r\n\r\n /**\r\n * Every comment thread — insertion order. Returns the SAME array\r\n * reference across calls unless a comments op ran in between — required\r\n * for useSyncExternalStore (see useComments), same contract as\r\n * getFieldTypes.\r\n */\r\n getComments() {\r\n if (!this._commentsSnapshot) this._commentsSnapshot = [...this.comments.values()];\r\n return this._commentsSnapshot;\r\n }\r\n\r\n getComment(id) {\r\n return this.comments.get(id);\r\n }\r\n\r\n /**\r\n * Every run id in the whole document, regardless of reachability from\r\n * the root — used by removeCommentMarkEverywhere (see\r\n * src/comments/commentMarks.js) to strip a deleted comment's id from\r\n * any run that still carries it, without needing a separate index.\r\n */\r\n getAllRunIds() {\r\n return [...this.runs.keys()];\r\n }\r\n\r\n getRootId() {\r\n return this.rootId;\r\n }\r\n\r\n subscribe(id, listener) {\r\n let set = this._listeners.get(id);\r\n if (!set) {\r\n set = new Set();\r\n this._listeners.set(id, set);\r\n }\r\n set.add(listener);\r\n return () => {\r\n set.delete(listener);\r\n if (set.size === 0) this._listeners.delete(id);\r\n };\r\n }\r\n\r\n /**\r\n * Fires on every mutation, local or remote (applyOperation and\r\n * applyRemoteOperation both funnel through _notify), regardless of\r\n * which specific id(s) changed — unlike subscribe(id, ...), which is\r\n * scoped to one id for render-isolation purposes. Meant for\r\n * whole-document concerns like auto-persistence, not for UI rendering\r\n * (a component re-rendering on every edit anywhere defeats the point of\r\n * per-id subscriptions).\r\n */\r\n subscribeAll(listener) {\r\n this._globalListeners.add(listener);\r\n return () => this._globalListeners.delete(listener);\r\n }\r\n\r\n _notify(touchedIds) {\r\n for (const id of touchedIds) {\r\n const set = this._listeners.get(id);\r\n if (!set) continue;\r\n // copy before iterating: a listener may unsubscribe during notification\r\n for (const listener of [...set]) listener();\r\n }\r\n if (this._globalListeners.size > 0) {\r\n for (const listener of [...this._globalListeners]) listener();\r\n }\r\n }\r\n\r\n /** Recursively collects a block (or run) and everything reachable under it. */\r\n _captureSubtree(rootId) {\r\n const blocks = [];\r\n const runs = [];\r\n const walk = (id) => {\r\n if (this.runs.has(id)) {\r\n runs.push(this.runs.get(id));\r\n return;\r\n }\r\n const block = this.blocks.get(id);\r\n if (!block) return;\r\n blocks.push(block);\r\n for (const childId of block.contentIds) walk(childId);\r\n // A block type (e.g. list_item) may hold its own inline runs in\r\n // props.titleRunIds alongside nested child blocks in contentIds.\r\n // Walk that too, generically, so nothing gets orphaned on delete.\r\n for (const runId of block.props?.titleRunIds ?? []) walk(runId);\r\n };\r\n walk(rootId);\r\n return { blocks, runs };\r\n }\r\n\r\n _deleteSubtree(rootId) {\r\n const walk = (id) => {\r\n if (this.runs.has(id)) {\r\n this.runs.delete(id);\r\n return;\r\n }\r\n const block = this.blocks.get(id);\r\n if (!block) return;\r\n for (const childId of block.contentIds) walk(childId);\r\n for (const runId of block.props?.titleRunIds ?? []) walk(runId);\r\n this.blocks.delete(id);\r\n };\r\n walk(rootId);\r\n }\r\n\r\n /**\r\n * Applies one operation, mutating only the affected map entries, and\r\n * returns the inverse operation (computed from state captured *before* the\r\n * mutation, per-op — never reconstructed afterward).\r\n */\r\n applyOperation(op) {\r\n switch (op.type) {\r\n case OP.UPDATE_RUN: {\r\n const run = this.runs.get(op.id);\r\n const patchKeys = Object.keys(op.patch);\r\n\r\n // The overwhelmingly common (and, per every real call site in this\r\n // codebase, the ONLY observed) shape: a lone `value` key, from\r\n // typing. Routed through this run's own character CRDT instead of\r\n // whole-value LWW, so concurrent edits to the same run interleave\r\n // instead of one clobbering the other, and undo can precisely\r\n // reverse only the characters THIS actor touched (via\r\n // EDIT_RUN_CHARS below) instead of replaying a stale whole-string\r\n // snapshot that can clobber a peer's concurrent edit. Any other\r\n // patch shape (marks, an atomic chip's `data`, or — never observed\r\n // in practice — `value` mixed with another key) keeps the\r\n // original whole-field LWW path below.\r\n if (patchKeys.length === 1 && patchKeys[0] === 'value') {\r\n let charEdit = op._charEdit;\r\n if (charEdit) {\r\n this._replayRunTextEdit(op.id, charEdit); // redo: reuse the exact ids from the first application\r\n } else {\r\n const { oldValue, insertedChars, deletedCharIds, clock } = this._editRunText(op.id, op.patch.value);\r\n charEdit = { oldValue, insertedChars, deletedCharIds, clock };\r\n op._charEdit = charEdit; // cached on the op object itself so a future redo replays these same ids -- see _replayRunTextEdit\r\n }\r\n const newValue = this._materializeRunValue(op.id);\r\n this.runs.set(op.id, { ...run, value: newValue });\r\n this._lastEnvelope = {\r\n kind: 'runTextEdit',\r\n runId: op.id,\r\n insertedChars: charEdit.insertedChars,\r\n deletedCharIds: charEdit.deletedCharIds,\r\n clock: charEdit.clock,\r\n };\r\n this._notify([op.id]);\r\n return editRunChars(\r\n op.id,\r\n charEdit.insertedChars.map((c) => c.id), // undo: tombstone what was just inserted...\r\n charEdit.deletedCharIds.map((c) => c.id), // ...and restore what was just deleted\r\n charEdit.oldValue, // cosmetic-only, for History's caret restoration/change log -- see editRunChars's own doc comment\r\n );\r\n }\r\n\r\n const previousPatch = {};\r\n const clocks = {};\r\n for (const key of patchKeys) {\r\n previousPatch[key] = run[key];\r\n clocks[key] = this._clock.tick();\r\n this._fieldClocks.recordLocal(op.id, key, clocks[key]);\r\n }\r\n this.runs.set(op.id, { ...run, ...op.patch });\r\n this._lastEnvelope = { kind: 'fieldWrite', target: 'run', id: op.id, patch: op.patch, clocks };\r\n this._notify([op.id]);\r\n return updateRun(op.id, previousPatch);\r\n }\r\n\r\n case OP.EDIT_RUN_CHARS: {\r\n const order = this._getRunOrder(op.id);\r\n const clock = this._clock.tick();\r\n for (const charId of op.tombstoneIds) order.delete(charId, clock);\r\n for (const charId of op.restoreIds) order.restore(charId);\r\n this._runValueSnapshots.delete(op.id);\r\n const run = this.runs.get(op.id);\r\n const newValue = this._materializeRunValue(op.id);\r\n this.runs.set(op.id, { ...run, value: newValue });\r\n this._lastEnvelope = { kind: 'runCharEdit', runId: op.id, tombstoneIds: op.tombstoneIds, restoreIds: op.restoreIds, clock };\r\n this._notify([op.id]);\r\n return editRunChars(op.id, op.restoreIds, op.tombstoneIds); // swapped -- this op is its own inverse shape\r\n }\r\n\r\n case OP.UPDATE_BLOCK_PROPS: {\r\n const block = this.blocks.get(op.id);\r\n const previousPatch = {};\r\n const clocks = {};\r\n for (const key of Object.keys(op.patch)) {\r\n previousPatch[key] = block.props[key];\r\n clocks[key] = this._clock.tick();\r\n this._fieldClocks.recordLocal(op.id, `props.${key}`, clocks[key]);\r\n }\r\n this.blocks.set(op.id, { ...block, props: { ...block.props, ...op.patch } });\r\n this._lastEnvelope = { kind: 'fieldWrite', target: 'blockProps', id: op.id, patch: op.patch, clocks };\r\n this._notify([op.id]);\r\n return updateBlockProps(op.id, previousPatch);\r\n }\r\n\r\n case OP.CHANGE_BLOCK_TYPE: {\r\n const block = this.blocks.get(op.id);\r\n const previousType = block.type;\r\n const previousProps = block.props;\r\n const clock = this._clock.tick();\r\n this._fieldClocks.recordLocal(op.id, 'type', clock);\r\n this.blocks.set(op.id, { ...block, type: op.blockType, props: op.props });\r\n this._lastEnvelope = { kind: 'fieldWrite', target: 'blockType', id: op.id, blockType: op.blockType, props: op.props, clock };\r\n this._notify([op.id]);\r\n return changeBlockType(op.id, previousType, previousProps);\r\n }\r\n\r\n case OP.INSERT_BLOCK: {\r\n if (op.subtree) {\r\n for (const b of op.subtree.blocks) this.blocks.set(b.id, b);\r\n for (const r of op.subtree.runs) this.runs.set(r.id, r);\r\n } else {\r\n this.blocks.set(op.block.id, op.block);\r\n }\r\n const parent = this.blocks.get(op.parentId);\r\n const order = this._getOrder(op.parentId);\r\n if (order.has(op.block.id)) {\r\n // Already has a slot here (undo of a REMOVE_BLOCK, or duplicate\r\n // delivery) -- restore its original position instead of trying\r\n // to create a second slot for the same id.\r\n order.restore(op.block.id);\r\n } else {\r\n const currentArray = order.toArray();\r\n const index = op.index ?? currentArray.length;\r\n const afterId = index > 0 ? currentArray[index - 1] : null;\r\n order.insert(op.block.id, afterId, this._clock.tick(), this._peerId);\r\n }\r\n this.blocks.set(op.parentId, { ...parent, contentIds: order.toArray() });\r\n this._lastEnvelope = {\r\n kind: 'insertSlot',\r\n parentId: op.parentId,\r\n blockId: op.block.id,\r\n slot: order.getSlot(op.block.id),\r\n subtree: op.subtree ?? { blocks: [op.block], runs: [] },\r\n };\r\n this._notify([op.block.id, op.parentId]);\r\n return removeBlock(op.block.id);\r\n }\r\n\r\n case OP.REMOVE_BLOCK: {\r\n const target = this.blocks.get(op.id);\r\n const parentId = target.parentId;\r\n const parent = this.blocks.get(parentId);\r\n const order = this._getOrder(parentId);\r\n const index = order.toArray().indexOf(op.id);\r\n const subtree = this._captureSubtree(op.id);\r\n this._deleteSubtree(op.id);\r\n const deleteClock = this._clock.tick();\r\n order.delete(op.id, deleteClock);\r\n this.blocks.set(parentId, { ...parent, contentIds: order.toArray() });\r\n this._lastEnvelope = { kind: 'deleteSlot', parentId, blockId: op.id, clock: deleteClock };\r\n this._notify([parentId]);\r\n return { type: OP.INSERT_BLOCK, block: target, parentId, index, subtree };\r\n }\r\n\r\n case OP.MOVE_BLOCK: {\r\n const target = this.blocks.get(op.id);\r\n const fromParentId = target.parentId;\r\n const fromOrder = this._getOrder(fromParentId);\r\n const fromIndex = fromOrder.toArray().indexOf(op.id);\r\n\r\n // Tombstone the slot at its old position first -- for a\r\n // same-parent reorder this is the SAME ListCrdtState as toOrder\r\n // below, and the array it produces afterward is what toIndex is\r\n // interpreted against (matches the original index-based\r\n // contract, where toIndex already meant \"position in the\r\n // resulting list\").\r\n fromOrder.delete(op.id, this._clock.tick());\r\n this.blocks.set(fromParentId, { ...this.blocks.get(fromParentId), contentIds: fromOrder.toArray() });\r\n\r\n const toOrder = this._getOrder(op.toParentId);\r\n const toArray = toOrder.toArray();\r\n const toIndex = op.toIndex ?? toArray.length;\r\n const afterId = toIndex > 0 ? toArray[toIndex - 1] : null;\r\n const ts = this._clock.tick();\r\n if (toOrder.has(op.id)) {\r\n // Reposition the existing slot (same-parent reorder, or moving\r\n // back to a parent this id was in — and tombstoned — before).\r\n toOrder.move(op.id, afterId, ts, this._peerId);\r\n } else {\r\n toOrder.insert(op.id, afterId, ts, this._peerId);\r\n }\r\n this.blocks.set(op.toParentId, { ...this.blocks.get(op.toParentId), contentIds: toOrder.toArray() });\r\n\r\n this.blocks.set(op.id, { ...this.blocks.get(op.id), parentId: op.toParentId });\r\n\r\n this._lastEnvelope = {\r\n kind: 'moveSlot',\r\n fromParentId,\r\n toParentId: op.toParentId,\r\n blockId: op.id,\r\n slot: toOrder.getSlot(op.id),\r\n };\r\n const touched = new Set([op.id, fromParentId, op.toParentId]);\r\n this._notify(touched);\r\n return moveBlock(op.id, fromParentId, fromIndex);\r\n }\r\n\r\n case OP.SET_BLOCK_CONTENT_IDS: {\r\n const block = this.blocks.get(op.blockId);\r\n const previousContentIds = block.contentIds;\r\n this.blocks.set(op.blockId, { ...block, contentIds: op.contentIds });\r\n // This op wholesale-replaces the array (a resync escape hatch, not\r\n // an incremental edit) -- reseed the ordering CRDT to match rather\r\n // than leave it stale relative to the new authoritative contents.\r\n this._orders.set(op.blockId, ListCrdtState.fromArray(op.contentIds, { peerId: 'legacy' }));\r\n this._lastEnvelope = null; // no CRDT-safe wire representation for a wholesale resync -- not broadcastable in Phase C\r\n this._notify([op.blockId]);\r\n return setBlockContentIds(op.blockId, previousContentIds);\r\n }\r\n\r\n case OP.REPLACE_RUN_SPAN: {\r\n const block = this.blocks.get(op.blockId);\r\n // The run span lives in contentIds for a plain leaf block (paragraph,\r\n // heading, tableCell), or in props.titleRunIds for a listItem (whose\r\n // contentIds instead holds nested child list items).\r\n const inContentIds = block.contentIds.indexOf(op.oldRunIds[0]) !== -1;\r\n const sourceArray = inContentIds ? block.contentIds : block.props?.titleRunIds ?? [];\r\n const startIndex = sourceArray.indexOf(op.oldRunIds[0]);\r\n\r\n const removedRuns = op.oldRunIds.map((id) => this.runs.get(id));\r\n for (const id of op.oldRunIds) this.runs.delete(id);\r\n for (const r of op.newRuns) this.runs.set(r.id, r);\r\n\r\n const newArray = [...sourceArray];\r\n newArray.splice(startIndex, op.oldRunIds.length, ...op.newRuns.map((r) => r.id));\r\n\r\n if (inContentIds) {\r\n this.blocks.set(op.blockId, { ...block, contentIds: newArray });\r\n } else {\r\n this.blocks.set(op.blockId, { ...block, props: { ...block.props, titleRunIds: newArray } });\r\n }\r\n this._lastEnvelope = null; // no CRDT-safe wire representation yet -- not broadcastable in Phase C\r\n this._notify([op.blockId, ...op.oldRunIds, ...op.newRuns.map((r) => r.id)]);\r\n return replaceRunSpan(\r\n op.blockId,\r\n op.newRuns.map((r) => r.id),\r\n removedRuns,\r\n );\r\n }\r\n\r\n case OP.SET_BLOCK_RUNS: {\r\n const block = this.blocks.get(op.blockId);\r\n // Same dual-path convention as REPLACE_RUN_SPAN: a listItem's own\r\n // runs live in props.titleRunIds (contentIds holds nested child\r\n // items instead); every other run-bearing leaf uses contentIds.\r\n const usesTitleRunIds = block.props && 'titleRunIds' in block.props;\r\n const previousRunIds = usesTitleRunIds ? block.props.titleRunIds : block.contentIds;\r\n const previousRuns = previousRunIds.map((id) => this.runs.get(id)).filter(Boolean);\r\n\r\n for (const id of previousRunIds) this.runs.delete(id);\r\n for (const r of op.runs) this.runs.set(r.id, r);\r\n const newRunIds = op.runs.map((r) => r.id);\r\n\r\n if (usesTitleRunIds) {\r\n this.blocks.set(op.blockId, { ...block, props: { ...block.props, titleRunIds: newRunIds } });\r\n } else {\r\n this.blocks.set(op.blockId, { ...block, contentIds: newRunIds });\r\n }\r\n this._lastEnvelope = null; // no CRDT-safe wire representation yet -- not broadcastable in Phase C\r\n this._notify([op.blockId, ...previousRunIds, ...newRunIds]);\r\n return setBlockRuns(op.blockId, previousRuns);\r\n }\r\n\r\n case OP.ADD_FIELD_TYPE: {\r\n this.fieldTypes.set(op.fieldType.id, op.fieldType);\r\n this._fieldTypesSnapshot = null;\r\n this._notify([FIELD_TYPES_KEY]);\r\n return removeFieldType(op.fieldType.id);\r\n }\r\n\r\n case OP.UPDATE_FIELD_TYPE: {\r\n const existing = this.fieldTypes.get(op.id);\r\n const previousPatch = {};\r\n for (const key of Object.keys(op.patch)) previousPatch[key] = existing[key];\r\n this.fieldTypes.set(op.id, { ...existing, ...op.patch });\r\n this._fieldTypesSnapshot = null;\r\n this._notify([FIELD_TYPES_KEY]);\r\n return updateFieldType(op.id, previousPatch);\r\n }\r\n\r\n case OP.REMOVE_FIELD_TYPE: {\r\n const existing = this.fieldTypes.get(op.id);\r\n this.fieldTypes.delete(op.id);\r\n this._fieldTypesSnapshot = null;\r\n this._notify([FIELD_TYPES_KEY]);\r\n return addFieldType(existing);\r\n }\r\n\r\n case OP.ADD_COMMENT_THREAD: {\r\n this.comments.set(op.thread.id, op.thread);\r\n this._commentsSnapshot = null;\r\n this._lastEnvelope = { kind: 'commentWrite', op: 'addThread', thread: op.thread };\r\n this._notify([COMMENTS_KEY]);\r\n return removeCommentThread(op.thread.id);\r\n }\r\n\r\n case OP.REMOVE_COMMENT_THREAD: {\r\n const existing = this.comments.get(op.commentId);\r\n this.comments.delete(op.commentId);\r\n this._commentsSnapshot = null;\r\n this._lastEnvelope = { kind: 'commentWrite', op: 'removeThread', commentId: op.commentId };\r\n this._notify([COMMENTS_KEY]);\r\n return addCommentThread(existing);\r\n }\r\n\r\n case OP.ADD_COMMENT_REPLY: {\r\n const thread = this.comments.get(op.commentId);\r\n this.comments.set(op.commentId, { ...thread, messages: [...thread.messages, op.message] });\r\n this._commentsSnapshot = null;\r\n this._lastEnvelope = { kind: 'commentWrite', op: 'addReply', commentId: op.commentId, message: op.message };\r\n this._notify([COMMENTS_KEY]);\r\n return removeCommentReply(op.commentId, op.message.id);\r\n }\r\n\r\n case OP.REMOVE_COMMENT_REPLY: {\r\n const thread = this.comments.get(op.commentId);\r\n const removedMessage = thread.messages.find((m) => m.id === op.messageId);\r\n this.comments.set(op.commentId, { ...thread, messages: thread.messages.filter((m) => m.id !== op.messageId) });\r\n this._commentsSnapshot = null;\r\n this._lastEnvelope = { kind: 'commentWrite', op: 'removeReply', commentId: op.commentId, messageId: op.messageId };\r\n this._notify([COMMENTS_KEY]);\r\n return addCommentReply(op.commentId, removedMessage);\r\n }\r\n\r\n case OP.RESOLVE_COMMENT: {\r\n const thread = this.comments.get(op.commentId);\r\n const previousResolved = thread.resolved;\r\n this.comments.set(op.commentId, { ...thread, resolved: op.resolved });\r\n this._commentsSnapshot = null;\r\n this._lastEnvelope = { kind: 'commentWrite', op: 'resolve', commentId: op.commentId, resolved: op.resolved };\r\n this._notify([COMMENTS_KEY]);\r\n return resolveComment(op.commentId, previousResolved);\r\n }\r\n\r\n default:\r\n throw new Error(`Unknown operation type: ${op.type}`);\r\n }\r\n }\r\n\r\n /** Applies a batch as one transaction: all mutations first, one notify pass, one combined inverse list. */\r\n applyOperations(ops) {\r\n return ops.map((op) => this.applyOperation(op));\r\n }\r\n\r\n /**\r\n * The CRDT-native wire envelope for whatever `applyOperation` just did —\r\n * read this immediately after each call to broadcast the change to\r\n * other peers. `null` for op types with no CRDT-safe representation yet\r\n * (the coarse resync ops: setBlockContentIds/replaceRunSpan/\r\n * setBlockRuns/fieldType ops) — those remain local-only in this phase.\r\n */\r\n getLastEnvelope() {\r\n return this._lastEnvelope;\r\n }\r\n\r\n /**\r\n * Applies a change received from another peer. Deliberately separate\r\n * from `applyOperation`/`History.perform` — a remote change must never\r\n * enter the local undo stack (only `perform`/`performBatch` push onto\r\n * it), so this method is the only way for a remote envelope to reach\r\n * the store. Idempotent and order-independent per envelope kind: safe\r\n * to call more than once, or with envelopes arriving out of order.\r\n */\r\n applyRemoteOperation(envelope) {\r\n if (!envelope) return;\r\n switch (envelope.kind) {\r\n case 'insertSlot': {\r\n for (const b of envelope.subtree.blocks) if (!this.blocks.has(b.id)) this.blocks.set(b.id, b);\r\n for (const r of envelope.subtree.runs) if (!this.runs.has(r.id)) this.runs.set(r.id, r);\r\n const order = this._getOrder(envelope.parentId);\r\n order.merge([envelope.slot]);\r\n const parent = this.blocks.get(envelope.parentId);\r\n this.blocks.set(envelope.parentId, { ...parent, contentIds: order.toArray() });\r\n this._clock.receive(envelope.slot.clock);\r\n this._notify([envelope.blockId, envelope.parentId]);\r\n return;\r\n }\r\n\r\n case 'deleteSlot': {\r\n const order = this._getOrder(envelope.parentId);\r\n if (this.blocks.has(envelope.blockId)) this._deleteSubtree(envelope.blockId);\r\n order.delete(envelope.blockId, envelope.clock);\r\n if (envelope.clock) this._clock.receive(envelope.clock);\r\n const parent = this.blocks.get(envelope.parentId);\r\n this.blocks.set(envelope.parentId, { ...parent, contentIds: order.toArray() });\r\n this._notify([envelope.parentId]);\r\n return;\r\n }\r\n\r\n case 'moveSlot': {\r\n const fromOrder = this._getOrder(envelope.fromParentId);\r\n // The move's own clock (envelope.slot.clock) is a reasonable proxy\r\n // for \"when the old position was vacated\" -- there's no separate\r\n // timestamp for that specific fact, and it's close enough in time\r\n // to be a safe (if not perfectly precise) tombstone age.\r\n fromOrder.delete(envelope.blockId, envelope.slot?.clock);\r\n this.blocks.set(envelope.fromParentId, { ...this.blocks.get(envelope.fromParentId), contentIds: fromOrder.toArray() });\r\n\r\n const toOrder = this._getOrder(envelope.toParentId);\r\n const hadSlot = toOrder.has(envelope.blockId);\r\n toOrder.merge([envelope.slot]);\r\n // merge() only creates a slot or un-deletes one — it never\r\n // repositions an existing slot (that's not what merging two\r\n // independently-evolved lists means). A remote MOVE needs the\r\n // actual reposition, applied only when the slot already existed\r\n // here before this merge.\r\n if (hadSlot) toOrder.move(envelope.blockId, envelope.slot.originId, envelope.slot.clock, envelope.slot.peerId);\r\n this.blocks.set(envelope.toParentId, { ...this.blocks.get(envelope.toParentId), contentIds: toOrder.toArray() });\r\n\r\n if (this.blocks.has(envelope.blockId)) {\r\n this.blocks.set(envelope.blockId, { ...this.blocks.get(envelope.blockId), parentId: envelope.toParentId });\r\n }\r\n this._clock.receive(envelope.slot.clock);\r\n this._notify([envelope.blockId, envelope.fromParentId, envelope.toParentId]);\r\n return;\r\n }\r\n\r\n case 'fieldWrite': {\r\n if (envelope.target === 'run') {\r\n const run = this.runs.get(envelope.id);\r\n if (run) {\r\n const patch = {};\r\n for (const key of Object.keys(envelope.patch)) {\r\n const remoteClock = envelope.clocks[key];\r\n if (!this._fieldClocks.shouldApplyRemote(envelope.id, key, remoteClock)) continue;\r\n patch[key] = envelope.patch[key];\r\n this._fieldClocks.recordRemote(envelope.id, key, remoteClock);\r\n }\r\n if (Object.keys(patch).length > 0) {\r\n this.runs.set(envelope.id, { ...run, ...patch });\r\n this._notify([envelope.id]);\r\n }\r\n }\r\n } else if (envelope.target === 'blockProps') {\r\n const block = this.blocks.get(envelope.id);\r\n if (block) {\r\n const patch = {};\r\n for (const key of Object.keys(envelope.patch)) {\r\n const remoteClock = envelope.clocks[key];\r\n if (!this._fieldClocks.shouldApplyRemote(envelope.id, `props.${key}`, remoteClock)) continue;\r\n patch[key] = envelope.patch[key];\r\n this._fieldClocks.recordRemote(envelope.id, `props.${key}`, remoteClock);\r\n }\r\n if (Object.keys(patch).length > 0) {\r\n this.blocks.set(envelope.id, { ...block, props: { ...block.props, ...patch } });\r\n this._notify([envelope.id]);\r\n }\r\n }\r\n } else if (envelope.target === 'blockType') {\r\n const block = this.blocks.get(envelope.id);\r\n if (block && this._fieldClocks.shouldApplyRemote(envelope.id, 'type', envelope.clock)) {\r\n this._fieldClocks.recordRemote(envelope.id, 'type', envelope.clock);\r\n this.blocks.set(envelope.id, { ...block, type: envelope.blockType, props: envelope.props });\r\n this._notify([envelope.id]);\r\n }\r\n }\r\n for (const ts of Object.values(envelope.clocks ?? {})) this._clock.receive(ts);\r\n if (envelope.clock) this._clock.receive(envelope.clock);\r\n return;\r\n }\r\n\r\n case 'runTextEdit': {\r\n const order = this._getRunOrder(envelope.runId);\r\n const chars = this._runChars.get(envelope.runId);\r\n for (const c of envelope.insertedChars) {\r\n if (!order.has(c.id)) chars.set(c.id, c.char);\r\n order.insert(c.id, c.afterId, c.clock, c.clock?.peerId); // idempotent -- safe on duplicate delivery, same as block inserts\r\n }\r\n for (const d of envelope.deletedCharIds) order.delete(d.id, d.clock);\r\n this._runValueSnapshots.delete(envelope.runId);\r\n const run = this.runs.get(envelope.runId);\r\n if (run) {\r\n this.runs.set(envelope.runId, { ...run, value: this._materializeRunValue(envelope.runId) });\r\n this._notify([envelope.runId]);\r\n }\r\n this._clock.receive(envelope.clock);\r\n return;\r\n }\r\n\r\n case 'runCharEdit': {\r\n const order = this._getRunOrder(envelope.runId);\r\n for (const charId of envelope.tombstoneIds) order.delete(charId, envelope.clock);\r\n for (const charId of envelope.restoreIds) order.restore(charId);\r\n this._runValueSnapshots.delete(envelope.runId);\r\n const run = this.runs.get(envelope.runId);\r\n if (run) {\r\n this.runs.set(envelope.runId, { ...run, value: this._materializeRunValue(envelope.runId) });\r\n this._notify([envelope.runId]);\r\n }\r\n this._clock.receive(envelope.clock);\r\n return;\r\n }\r\n\r\n case 'commentWrite': {\r\n // Simple, no-per-field-clock handling -- comment thread metadata\r\n // sees low write concurrency in practice (see the plan's own\r\n // rationale), so each sub-kind just applies directly rather than\r\n // comparing HLC clocks the way run/block field writes do above.\r\n // Existence checks guard only against out-of-order delivery (e.g.\r\n // a reply arriving before its thread's own add), not against real\r\n // conflicts -- a later full resync reconciles anything this misses.\r\n if (envelope.op === 'addThread') {\r\n if (!this.comments.has(envelope.thread.id)) {\r\n this.comments.set(envelope.thread.id, envelope.thread);\r\n this._commentsSnapshot = null;\r\n this._notify([COMMENTS_KEY]);\r\n }\r\n } else if (envelope.op === 'removeThread') {\r\n if (this.comments.delete(envelope.commentId)) {\r\n this._commentsSnapshot = null;\r\n this._notify([COMMENTS_KEY]);\r\n }\r\n } else if (envelope.op === 'addReply') {\r\n const thread = this.comments.get(envelope.commentId);\r\n if (thread && !thread.messages.some((m) => m.id === envelope.message.id)) {\r\n this.comments.set(envelope.commentId, { ...thread, messages: [...thread.messages, envelope.message] });\r\n this._commentsSnapshot = null;\r\n this._notify([COMMENTS_KEY]);\r\n }\r\n } else if (envelope.op === 'removeReply') {\r\n const thread = this.comments.get(envelope.commentId);\r\n if (thread && thread.messages.some((m) => m.id === envelope.messageId)) {\r\n this.comments.set(envelope.commentId, { ...thread, messages: thread.messages.filter((m) => m.id !== envelope.messageId) });\r\n this._commentsSnapshot = null;\r\n this._notify([COMMENTS_KEY]);\r\n }\r\n } else if (envelope.op === 'resolve') {\r\n const thread = this.comments.get(envelope.commentId);\r\n if (thread) {\r\n this.comments.set(envelope.commentId, { ...thread, resolved: envelope.resolved });\r\n this._commentsSnapshot = null;\r\n this._notify([COMMENTS_KEY]);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n default:\r\n throw new Error(`Unknown remote envelope kind: ${envelope.kind}`);\r\n }\r\n }\r\n\r\n /** Total tombstoned (deleted but still retained) slots across every parent's ordering CRDT and every run's character CRDT — a cheap signal for whether pruneTombstones() is worth calling, or just for observing growth over a long session. */\r\n getTombstoneCount() {\r\n let count = 0;\r\n for (const order of this._orders.values()) count += order.tombstoneCount();\r\n for (const order of this._runOrders.values()) count += order.tombstoneCount();\r\n return count;\r\n }\r\n\r\n /**\r\n * Permanently removes tombstones older than `maxAgeMs` (default 24h)\r\n * across every parent's ordering CRDT — see ListCrdtState.pruneTombstones\r\n * for the safety argument this relies on (this package's reconnect model\r\n * always resyncs via a full snapshot, never a replayed op log, which is\r\n * what makes a time-based threshold safe here specifically). Opt-in:\r\n * never called automatically by anything in this store — call it\r\n * yourself on whatever schedule fits (see createPeriodicTombstoneGC for\r\n * a ready-made \"just handle it\" helper). Returns the number of slots\r\n * removed.\r\n */\r\n pruneTombstones({ maxAgeMs = 24 * 60 * 60 * 1000, now = Date.now() } = {}) {\r\n const threshold = { wallTime: now - maxAgeMs, counter: 0, peerId: '' };\r\n let removed = 0;\r\n for (const order of this._orders.values()) removed += order.pruneTombstones(threshold);\r\n // Character payloads for pruned run-char slots (_runChars) are\r\n // deliberately left in place rather than cleaned up here:\r\n // ListCrdtState.pruneTombstones only returns a removed *count*, not\r\n // which ids were removed (a shared contract with the block-level GC\r\n // above, which has no equivalent payload map to clean), and a few\r\n // orphaned single-character map entries per prune is a far smaller\r\n // concern than the whole-subtree leaks tombstone GC exists to prevent\r\n // in the first place.\r\n for (const order of this._runOrders.values()) removed += order.pruneTombstones(threshold);\r\n return removed;\r\n }\r\n\r\n toJSON() {\r\n return {\r\n blocks: [...this.blocks.values()],\r\n runs: [...this.runs.values()],\r\n rootId: this.rootId,\r\n fieldTypes: [...this.fieldTypes.values()],\r\n comments: [...this.comments.values()],\r\n };\r\n }\r\n\r\n static fromJSON(doc) {\r\n return new EditorStore(doc);\r\n }\r\n}\r\n","const IDLE_MS = 500;\r\n\r\n/**\r\n * Finds the boundaries of the differing region between an old and new\r\n * string via common-prefix/common-suffix trimming — e.g. \"hello\" ->\r\n * \"hello!\" gives {beforeOffset: 5, afterOffset: 6} (the edit happened right\r\n * at the end); \"hello\" -> \"helXlo\" gives {beforeOffset: 3, afterOffset: 4}\r\n * (caret was at 3 before typing \"X\", ends up at 4 after). Used to recover\r\n * exactly where the caret was/ended up around a single text-run edit,\r\n * purely from the op's before/after values — no DOM read needed (which\r\n * matters because by the time an updateRun op reaches History, the browser\r\n * has usually already mutated the DOM for that keystroke, so a live\r\n * `window.getSelection()` read at record-time would already reflect the\r\n * *post*-edit caret, not the pre-edit one this needs for undo).\r\n */\r\nfunction diffValueOffsets(oldValue, newValue) {\r\n const a = oldValue ?? '';\r\n const b = newValue ?? '';\r\n let start = 0;\r\n const maxStart = Math.min(a.length, b.length);\r\n while (start < maxStart && a[start] === b[start]) start += 1;\r\n let endA = a.length;\r\n let endB = b.length;\r\n while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) {\r\n endA -= 1;\r\n endB -= 1;\r\n }\r\n return { beforeOffset: endA, afterOffset: endB };\r\n}\r\n\r\n/**\r\n * Recovers the caret {runId, beforeOffset, afterOffset} for an undo entry,\r\n * when it's cleanly expressible as one text-run edit (an ordinary typing\r\n * batch, or a lone updateRun step) — returns null for anything else\r\n * (structural batches, non-text runs), which callers treat as \"don't move\r\n * focus\", same as today's behavior.\r\n */\r\n/**\r\n * Pulls \"the run's value right before this op was applied\" out of an\r\n * inverse, regardless of which of the two shapes `applyOperation` can\r\n * return for a text `updateRun`: the classic whole-value inverse\r\n * (`{type: 'updateRun', patch: {value}}`, still used for non-text patches\r\n * like marks/data) or the character-CRDT inverse (`{type: 'editRunChars',\r\n * previousValue}` — see operations.js's own doc comment on why it carries\r\n * a cosmetic-only plain-string snapshot alongside the real tombstone/\r\n * restore ids). Returns `undefined` for anything else.\r\n */\r\nfunction previousValueFromInverse(inverse) {\r\n if (inverse?.type === 'updateRun' && typeof inverse.patch?.value === 'string') return inverse.patch.value;\r\n if (inverse?.type === 'editRunChars' && typeof inverse.previousValue === 'string') return inverse.previousValue;\r\n return undefined;\r\n}\r\n\r\nfunction computeEntrySelection(entry) {\r\n if (!entry.ops.length || !entry.inverses.length) return null;\r\n const firstOp = entry.ops[0];\r\n const lastOp = entry.ops[entry.ops.length - 1];\r\n if (firstOp.type !== 'updateRun' || lastOp.type !== 'updateRun' || firstOp.id !== lastOp.id) return null;\r\n if (typeof lastOp.patch?.value !== 'string') return null;\r\n\r\n // inverses are unshifted (most-recent-first), so the last element is the\r\n // inverse of the *first* op — the run's value before the whole batch.\r\n const oldestInverse = entry.inverses[entry.inverses.length - 1];\r\n const previousValue = previousValueFromInverse(oldestInverse);\r\n if (previousValue === undefined) return null;\r\n\r\n const { beforeOffset, afterOffset } = diffValueOffsets(previousValue, lastOp.patch.value);\r\n return { runId: firstOp.id, beforeOffset, afterOffset };\r\n}\r\n\r\n/**\r\n * Structural ops (insert/remove/move block, setBlockContentIds,\r\n * updateBlockProps, ...) don't reduce to one clean run+offset the way a\r\n * text edit does, but every op shape here carries *some* id that names the\r\n * block it touched — block.id (insertBlock/its inverse), blockId\r\n * (setBlockContentIds/replaceRunSpan/setBlockRuns), id (removeBlock/\r\n * moveBlock/updateBlockProps — also a run id for updateRun, harmless here\r\n * since a plain-text-edit entry never reaches this function in the first\r\n * place; computeEntrySelection already handles that case), and\r\n * parentId/toParentId as a fallback anchor for when the primary block no\r\n * longer exists (e.g. after redoing a delete). Collected in that order\r\n * (most-specific first) so callers can walk the list and focus whichever\r\n * id is the first one that still resolves to a real block post-undo/redo.\r\n */\r\nfunction extractAffectedBlockIds(entry) {\r\n const ids = [];\r\n const collect = (op) => {\r\n if (!op) return;\r\n if (op.block?.id) ids.push(op.block.id);\r\n if (op.blockId) ids.push(op.blockId);\r\n if (op.id) ids.push(op.id);\r\n if (op.parentId) ids.push(op.parentId);\r\n if (op.toParentId) ids.push(op.toParentId);\r\n };\r\n for (const op of entry.ops) collect(op);\r\n for (const inverse of entry.inverses) collect(inverse);\r\n return [...new Set(ids)];\r\n}\r\n\r\n/**\r\n * Wraps an EditorStore with operation-based undo/redo and an audit log.\r\n *\r\n * Exposes the exact same read/write surface as EditorStore (getBlock,\r\n * getRun, getRootId, subscribe, applyOperation, toJSON) so any component\r\n * written against a plain store works unchanged when given a History\r\n * instance instead — `applyOperation` here just also records the inverse\r\n * before delegating to the store.\r\n *\r\n * Undo/redo replay inverse/forward operations directly (no full-document\r\n * snapshot). Rapid edits to the same run coalesce into one undo step via a\r\n * short idle timeout and a word-boundary heuristic; structural operations\r\n * (insert/remove/move block) never coalesce, each is its own undo step.\r\n * Every batch carries {actorId, timestamp}, which is also what backs the\r\n * audit log (`getHistoryLog`) — a bounded undo/redo stack and an unbounded\r\n * audit log are deliberately kept separate, since undoing/redoing should\r\n * not erase \"who changed what, when\".\r\n */\r\nexport class History {\r\n constructor(store, { idleMs = IDLE_MS, trackChanges = false, maxChangeLogSize = 500, defaultActorId = null } = {}) {\r\n this.store = store;\r\n this.idleMs = idleMs;\r\n // Stamped onto historyLog/changeLog entries whenever a perform/\r\n // performBatch call doesn't pass its own `meta.actorId` -- the\r\n // pass-an-actorId-to-every-call-site convention this class already had\r\n // was never actually wired up anywhere in the package (every internal\r\n // call site is single-argument), so nothing knew \"who\" made an edit in\r\n // practice. Setting this once (see useEditor's `currentUserId` option)\r\n // makes every edit attributable for free, which is what\r\n // createAutoVersionHistory relies on for its own \"who changed this\"\r\n // tracking. `setDefaultActorId` below lets it change after construction\r\n // (e.g. identity resolves asynchronously after the editor already mounted).\r\n this.defaultActorId = defaultActorId;\r\n this.undoStack = [];\r\n this.redoStack = [];\r\n this.currentBatch = null;\r\n this.idleTimer = null;\r\n this.historyLog = [];\r\n this._listeners = new Set();\r\n this._undoRedoSnapshot = { canUndo: false, canRedo: false };\r\n this._pendingSelection = null;\r\n this._pendingAffectedBlockIds = [];\r\n // Opt-in, capped \"what changed, from what to what\" log — separate from\r\n // historyLog (which is just {opType, id, actorId, timestamp}, always\r\n // on) because storing actual before/after values has a real per-edit\r\n // memory cost. Off by default so it costs nothing for apps that never\r\n // ask for it; ring-buffered at maxChangeLogSize so a long session can't\r\n // grow it unbounded even with tracking on.\r\n this.trackChanges = trackChanges;\r\n this.maxChangeLogSize = maxChangeLogSize;\r\n this.changeLog = [];\r\n }\r\n\r\n /**\r\n * Appends one entry to the opt-in change log (see `trackChanges`) and\r\n * drops the oldest entry once over maxChangeLogSize. Only records actual\r\n * before/after *values* for updateRun/updateBlockProps — both carry a\r\n * small `patch` object on the op and its inverse already, so the diff is\r\n * free to capture. Structural ops (insert/remove/move block, ...) are\r\n * logged as the bare fact (opType/id/actorId/timestamp, before/after\r\n * left undefined) rather than snapshotting a whole block subtree, which\r\n * would defeat the point of keeping this lightweight.\r\n */\r\n _recordChange(op, inverse, meta) {\r\n if (!this.trackChanges) return;\r\n const hasPatch = op.patch !== undefined && inverse?.patch !== undefined;\r\n // A text `updateRun`'s inverse is `editRunChars`-shaped (see\r\n // operations.js), which has no `.patch` at all — its cosmetic-only\r\n // `previousValue` string is the equivalent \"before\" here.\r\n const previousValue = hasPatch ? undefined : previousValueFromInverse(inverse);\r\n this.changeLog.push({\r\n opType: op.type,\r\n id: op.id ?? op.blockId ?? op.block?.id,\r\n before: hasPatch ? inverse.patch : previousValue !== undefined ? { value: previousValue } : undefined,\r\n after: hasPatch ? op.patch : previousValue !== undefined ? op.patch : undefined,\r\n actorId: meta.actorId ?? null,\r\n timestamp: meta.timestamp ?? Date.now(),\r\n });\r\n if (this.changeLog.length > this.maxChangeLogSize) this.changeLog.shift();\r\n }\r\n\r\n /**\r\n * The opt-in change log (empty unless constructed with trackChanges:\r\n * true) — one entry per operation as it was originally applied, each\r\n * `{opType, id, before, after, actorId, timestamp}`. Same\r\n * independent-of-undo/redo convention as getHistoryLog: undoing an edit\r\n * doesn't erase or rewrite its original log entry.\r\n */\r\n getChangeLog() {\r\n return [...this.changeLog];\r\n }\r\n\r\n /**\r\n * Where the caret should move to after the undo/redo that was just\r\n * performed — {runId, offset}, or null when the entry wasn't a plain\r\n * text-run edit (structural ops) or carried no derivable caret. Read this\r\n * right after calling undo()/redo(); it's overwritten by the next call.\r\n */\r\n getPendingSelection() {\r\n return this._pendingSelection;\r\n }\r\n\r\n /**\r\n * Fallback for structural entries where getPendingSelection() is null —\r\n * ids (most-specific first) of blocks the just-undone/redone entry\r\n * touched, so a caller can focus the first one that still exists rather\r\n * than leaving focus wherever it happened to be (typically stale, since a\r\n * removed/re-inserted block is a brand-new DOM node). See\r\n * extractAffectedBlockIds for exactly what's collected.\r\n */\r\n getPendingAffectedBlockIds() {\r\n return this._pendingAffectedBlockIds;\r\n }\r\n\r\n /**\r\n * Cached {canUndo, canRedo} snapshot — only a new object when either value\r\n * actually changed, so useSyncExternalStore's getSnapshot can call this\r\n * every render without ever seeing a \"changed\" reference for no reason.\r\n */\r\n getUndoRedoSnapshot() {\r\n const canUndo = this.canUndo();\r\n const canRedo = this.canRedo();\r\n if (this._undoRedoSnapshot.canUndo !== canUndo || this._undoRedoSnapshot.canRedo !== canRedo) {\r\n this._undoRedoSnapshot = { canUndo, canRedo };\r\n }\r\n return this._undoRedoSnapshot;\r\n }\r\n\r\n // --- read surface: delegate straight through ---\r\n getBlock(id) {\r\n return this.store.getBlock(id);\r\n }\r\n\r\n getRun(id) {\r\n return this.store.getRun(id);\r\n }\r\n\r\n getRootId() {\r\n return this.store.getRootId();\r\n }\r\n\r\n getFieldTypes() {\r\n return this.store.getFieldTypes();\r\n }\r\n\r\n getFieldType(id) {\r\n return this.store.getFieldType(id);\r\n }\r\n\r\n getComments() {\r\n return this.store.getComments();\r\n }\r\n\r\n getComment(id) {\r\n return this.store.getComment(id);\r\n }\r\n\r\n getAllRunIds() {\r\n return this.store.getAllRunIds();\r\n }\r\n\r\n subscribe(id, listener) {\r\n return this.store.subscribe(id, listener);\r\n }\r\n\r\n subscribeAll(listener) {\r\n return this.store.subscribeAll(listener);\r\n }\r\n\r\n /**\r\n * Delegates straight to the store, deliberately outside perform/\r\n * performBatch — pruning tombstones never changes the visible document\r\n * (they were already invisible), so it isn't a user-facing edit and has\r\n * no business on the undo stack.\r\n */\r\n getTombstoneCount() {\r\n return this.store.getTombstoneCount();\r\n }\r\n\r\n pruneTombstones(options) {\r\n return this.store.pruneTombstones(options);\r\n }\r\n\r\n toJSON() {\r\n return this.store.toJSON();\r\n }\r\n\r\n // --- write surface ---\r\n applyOperation(op, meta = {}) {\r\n return this.perform(op, meta);\r\n }\r\n\r\n applyOperations(ops, meta = {}) {\r\n return ops.map((op) => this.perform(op, meta));\r\n }\r\n\r\n /**\r\n * Applies several operations as one atomic undo step (e.g. merging a\r\n * block into its previous sibling is remove-empty-block + reassign-\r\n * contentIds + delete-shell — three ops that must undo together, not one\r\n * press per op). Flushes any in-progress typing batch first so the merge\r\n * doesn't get folded into unrelated coalescing.\r\n */\r\n /** Changes the actorId future perform/performBatch calls fall back to when they don't pass their own `meta.actorId`. */\r\n setDefaultActorId(actorId) {\r\n this.defaultActorId = actorId;\r\n }\r\n\r\n performBatch(ops, meta = {}) {\r\n const actorId = meta.actorId ?? this.defaultActorId;\r\n const timestamp = meta.timestamp ?? Date.now();\r\n this._commitCurrentBatch();\r\n\r\n const inverses = [];\r\n for (const op of ops) {\r\n const inverse = this.store.applyOperation(op);\r\n inverses.unshift(inverse);\r\n this.historyLog.push({ opType: op.type, id: op.id ?? op.blockId ?? op.block?.id, actorId, timestamp });\r\n this._recordChange(op, inverse, { actorId, timestamp });\r\n }\r\n\r\n this.redoStack = [];\r\n this.undoStack.push({\r\n ops: [...ops],\r\n inverses,\r\n batchKey: null,\r\n actorId,\r\n timestamp,\r\n lastTimestamp: timestamp,\r\n boundaryHit: true,\r\n });\r\n this._notify();\r\n }\r\n\r\n perform(op, meta = {}) {\r\n const actorId = meta.actorId ?? this.defaultActorId;\r\n const timestamp = meta.timestamp ?? Date.now();\r\n const inverse = this.store.applyOperation(op);\r\n this._record(op, inverse, { actorId, timestamp });\r\n return inverse;\r\n }\r\n\r\n _batchKeyFor(op) {\r\n // Only same-run text edits coalesce; every structural op is its own step.\r\n return op.type === 'updateRun' ? `run:${op.id}` : null;\r\n }\r\n\r\n _isWordBoundary(op) {\r\n if (op.type !== 'updateRun') return false;\r\n const value = op.patch?.value;\r\n if (typeof value !== 'string' || value.length === 0) return false;\r\n return /\\s/.test(value[value.length - 1]);\r\n }\r\n\r\n _record(op, inverse, meta) {\r\n this.redoStack = [];\r\n const batchKey = this._batchKeyFor(op);\r\n const withinIdle = this.currentBatch && meta.timestamp - this.currentBatch.lastTimestamp <= this.idleMs;\r\n const sameBatch =\r\n this.currentBatch &&\r\n batchKey !== null &&\r\n this.currentBatch.batchKey === batchKey &&\r\n withinIdle &&\r\n !this.currentBatch.boundaryHit;\r\n\r\n if (sameBatch) {\r\n this.currentBatch.ops.push(op);\r\n this.currentBatch.inverses.unshift(inverse); // undo applies most-recent-first\r\n this.currentBatch.lastTimestamp = meta.timestamp;\r\n if (this._isWordBoundary(op)) this.currentBatch.boundaryHit = true;\r\n } else {\r\n this._commitCurrentBatch();\r\n this.currentBatch = {\r\n ops: [op],\r\n inverses: [inverse],\r\n batchKey,\r\n actorId: meta.actorId,\r\n timestamp: meta.timestamp,\r\n lastTimestamp: meta.timestamp,\r\n boundaryHit: this._isWordBoundary(op),\r\n };\r\n }\r\n\r\n this._resetIdleTimer();\r\n this.historyLog.push({\r\n opType: op.type,\r\n id: op.id ?? op.block?.id,\r\n actorId: meta.actorId,\r\n timestamp: meta.timestamp,\r\n });\r\n this._recordChange(op, inverse, meta);\r\n this._notify();\r\n }\r\n\r\n _resetIdleTimer() {\r\n if (this.idleTimer) clearTimeout(this.idleTimer);\r\n this.idleTimer = setTimeout(() => {\r\n this._commitCurrentBatch();\r\n this._notify();\r\n }, this.idleMs);\r\n }\r\n\r\n _commitCurrentBatch() {\r\n if (!this.currentBatch) return;\r\n this.undoStack.push(this.currentBatch);\r\n this.currentBatch = null;\r\n if (this.idleTimer) {\r\n clearTimeout(this.idleTimer);\r\n this.idleTimer = null;\r\n }\r\n }\r\n\r\n /** Force any in-progress coalescing batch to close (e.g. on blur). */\r\n flush() {\r\n this._commitCurrentBatch();\r\n this._notify();\r\n }\r\n\r\n undo() {\r\n this._commitCurrentBatch();\r\n const entry = this.undoStack.pop();\r\n if (!entry) return false;\r\n for (const inverse of entry.inverses) this.store.applyOperation(inverse);\r\n this.redoStack.push(entry);\r\n const selection = computeEntrySelection(entry);\r\n this._pendingSelection = selection ? { runId: selection.runId, offset: selection.beforeOffset } : null;\r\n this._pendingAffectedBlockIds = extractAffectedBlockIds(entry);\r\n this._notify();\r\n return true;\r\n }\r\n\r\n redo() {\r\n const entry = this.redoStack.pop();\r\n if (!entry) return false;\r\n for (const op of entry.ops) this.store.applyOperation(op);\r\n this.undoStack.push(entry);\r\n const selection = computeEntrySelection(entry);\r\n this._pendingSelection = selection ? { runId: selection.runId, offset: selection.afterOffset } : null;\r\n this._pendingAffectedBlockIds = extractAffectedBlockIds(entry);\r\n this._notify();\r\n return true;\r\n }\r\n\r\n canUndo() {\r\n return this.undoStack.length > 0 || this.currentBatch !== null;\r\n }\r\n\r\n canRedo() {\r\n return this.redoStack.length > 0;\r\n }\r\n\r\n /** Unbounded (never popped by undo/redo) who/when/what audit trail. */\r\n getHistoryLog() {\r\n return [...this.historyLog];\r\n }\r\n\r\n subscribeToHistory(listener) {\r\n this._listeners.add(listener);\r\n return () => this._listeners.delete(listener);\r\n }\r\n\r\n _notify() {\r\n for (const listener of this._listeners) listener();\r\n }\r\n}\r\n","const DEFAULT_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24 hours\n\n/**\n * A ready-made \"just handle it\" wrapper around `store.pruneTombstones()`\n * — runs it on a periodic timer for the lifetime of a session, so a\n * long-running collaborative document doesn't need anyone to remember to\n * call it manually. Purely opt-in (nothing in the store or CollabSession\n * calls this on its own) — construct one if you want it.\n *\n * `store` is anything with `pruneTombstones()` (an `EditorStore`, or a\n * `History` wrapping one). Returns `{ stop }` — call it when the store is\n * no longer in use to clear the timer.\n */\nexport function createPeriodicTombstoneGC({ store, intervalMs = DEFAULT_INTERVAL_MS, maxAgeMs = DEFAULT_MAX_AGE_MS, onPrune, onError }) {\n const timer = setInterval(() => {\n try {\n const removed = store.pruneTombstones({ maxAgeMs });\n if (removed > 0) onPrune?.(removed);\n } catch (err) {\n onError?.(err);\n }\n }, intervalMs);\n\n return {\n stop() {\n clearInterval(timer);\n },\n };\n}\n","export const MESSAGE_TYPE = {\n HELLO: 'hello',\n OP: 'op',\n SYNC_REQUEST: 'syncRequest',\n SYNC_RESPONSE: 'syncResponse',\n PRESENCE: 'presence',\n};\n\nexport function encodeMessage(message) {\n return JSON.stringify(message);\n}\n\nexport function decodeMessage(raw) {\n const message = JSON.parse(raw);\n if (!message || typeof message.type !== 'string') throw new Error('Invalid sync message: missing type');\n return message;\n}\n\n/** Sent once right after a data channel opens, so the receiving side knows who it's talking to. Carries no required action yet — reserved for future presence/awareness use. */\nexport function helloMessage(peerId) {\n return { type: MESSAGE_TYPE.HELLO, peerId };\n}\n\n/** Relays one CRDT-native change envelope, as produced by `EditorStore.getLastEnvelope()`. */\nexport function opMessage(envelope) {\n return { type: MESSAGE_TYPE.OP, envelope };\n}\n\n/** \"Send me your full document state\" — sent on first connecting to a peer, and again on every reconnect (no attempt to track/replay only what was missed). */\nexport function syncRequestMessage() {\n return { type: MESSAGE_TYPE.SYNC_REQUEST };\n}\n\n/** A full document snapshot, as produced by `EditorStore.toJSON()`. */\nexport function syncResponseMessage(doc) {\n return { type: MESSAGE_TYPE.SYNC_RESPONSE, doc };\n}\n\n/**\n * Ephemeral \"here's where I am\" broadcast — a cursor/selection position,\n * a display name, a color, whatever the host app wants peers to see.\n * `data` is opaque to the transport layer (CollabSession only relays it,\n * never inspects or interprets it) — deliberately, since what presence\n * *means* is entirely a host-app concern, not something this package has\n * an opinion on. Never persisted, never part of the document CRDT.\n */\nexport function presenceMessage(peerId, data) {\n return { type: MESSAGE_TYPE.PRESENCE, peerId, data };\n}\n","const SYNC_LABEL = 'noteloom-sync';\nconst DEFAULT_RTC_CONFIG = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };\n\n// RTCDataChannel enforces a max-message-size that `send()` throws past --\n// it varies by browser/OS/negotiation (commonly reported anywhere from\n// ~64KB to 256KB) and isn't queryable in advance, so any single logical\n// message (an op envelope carrying an embedded file's data: URL, or a\n// full-document syncResponse snapshot, both of which can easily exceed\n// that) needs to be fragmented rather than assumed to fit. 16KB is\n// conservative -- comfortably under every browser's limit -- in exchange\n// for more individual send() calls on the rare oversized message.\nconst MAX_CHUNK_PAYLOAD = 16000;\n\n// The data channel's OWN outgoing buffer (bufferedAmount) is a separate\n// limit from max-message-size: even correctly-sized individual chunks can\n// overflow the channel's internal send queue if too many are fired\n// synchronously back to back (a large embedded video easily needs\n// thousands of 16KB chunks) -- send() then throws \"send queue is full\".\n// These thresholds pace sending: once bufferedAmount crosses HIGH, further\n// chunks wait for the channel's 'bufferedamountlow' event (fired once it\n// drains back under LOW) before continuing, so outgoing data is throttled\n// to roughly what the channel can actually keep up with.\nconst BUFFERED_AMOUNT_HIGH_WATERMARK = 1_000_000;\nconst BUFFERED_AMOUNT_LOW_WATERMARK = 256_000;\n\nfunction genMessageId() {\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Wraps one WebRTC connection to a single remote peer, using a caller-\n * supplied `SignalingChannel` (see signaling.js) purely to exchange the\n * SDP offer/answer and ICE candidates needed to establish it. Once the\n * data channel opens, no further traffic goes through signaling — the\n * rest of the sync protocol flows directly peer-to-peer over the channel.\n *\n * `initiator` must be true on exactly one side of each pair (whichever\n * peer starts the connection creates the data channel and the offer; the\n * other side waits for both to arrive).\n */\nexport class PeerConnection {\n constructor({ signaling, remotePeerId, initiator, rtcConfig = DEFAULT_RTC_CONFIG }) {\n this.remotePeerId = remotePeerId;\n this._signaling = signaling;\n this._pc = new RTCPeerConnection(rtcConfig);\n this._channel = null;\n this._openListeners = new Set();\n this._closeListeners = new Set();\n this._messageListeners = new Set();\n this._chunkBuffers = new Map(); // messageId -> { total, received: Map<index, string> }\n this._sendQueue = []; // frame strings waiting to go out, drained by _pumpSendQueue\n this._pumping = false;\n\n this._pc.onicecandidate = (event) => {\n // event.candidate is an RTCIceCandidate class instance, not a plain\n // object -- signaling implementations may serialize `message` (JSON\n // over a WebSocket, structured-clone over a BroadcastChannel, etc.),\n // and neither survives a class instance. .toJSON() is the plain,\n // serializable RTCIceCandidateInit shape that addIceCandidate also\n // accepts directly, so no reconstruction is needed on the other end.\n if (event.candidate) this._signaling.send(remotePeerId, { kind: 'ice', candidate: event.candidate.toJSON() });\n };\n\n if (initiator) {\n this._wireChannel(this._pc.createDataChannel(SYNC_LABEL));\n this._pc\n .createOffer()\n .then((offer) => this._pc.setLocalDescription(offer).then(() => offer))\n .then((offer) => this._signaling.send(remotePeerId, { kind: 'offer', sdp: offer }));\n } else {\n this._pc.ondatachannel = (event) => this._wireChannel(event.channel);\n }\n\n this._unsubscribeSignaling = signaling.onMessage((fromPeerId, message) => {\n if (fromPeerId !== remotePeerId) return;\n this._handleSignal(message);\n });\n }\n\n async _handleSignal(message) {\n if (message.kind === 'offer') {\n await this._pc.setRemoteDescription(message.sdp);\n const answer = await this._pc.createAnswer();\n await this._pc.setLocalDescription(answer);\n this._signaling.send(this.remotePeerId, { kind: 'answer', sdp: answer });\n } else if (message.kind === 'answer') {\n await this._pc.setRemoteDescription(message.sdp);\n } else if (message.kind === 'ice') {\n try {\n await this._pc.addIceCandidate(message.candidate);\n } catch {\n // A candidate arriving after the connection is already\n // closed/failed is safe to drop rather than surfacing an error.\n }\n }\n }\n\n _wireChannel(channel) {\n this._channel = channel;\n channel.bufferedAmountLowThreshold = BUFFERED_AMOUNT_LOW_WATERMARK;\n channel.onopen = () => {\n for (const cb of this._openListeners) cb();\n };\n channel.onclose = () => {\n for (const cb of this._closeListeners) cb();\n };\n channel.onmessage = (event) => this._handleRawMessage(event.data);\n }\n\n /**\n * Every wire frame carries a 1-character marker so the receiving side\n * can tell a complete message from one fragment of a larger one without\n * touching the actual payload's own framing (which is opaque to this\n * layer — see syncProtocol.js): 'S' for a single, already-small-enough\n * message; 'C' for one piece of a chunked one, reassembled once every\n * piece with the same messageId has arrived.\n */\n _handleRawMessage(raw) {\n if (typeof raw !== 'string' || raw.length === 0) return;\n const marker = raw[0];\n if (marker === 'S') {\n for (const cb of this._messageListeners) cb(raw.slice(1));\n return;\n }\n if (marker !== 'C') return; // unrecognized frame -- ignore rather than crash on a malformed/foreign message\n\n const rest = raw.slice(1);\n const firstColon = rest.indexOf(':');\n const secondColon = rest.indexOf(':', firstColon + 1);\n const thirdColon = rest.indexOf(':', secondColon + 1);\n if (firstColon === -1 || secondColon === -1 || thirdColon === -1) return;\n const messageId = rest.slice(0, firstColon);\n const index = Number(rest.slice(firstColon + 1, secondColon));\n const total = Number(rest.slice(secondColon + 1, thirdColon));\n const piece = rest.slice(thirdColon + 1);\n\n let buffer = this._chunkBuffers.get(messageId);\n if (!buffer) {\n buffer = { total, received: new Map() };\n this._chunkBuffers.set(messageId, buffer);\n }\n buffer.received.set(index, piece);\n if (buffer.received.size < buffer.total) return;\n\n this._chunkBuffers.delete(messageId);\n let full = '';\n for (let i = 0; i < buffer.total; i += 1) full += buffer.received.get(i);\n for (const cb of this._messageListeners) cb(full);\n }\n\n /**\n * Sends a raw string, transparently fragmenting it first if it's too\n * large for one data-channel message (see MAX_CHUNK_PAYLOAD). Enqueues\n * and returns immediately — the actual sending happens asynchronously\n * via _pumpSendQueue, which paces itself against the channel's own\n * backpressure (see BUFFERED_AMOUNT_HIGH/LOW_WATERMARK) so a large\n * payload's thousands of chunks don't overflow the channel's send queue\n * by firing all at once.\n */\n send(raw) {\n if (this._channel?.readyState !== 'open') return;\n if (raw.length <= MAX_CHUNK_PAYLOAD) {\n this._sendQueue.push(`S${raw}`);\n } else {\n const messageId = genMessageId();\n const total = Math.ceil(raw.length / MAX_CHUNK_PAYLOAD);\n for (let index = 0; index < total; index += 1) {\n const piece = raw.slice(index * MAX_CHUNK_PAYLOAD, (index + 1) * MAX_CHUNK_PAYLOAD);\n this._sendQueue.push(`C${messageId}:${index}:${total}:${piece}`);\n }\n }\n this._pumpSendQueue();\n }\n\n /** Drains _sendQueue one frame at a time, pausing whenever the channel's own outgoing buffer is too full rather than firing send() calls faster than the channel can actually flush them. Only one pump loop ever runs per connection (re-entrant calls from send() while a pump is already draining just top up the same queue). */\n async _pumpSendQueue() {\n if (this._pumping) return;\n this._pumping = true;\n try {\n while (this._sendQueue.length > 0) {\n if (!this._channel || this._channel.readyState !== 'open') {\n this._sendQueue.length = 0;\n break;\n }\n if (this._channel.bufferedAmount > BUFFERED_AMOUNT_HIGH_WATERMARK) {\n await this._waitForBufferedAmountLow();\n continue;\n }\n const frame = this._sendQueue.shift();\n try {\n this._channel.send(frame);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn('[noteloom] failed to send a sync message to peer', this.remotePeerId, err);\n // A send() failure here (as opposed to the backpressure this\n // loop already avoids) means the channel itself is in trouble\n // (e.g. closing mid-send) -- draining the rest of the queue\n // against it would just fail the same way, so give up on it.\n this._sendQueue.length = 0;\n break;\n }\n }\n } finally {\n this._pumping = false;\n }\n }\n\n _waitForBufferedAmountLow() {\n return new Promise((resolve) => {\n if (!this._channel) {\n resolve();\n return;\n }\n const handler = () => {\n this._channel.removeEventListener('bufferedamountlow', handler);\n resolve();\n };\n this._channel.addEventListener('bufferedamountlow', handler);\n });\n }\n\n onOpen(cb) {\n this._openListeners.add(cb);\n return () => this._openListeners.delete(cb);\n }\n\n onClose(cb) {\n this._closeListeners.add(cb);\n return () => this._closeListeners.delete(cb);\n }\n\n onMessage(cb) {\n this._messageListeners.add(cb);\n return () => this._messageListeners.delete(cb);\n }\n\n close() {\n this._chunkBuffers.clear();\n this._sendQueue.length = 0;\n this._unsubscribeSignaling?.();\n this._channel?.close();\n this._pc.close();\n }\n}\n","import { MESSAGE_TYPE, encodeMessage, decodeMessage, helloMessage, opMessage, syncRequestMessage, syncResponseMessage, presenceMessage } from './syncProtocol.js';\nimport { PeerConnection } from './peerConnection.js';\n\nconst DEFAULT_PRESENCE_THROTTLE_MS = 100;\n\n/**\n * Wires a History-wrapped EditorStore up to one or more WebRTC peers.\n * Every local write — `history.perform`, `performBatch` (each op in a\n * multi-op batch individually, not just the batch's net effect),\n * `undo`, and `redo` — is broadcast to every connected peer right after\n * it's applied, using the same envelope `EditorStore` already computed\n * for it. Incoming changes are applied via `store.applyRemoteOperation`,\n * which — by construction — never reaches `history`, so remote edits can\n * never be locally undone.\n *\n * A peer connecting for the first time gets a full document snapshot\n * (`syncResponse`) rather than a partial op backlog, and a peer\n * reconnecting after a drop re-requests the same full snapshot rather\n * than trying to track what it might have missed — simple and correct,\n * at the cost of O(document size) traffic per (re)connect. Swapping in an\n * op-log-since-clock resync later is a pure optimization, not a\n * correctness fix, so it's deliberately not attempted here.\n *\n * Also carries ephemeral presence (cursor/selection position, name,\n * color, ...) alongside the document sync — see setLocalPresence/\n * getPresence/onPresenceChange. Presence is entirely separate from the\n * document CRDT: never persisted, never subject to merge conflicts, just\n * \"whatever the last message said,\" rebroadcast to a newly-joining peer\n * on connect and cleared the moment a peer disconnects.\n */\nexport class CollabSession {\n constructor({ history, signaling, presenceThrottleMs = DEFAULT_PRESENCE_THROTTLE_MS }) {\n this._history = history;\n this._store = history.store;\n this._signaling = signaling;\n this._peers = new Map(); // remotePeerId -> PeerConnection\n this._unsubscribeLocal = this._attachLocalBroadcast();\n\n // Ephemeral presence (cursor position, name, color, ...) -- never\n // part of the document CRDT, never persisted, opaque to this class\n // (see presenceMessage's own doc comment for why).\n this._localPresence = null;\n this._remotePresence = new Map(); // remotePeerId -> data\n this._presenceListeners = new Set();\n this._presenceThrottleMs = presenceThrottleMs;\n this._presenceThrottleTimer = null;\n this._presenceDirty = false;\n }\n\n /**\n * Wraps `store.applyOperation` itself — the one chokepoint every local\n * write path funnels through (perform, performBatch's internal loop,\n * undo, redo) — rather than perform/performBatch individually. A\n * multi-op batch (e.g. \"remove this block, insert a replacement\" for an\n * in-place block-type conversion) calls applyOperation once per op but\n * only returns/settles once at the end; broadcasting only\n * `getLastEnvelope()` after the whole batch would silently drop every\n * op's envelope except the last one. Queuing one envelope per\n * applyOperation call and flushing the queue after perform/\n * performBatch/undo/redo -- all of which call applyOperation and\n * nothing else pushes onto the undo stack or replays inverses -- is\n * what makes multi-op batches sync completely instead of partially.\n * Undo/redo are included deliberately: an undo is itself a local write\n * peers should see too (their document should also lose whatever was\n * undone), not just a local-only reversal.\n */\n _attachLocalBroadcast() {\n const originalApplyOperation = this._store.applyOperation.bind(this._store);\n this._pendingEnvelopes = [];\n this._store.applyOperation = (op) => {\n const inverse = originalApplyOperation(op);\n const envelope = this._store.getLastEnvelope();\n if (envelope) this._pendingEnvelopes.push(envelope);\n return inverse;\n };\n\n const originals = {};\n for (const methodName of ['perform', 'performBatch', 'undo', 'redo']) {\n const original = this._history[methodName].bind(this._history);\n originals[methodName] = original;\n this._history[methodName] = (...args) => {\n const result = original(...args);\n this._flushPendingEnvelopes();\n return result;\n };\n }\n\n return () => {\n for (const methodName of Object.keys(originals)) this._history[methodName] = originals[methodName];\n this._store.applyOperation = originalApplyOperation;\n };\n }\n\n _flushPendingEnvelopes() {\n const envelopes = this._pendingEnvelopes;\n this._pendingEnvelopes = [];\n for (const envelope of envelopes) {\n // Coarse resync ops (setBlockContentIds/replaceRunSpan/setBlockRuns)\n // have no CRDT-safe wire form yet -- getLastEnvelope() is null for\n // those, so they're already filtered out before reaching this queue.\n this._broadcast(opMessage(envelope));\n }\n }\n\n _broadcast(message) {\n const raw = encodeMessage(message);\n for (const peer of this._peers.values()) peer.send(raw);\n }\n\n /** Establishes (or re-establishes) a connection to `remotePeerId`. `initiator` must be true on exactly one side of each pair. */\n connect(remotePeerId, { initiator }) {\n this._peers.get(remotePeerId)?.close();\n const peer = new PeerConnection({ signaling: this._signaling, remotePeerId, initiator });\n peer.onOpen(() => {\n peer.send(encodeMessage(helloMessage(this._signaling.localPeerId)));\n peer.send(encodeMessage(syncRequestMessage()));\n // A peer connecting after we already have presence set (we've been\n // in the room a while, they're just joining) has no way to know it\n // otherwise -- our next actual move would tell them eventually, but\n // there's no reason to make them wait for that.\n if (this._localPresence !== null) {\n peer.send(encodeMessage(presenceMessage(this._signaling.localPeerId, this._localPresence)));\n }\n });\n peer.onMessage((raw) => this._handleMessage(peer, raw));\n peer.onClose(() => {\n // Reconnection itself is a transport-layer concern (re-call connect\n // when the host app's own retry/backoff policy decides to) -- this\n // session just drops the peer on close. A fresh connect() always\n // starts with syncRequest/syncResponse, so there's no dependency on\n // resuming from wherever the dropped connection left off.\n this._peers.delete(remotePeerId);\n if (this._remotePresence.delete(remotePeerId)) this._notifyPresenceListeners();\n });\n this._peers.set(remotePeerId, peer);\n return peer;\n }\n\n /**\n * Updates this peer's own presence data and broadcasts it to everyone\n * connected, throttled (leading + trailing edge, default 100ms) so a\n * continuous stream of updates (mouse-driven selection changes, say)\n * doesn't send a message per pixel of movement — the first call in a\n * quiet period goes out immediately, further calls within the throttle\n * window coalesce into one trailing send of the latest value.\n */\n setLocalPresence(data) {\n this._localPresence = data;\n this._presenceDirty = true;\n if (this._presenceThrottleTimer) return;\n\n this._flushLocalPresence();\n this._presenceThrottleTimer = setTimeout(() => {\n this._presenceThrottleTimer = null;\n if (this._presenceDirty) this._flushLocalPresence();\n }, this._presenceThrottleMs);\n }\n\n _flushLocalPresence() {\n this._presenceDirty = false;\n this._broadcast(presenceMessage(this._signaling.localPeerId, this._localPresence));\n }\n\n /** A snapshot Map of every OTHER currently-known peer's presence data (never includes this peer's own — the caller already has that). */\n getPresence() {\n return new Map(this._remotePresence);\n }\n\n /** Fires whenever any peer's presence data changes, or a peer disconnects (removing their entry). Returns an unsubscribe function. */\n onPresenceChange(cb) {\n this._presenceListeners.add(cb);\n return () => this._presenceListeners.delete(cb);\n }\n\n _notifyPresenceListeners() {\n const snapshot = this.getPresence();\n for (const cb of this._presenceListeners) cb(snapshot);\n }\n\n _handleMessage(peer, raw) {\n let message;\n try {\n message = decodeMessage(raw);\n } catch {\n return; // malformed message from a misbehaving/incompatible peer -- ignore rather than crash the session\n }\n\n if (message.type === MESSAGE_TYPE.OP) {\n this._store.applyRemoteOperation(message.envelope);\n // A remote write can land on the same field a local edit is\n // mid-coalescing on (e.g. both peers typing into the same run).\n // History's coalescing has no visibility into applyRemoteOperation\n // (by design — that path never touches History), so without this,\n // the NEXT local keystroke would still be folded into the batch\n // that started BEFORE the remote write, and a single local undo\n // would revert past it, clobbering the peer's edit. Flushing here\n // closes that batch out, so the next local keystroke starts a new\n // one whose \"undo to\" state correctly includes what just arrived.\n this._history.flush();\n } else if (message.type === MESSAGE_TYPE.SYNC_REQUEST) {\n peer.send(encodeMessage(syncResponseMessage(this._store.toJSON())));\n } else if (message.type === MESSAGE_TYPE.SYNC_RESPONSE) {\n this._adoptSnapshotIfEmpty(message.doc);\n } else if (message.type === MESSAGE_TYPE.PRESENCE) {\n this._remotePresence.set(message.peerId, message.data);\n this._notifyPresenceListeners();\n }\n // HELLO carries no required action yet -- reserved for future use.\n }\n\n /**\n * Adopts a peer's full document wholesale, ONLY when this side has no\n * document of its own yet (the common \"join and get the existing note\"\n * flow). Deliberately does not attempt to merge two independently-\n * created, already-diverged documents together on first contact — that\n * requires reconciling two entirely different id spaces with no shared\n * history, which is a fundamentally different (and unsolved here)\n * problem from merging concurrent edits to the *same* document that\n * both peers already agree is the same document. If both sides already\n * have real, different content when they connect, this is a no-op and\n * the two documents simply stay unsynced until one side is cleared.\n */\n _adoptSnapshotIfEmpty(doc) {\n const rootId = this._store.getRootId();\n if (rootId && this._store.getBlock(rootId)) return;\n this._store.blocks = new Map((doc.blocks ?? []).map((b) => [b.id, b]));\n this._store.runs = new Map((doc.runs ?? []).map((r) => [r.id, r]));\n this._store.rootId = doc.rootId ?? null;\n this._store._orders = new Map(); // reseed lazily from the newly-adopted contentIds, same as a fresh EditorStore(doc) would\n this._store._notify([...this._store.blocks.keys(), ...this._store.runs.keys()]);\n }\n\n disconnect(remotePeerId) {\n this._peers.get(remotePeerId)?.close();\n this._peers.delete(remotePeerId);\n }\n\n destroy() {\n this._unsubscribeLocal();\n if (this._presenceThrottleTimer) clearTimeout(this._presenceThrottleTimer);\n for (const peer of this._peers.values()) peer.close();\n this._peers.clear();\n this._remotePresence.clear();\n this._presenceListeners.clear();\n }\n}\n","/**\n * A `SignalingChannel` (see signaling.js) backed by a plain WebSocket\n * connection to a relay server — usable for any manual/shared-rendezvous\n * setup: a relay running on the same LAN (no internet needed once peers\n * and the relay share a network), one running on a normal cloud host, or\n * anything in between. Uses only the browser's native `WebSocket`, so\n * this adds no runtime dependency to the package.\n *\n * This is a generic tool, not a specific app feature — it doesn't know or\n * care whether the relay is reachable over the internet or only a LAN;\n * that's entirely a property of the `url` the host app supplies. A\n * minimal reference relay server implementing the wire protocol this\n * expects lives in `tools/lan-relay-server/` (Node-only, not part of\n * this package's browser bundle).\n *\n * Wire protocol (JSON messages over the WebSocket):\n * client -> server, on connect: nothing extra needed -- `roomId` and\n * `peerId` are passed as URL query params so the server knows the\n * room/identity before the first message.\n * server -> client: {type: 'roster', peerIds: [...]} -- once, right after connecting: who else is already in the room\n * server -> client: {type: 'peer-joined', peerId} -- another peer joined the same room later\n * server -> client: {type: 'peer-left', peerId} -- a peer disconnected\n * client -> server: {type: 'signal', toPeerId, payload} -- relay this to one specific peer in the same room\n * server -> client: {type: 'signal', fromPeerId, payload} -- a relayed signal addressed to us\n */\nexport function createWebSocketSignaling({ url, roomId, peerId, WebSocketImpl = WebSocket }) {\n const messageHandlers = new Set();\n const peerJoinedHandlers = new Set();\n const peerLeftHandlers = new Set();\n const pendingSends = []; // queued {toPeerId, payload} while the socket is still connecting\n\n const connectUrl = `${url}${url.includes('?') ? '&' : '?'}room=${encodeURIComponent(roomId)}&peerId=${encodeURIComponent(peerId)}`;\n const socket = new WebSocketImpl(connectUrl);\n\n socket.addEventListener('open', () => {\n for (const { toPeerId, payload } of pendingSends) sendSignal(toPeerId, payload);\n pendingSends.length = 0;\n });\n\n socket.addEventListener('message', (event) => {\n let message;\n try {\n message = JSON.parse(event.data);\n } catch {\n return; // malformed frame from an incompatible/misbehaving relay -- ignore rather than crash\n }\n if (message.type === 'roster') {\n for (const otherId of message.peerIds ?? []) {\n for (const cb of peerJoinedHandlers) cb(otherId);\n }\n } else if (message.type === 'peer-joined') {\n for (const cb of peerJoinedHandlers) cb(message.peerId);\n } else if (message.type === 'peer-left') {\n for (const cb of peerLeftHandlers) cb(message.peerId);\n } else if (message.type === 'signal') {\n for (const cb of messageHandlers) cb(message.fromPeerId, message.payload);\n }\n });\n\n function sendSignal(toPeerId, payload) {\n if (socket.readyState !== WebSocketImpl.OPEN) {\n pendingSends.push({ toPeerId, payload });\n return;\n }\n socket.send(JSON.stringify({ type: 'signal', toPeerId, payload }));\n }\n\n return {\n localPeerId: peerId,\n\n send(toPeerId, payload) {\n sendSignal(toPeerId, payload);\n },\n\n onMessage(cb) {\n messageHandlers.add(cb);\n return () => messageHandlers.delete(cb);\n },\n\n /** Not part of the base SignalingChannel contract -- a relay-backed signaling implementation can tell you who's already here (the initial roster) and who joins afterward, unlike the peer-to-peer-only BroadcastChannel backend, which can only hear a live announcement. */\n onPeerDiscovered(cb) {\n peerJoinedHandlers.add(cb);\n return () => peerJoinedHandlers.delete(cb);\n },\n\n /** Not part of the base SignalingChannel contract -- the relay knows when a peer's connection drops, so it can tell everyone else, which a pure BroadcastChannel backend has no way to do. */\n onPeerLeft(cb) {\n peerLeftHandlers.add(cb);\n return () => peerLeftHandlers.delete(cb);\n },\n\n close() {\n pendingSends.length = 0;\n socket.close();\n },\n };\n}\n","const DB_NAME = 'noteloom-documents';\nconst STORE_NAME = 'documents';\nconst TEMPLATES_STORE_NAME = 'templates';\nconst VERSIONS_STORE_NAME = 'versions';\nconst DB_VERSION = 3;\n\n/**\n * IndexedDB-backed local persistence for documents (the shape `EditorStore\n * .toJSON()`/`.fromJSON()` already produce/accept) — native browser API,\n * no added dependency. Chosen over `localStorage` deliberately: documents\n * can carry large embedded media as `data:` URLs (this editor doesn't do\n * server uploads — see EmbedBlock.jsx), easily exceeding localStorage's\n * ~5-10MB synchronous string-only quota, whereas IndexedDB is async and\n * has a much larger practical ceiling.\n *\n * One shared connection is reused across calls rather than opened fresh\n * each time (opening is itself an async round-trip) — lazily created on\n * first use, cached in-module.\n */\nlet dbPromise = null;\n\nfunction openDatabase() {\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(STORE_NAME)) {\n request.result.createObjectStore(STORE_NAME);\n }\n if (!request.result.objectStoreNames.contains(TEMPLATES_STORE_NAME)) {\n // Inline-keyed (unlike `documents`' external key) -- listTemplates()\n // needs getAll() to return full {id, name, ...} objects in one read\n // for a gallery UI, not just keys.\n request.result.createObjectStore(TEMPLATES_STORE_NAME, { keyPath: 'id' });\n }\n if (!request.result.objectStoreNames.contains(VERSIONS_STORE_NAME)) {\n // Same inline-keyed shape as templates, same reason (a version\n // history list needs full {id, docId, timestamp, ...} objects in\n // one read). No index on docId -- listDocumentVersions() filters\n // client-side after getAll(), same no-index precedent as\n // listTemplates(); per-document version counts are small enough\n // that this is fine.\n request.result.createObjectStore(VERSIONS_STORE_NAME, { keyPath: 'id' });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n return dbPromise;\n}\n\n/** Persists `doc` (a plain object, e.g. from `store.toJSON()`) under `docId`, overwriting whatever was there before. */\nexport async function savePersistedDocument(docId, doc) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).put(doc, docId);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the persisted document for `docId`, or `null` if nothing has been saved under that id yet. */\nexport async function loadPersistedDocument(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).get(docId);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the persisted document for `docId`, if any. A no-op if nothing was stored under that id. */\nexport async function deletePersistedDocument(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readwrite');\n tx.objectStore(STORE_NAME).delete(docId);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every docId with a persisted document — e.g. for a \"recent documents\" list. Insertion/write order is not guaranteed. */\nexport async function listPersistedDocumentIds() {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, 'readonly');\n const request = tx.objectStore(STORE_NAME).getAllKeys();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\n/**\n * Persists a template — `{ id, scope: 'document' | 'block', name,\n * description?, doc }`, where `doc` is a full document (for `'document'`\n * scope, e.g. from `exportDocumentJSON`) or `{ roots }` (for `'block'`\n * scope, from `captureBlockTemplate`) — overwriting whatever was stored\n * under the same `id` before. Separate object store from `documents`\n * (see openDatabase above): a template is independent of any one document\n * instance, not \"the current document.\"\n */\nexport async function saveTemplate(template) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readwrite');\n tx.objectStore(TEMPLATES_STORE_NAME).put(template);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the template stored under `id`, or `null` if none exists. */\nexport async function loadTemplate(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readonly');\n const request = tx.objectStore(TEMPLATES_STORE_NAME).get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the template stored under `id`, if any. A no-op if nothing was stored under that id. */\nexport async function deleteTemplate(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readwrite');\n tx.objectStore(TEMPLATES_STORE_NAME).delete(id);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every stored template, in full (unlike listPersistedDocumentIds, which only returns keys) — for rendering a gallery/picker without a per-template round trip. Insertion/write order is not guaranteed. */\nexport async function listTemplates() {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(TEMPLATES_STORE_NAME, 'readonly');\n const request = tx.objectStore(TEMPLATES_STORE_NAME).getAll();\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\n/**\n * Persists one point-in-time snapshot of a document — `{ id, docId,\n * timestamp, authorId?, authorIds?, summary?, label?, doc }`, where `doc`\n * is a full document (the same shape a document-scope template uses).\n * Separate object store from both `documents` and `templates` (see\n * openDatabase above): a version is tied to one specific document's\n * history, not \"the current document\" or a reusable starter. Overwrites\n * whatever was stored under the same `id` before, though callers normally\n * mint a fresh `id` per snapshot (see `createAutoVersionHistory`, which\n * saves one automatically after each burst of edits settles) rather than\n * reusing one.\n */\nexport async function saveDocumentVersion(version) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readwrite');\n tx.objectStore(VERSIONS_STORE_NAME).put(version);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Returns the version stored under `id`, or `null` if none exists. */\nexport async function loadDocumentVersion(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readonly');\n const request = tx.objectStore(VERSIONS_STORE_NAME).get(id);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\n/** Removes the version stored under `id`, if any. A no-op if nothing was stored under that id. */\nexport async function deleteDocumentVersion(id) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readwrite');\n tx.objectStore(VERSIONS_STORE_NAME).delete(id);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n/** Every version saved for `docId`, in full, newest first. Filters client-side after a full getAll() -- see openDatabase's own note on why there's no docId index. */\nexport async function listDocumentVersions(docId) {\n const db = await openDatabase();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(VERSIONS_STORE_NAME, 'readonly');\n const request = tx.objectStore(VERSIONS_STORE_NAME).getAll();\n request.onsuccess = () => {\n const all = request.result.filter((v) => v.docId === docId);\n all.sort((a, b) => b.timestamp - a.timestamp);\n resolve(all);\n };\n request.onerror = () => reject(request.error);\n });\n}\n","import { savePersistedDocument } from './indexedDbPersistence.js';\n\nconst DEFAULT_DEBOUNCE_MS = 500;\n\n/**\n * Wires a store (an `EditorStore`, or a `History` wrapping one — anything\n * with `subscribeAll`/`toJSON`) up to debounced auto-save into IndexedDB\n * under `docId`. Fires on every mutation, local or remote (subscribeAll\n * doesn't distinguish), so a document being live-collaborated on stays\n * persisted the same as one edited solo.\n *\n * Debounced rather than saving on every single keystroke: `toJSON()`\n * serializes the whole document, and typing already fires a store\n * mutation per keystroke — saving synchronously on each one would mean a\n * full-document IndexedDB write per character typed, which gets\n * expensive fast on a larger document.\n *\n * Returns a `stop()` function — call it when the store is no longer in\n * use (e.g. navigating away from this document) to unsubscribe and\n * cancel any pending debounced save. `stop()` does NOT flush a pending\n * save first; call `flush()` (also returned) beforehand if the most\n * recent edit must be persisted before tearing down.\n */\nexport function createAutoPersistence({ store, docId, debounceMs = DEFAULT_DEBOUNCE_MS, onError }) {\n let timer = null;\n\n function saveNow() {\n savePersistedDocument(docId, store.toJSON()).catch((err) => onError?.(err));\n }\n\n function flush() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n saveNow();\n }\n }\n\n const unsubscribe = store.subscribeAll(() => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n saveNow();\n }, debounceMs);\n });\n\n function stop() {\n if (timer) clearTimeout(timer);\n timer = null;\n unsubscribe();\n }\n\n return { stop, flush };\n}\n","/**\r\n * Serializes an ordered list of top-level (sibling) block ids into the three\r\n * clipboard payloads. All per-type formatting is delegated to the registry\r\n * (toHTML/toPlainText) — this module only owns cross-block concerns: joining\r\n * blocks together and grouping consecutive `listItem` blocks into one\r\n * wrapping <ul>/<ol> (a single list item's toHTML only knows about itself,\r\n * not its siblings).\r\n */\r\nimport { genId } from '../utils/idGen.js';\r\n\r\nexport function serializeBlockRange(store, registry, blockIds, inlineRegistry) {\r\n const ctx = { store, registry, inlineRegistry };\r\n return {\r\n html: serializeHTML(store, registry, blockIds, ctx),\r\n text: blockIds\r\n .map((id) => {\r\n const block = store.getBlock(id);\r\n return registry.get(block.type).toPlainText(block, ctx);\r\n })\r\n .join('\\n'),\r\n json: JSON.stringify({ version: 1, blocks: blockIds.map((id) => captureSubtree(store, id)) }),\r\n };\r\n}\r\n\r\nfunction serializeHTML(store, registry, blockIds, ctx) {\r\n let html = '';\r\n let i = 0;\r\n while (i < blockIds.length) {\r\n const block = store.getBlock(blockIds[i]);\r\n if (block.type === 'listItem') {\r\n const ordered = Boolean(block.props.ordered);\r\n let itemsHTML = '';\r\n let j = i;\r\n while (j < blockIds.length) {\r\n const candidate = store.getBlock(blockIds[j]);\r\n if (candidate.type !== 'listItem' || Boolean(candidate.props.ordered) !== ordered) break;\r\n itemsHTML += registry.get('listItem').toHTML(candidate, ctx);\r\n j += 1;\r\n }\r\n const tag = ordered ? 'ol' : 'ul';\r\n html += `<${tag}>${itemsHTML}</${tag}>`;\r\n i = j;\r\n } else if (block.type === 'blockquote') {\r\n // Same grouping idea as listItem above: each blockquote block's own\r\n // toHTML only emits its own line (a <p>), since the model keeps\r\n // multi-line quotes as separate sibling blocks rather than one\r\n // container — consecutive quote siblings share one wrapping\r\n // <blockquote> on the way out, matching how they'd come back in via\r\n // domWalk's consumeBlockquote.\r\n let linesHTML = '';\r\n let j = i;\r\n while (j < blockIds.length) {\r\n const candidate = store.getBlock(blockIds[j]);\r\n if (candidate.type !== 'blockquote') break;\r\n linesHTML += registry.get('blockquote').toHTML(candidate, ctx);\r\n j += 1;\r\n }\r\n html += `<blockquote>${linesHTML}</blockquote>`;\r\n i = j;\r\n } else {\r\n html += registry.get(block.type).toHTML(block, ctx);\r\n i += 1;\r\n }\r\n }\r\n return html;\r\n}\r\n\r\n/**\r\n * Read-only capture of a block subtree (block + descendants + their runs)\r\n * — used for the app-specific clipboard JSON, and reused as-is by\r\n * `duplicateBlock` (see blocks/shared/blockActions.js) since \"clone this\r\n * subtree with fresh ids\" is exactly the same operation either way.\r\n */\r\nexport function captureSubtree(store, rootId) {\r\n const blocks = [];\r\n const runs = [];\r\n const walk = (id) => {\r\n const run = store.getRun(id);\r\n if (run) {\r\n runs.push(run);\r\n return;\r\n }\r\n const block = store.getBlock(id);\r\n if (!block) return;\r\n blocks.push(block);\r\n for (const childId of block.contentIds) walk(childId);\r\n for (const runId of block.props?.titleRunIds ?? []) walk(runId);\r\n };\r\n walk(rootId);\r\n return { rootId, blocks, runs };\r\n}\r\n\r\n/**\r\n * Regenerates ids for a captured subtree so pasting the same clipboard\r\n * contents twice never collides with ids already in the document (or with\r\n * the ids still referenced by the copy source, if it's the same doc).\r\n */\r\nexport function remapSubtreeIds({ rootId, blocks, runs }) {\r\n const idMap = new Map();\r\n for (const b of blocks) idMap.set(b.id, genId());\r\n for (const r of runs) idMap.set(r.id, genId());\r\n const remap = (id) => idMap.get(id) ?? id;\r\n\r\n const newBlocks = blocks.map((b) => ({\r\n ...b,\r\n id: remap(b.id),\r\n parentId: b.parentId ? remap(b.parentId) : b.parentId,\r\n contentIds: b.contentIds.map(remap),\r\n props: {\r\n ...b.props,\r\n ...(b.props?.titleRunIds ? { titleRunIds: b.props.titleRunIds.map(remap) } : {}),\r\n },\r\n }));\r\n const newRuns = runs.map((r) => ({ ...r, id: remap(r.id) }));\r\n const newRootId = remap(rootId);\r\n\r\n return {\r\n block: newBlocks.find((b) => b.id === newRootId),\r\n runs: newRuns,\r\n subtreeBlocks: newBlocks.filter((b) => b.id !== newRootId),\r\n };\r\n}\r\n","import { captureSubtree, remapSubtreeIds } from '../clipboard/serialize.js';\nimport { insertBlock, updateRun } from '../store/operations.js';\n\n/** Batches ops if the store supports it (a History instance), else applies them one at a time — same idiom as blocks/shared/mergeCommands.js. */\nfunction applyOps(store, ops) {\n if (typeof store.performBatch === 'function') store.performBatch(ops);\n else for (const op of ops) store.applyOperation(op);\n}\n\n/**\n * Captures one or more sibling blocks (each with its own descendants) as a\n * reusable, storable template — the block-level counterpart to\n * `exportDocumentJSON` for whole documents. Ids are kept as-is (matching the\n * app clipboard's own JSON payload); `insertBlockTemplate` remaps them fresh\n * at insert time, so the same template can be inserted any number of times\n * without ever colliding with existing content.\n */\nexport function captureBlockTemplate(store, blockIds) {\n return { roots: blockIds.map((id) => captureSubtree(store, id)) };\n}\n\n/**\n * Inserts a captured block template as new sibling blocks under `parentId`,\n * starting at `index` — the same \"remap ids, then insert\" loop\n * useClipboardHandlers.js's onPaste uses for multi-block paste, reused here\n * instead of duplicated as a one-off.\n */\nexport function insertBlockTemplate(store, template, { parentId, index }) {\n const ops = [];\n let nextIndex = index;\n for (const root of template.roots) {\n const { block, runs, subtreeBlocks } = remapSubtreeIds(root);\n block.parentId = parentId;\n ops.push(insertBlock(block, parentId, nextIndex, { blocks: [block, ...subtreeBlocks], runs }));\n nextIndex += 1;\n }\n applyOps(store, ops);\n}\n\n/**\n * Wholesale-replaces an already-mounted editor's content with a document\n * template — the \"apply this starter document to a live editor\" counterpart\n * to passing `doc` to `useEditor()` at creation time. Same Map-reassignment\n * approach usePersistedDocument.js uses for loading a persisted document\n * (written fresh here rather than shared, to avoid touching that file).\n */\nexport function applyDocumentTemplate(store, doc) {\n const rawStore = store.store ?? store; // unwrap a History instance to the underlying EditorStore\n rawStore.blocks = new Map((doc.blocks ?? []).map((b) => [b.id, b]));\n rawStore.runs = new Map((doc.runs ?? []).map((r) => [r.id, r]));\n rawStore.rootId = doc.rootId ?? null;\n rawStore.fieldTypes = new Map((doc.fieldTypes ?? []).map((f) => [f.id, f]));\n rawStore._fieldTypesSnapshot = null;\n rawStore.comments = new Map((doc.comments ?? []).map((c) => [c.id, c]));\n rawStore._commentsSnapshot = null;\n rawStore._orders = new Map();\n // '$fieldTypes'/'$comments' are the same sentinel notify keys\n // useFieldTypes/useComments subscribe to -- without them, a restored\n // template/version's field types or comments wouldn't refresh a\n // currently-mounted list for either, even though the underlying Maps did change.\n rawStore._notify([...rawStore.blocks.keys(), ...rawStore.runs.keys(), '$fieldTypes', '$comments']);\n}\n\n/**\n * Registers block-level templates as slash commands — discoverable and\n * insertable via \"/\" alongside every built-in block, with no changes needed\n * to SlashMenu/useSlashMenuTrigger/BlockRegistry, since those already just\n * read whatever `listSlashCommands()` returns. Each template is registered\n * under a synthetic key that's never used as a real block's `type` (no\n * block of that type is ever inserted — only the template's own captured\n * blocks, which already carry their own real types), so `component`/\n * `isLeaf` here are never actually reached.\n */\nexport function registerBlockTemplates(registry, templates) {\n for (const template of templates) {\n registry.register(`__blockTemplate:${template.id}`, {\n component: () => null,\n isLeaf: true,\n slashCommand: {\n label: template.label,\n icon: template.icon,\n keywords: template.keywords ?? [template.label],\n run(store, { blockId, runId, sliceStart, sliceEnd }) {\n // clear the \"/query\" text that triggered this, same as every other block's slashCommand\n const run = store.getRun(runId);\n const value = run?.value ?? '';\n store.applyOperation(updateRun(runId, { value: value.slice(0, sliceStart) + value.slice(sliceEnd) }));\n\n const current = store.getBlock(blockId);\n const parent = store.getBlock(current.parentId);\n const index = parent.contentIds.indexOf(blockId) + 1;\n insertBlockTemplate(store, template, { parentId: current.parentId, index });\n },\n },\n });\n }\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { listTemplates } from '../persistence/indexedDbPersistence.js';\n\n/**\n * Reactive access to the stored template library (see saveTemplate/\n * loadTemplate/deleteTemplate/listTemplates) — for building a gallery/picker\n * UI (see TemplatePicker) backed by IndexedDB. Loads on mount and whenever\n * `scope` changes; `refresh()` re-queries on demand (e.g. right after a\n * saveTemplate/deleteTemplate call made elsewhere, since nothing here\n * subscribes to storage writes automatically).\n *\n * `scope` (optional) filters to `'document'` or `'block'` templates only —\n * client-side, since IndexedDB's `getAll()` already returns the whole\n * (typically small) template library in one read; omit it to get both.\n */\nexport function useTemplates({ scope } = {}) {\n const [templates, setTemplates] = useState([]);\n const [isLoaded, setIsLoaded] = useState(false);\n\n const refresh = useCallback(() => {\n setIsLoaded(false);\n return listTemplates().then((all) => {\n setTemplates(scope ? all.filter((t) => t.scope === scope) : all);\n setIsLoaded(true);\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scope]);\n\n useEffect(() => {\n let cancelled = false;\n setIsLoaded(false);\n listTemplates().then((all) => {\n if (cancelled) return;\n setTemplates(scope ? all.filter((t) => t.scope === scope) : all);\n setIsLoaded(true);\n });\n return () => {\n cancelled = true;\n };\n }, [scope]);\n\n return { templates, isLoaded, refresh };\n}\n","/**\n * A plain, unopinionated list of templates (name + description, each with a\n * \"Use\" button) — not wrapped in a Modal/popover itself, since it's reused\n * for genuinely different contexts (a \"new document\" starter-template\n * gallery, an in-editor \"insert a saved snippet\" picker). Wrap it in the\n * exported `Modal` component yourself, or render it inline on a page —\n * whichever fits the host app.\n *\n * Feed it `templates` from `useTemplates()` (or `listTemplates()` directly);\n * `onSelect(template)` receives the whole stored template object — what to\n * do with it (apply/insert it, or just read its `.doc`) is the caller's\n * call, since that differs by scope (see README's \"Templates\" section).\n */\nexport function TemplatePicker({ templates, onSelect, emptyLabel = 'No templates yet.' }) {\n if (templates.length === 0) {\n return <p className=\"be-template-picker-empty\">{emptyLabel}</p>;\n }\n\n return (\n <ul className=\"be-template-picker\" role=\"list\">\n {templates.map((template) => (\n <li key={template.id} className=\"be-template-card\">\n <div className=\"be-template-card-body\">\n <span className=\"be-template-card-name\">{template.name}</span>\n {template.description && <span className=\"be-template-card-description\">{template.description}</span>}\n </div>\n <button type=\"button\" className=\"be-template-card-select\" onClick={() => onSelect(template)}>\n Use\n </button>\n </li>\n ))}\n </ul>\n );\n}\n","import { captureSubtree } from './serialize.js';\nimport { serializeBlockRange } from './serialize.js';\n\n/**\n * Whole-document JSON export — the exact `{ rootId, blocks, runs }` shape\n * `new EditorStore({...})` itself accepts, so this round-trips: export a\n * document, and the result can be handed straight back into a fresh\n * EditorStore to reconstruct it. Wraps captureSubtree (already used for\n * duplicate/copy) starting from the document's own root rather than one\n * top-level block, so it walks the *entire* tree in one pass.\n */\nexport function exportDocumentJSON(store, { pretty = true } = {}) {\n const rootId = store.getRootId();\n const { blocks, runs } = captureSubtree(store, rootId);\n const payload = { version: 1, rootId, blocks, runs };\n return JSON.stringify(payload, null, pretty ? 2 : 0);\n}\n\n/** Whole-document HTML export — every top-level block's own toHTML, joined (see serializeBlockRange). */\nexport function exportDocumentHTML(store, registry, inlineRegistry) {\n const root = store.getBlock(store.getRootId());\n if (!root) return '';\n return serializeBlockRange(store, registry, root.contentIds, inlineRegistry).html;\n}\n\n/** Whole-document plain-text export — every top-level block's own toPlainText, joined (see serializeBlockRange). */\nexport function exportDocumentText(store, registry, inlineRegistry) {\n const root = store.getBlock(store.getRootId());\n if (!root) return '';\n return serializeBlockRange(store, registry, root.contentIds, inlineRegistry).text;\n}\n","import { exportDocumentJSON } from '../clipboard/exportDocument.js';\nimport { saveDocumentVersion, listDocumentVersions, deleteDocumentVersion } from '../persistence/indexedDbPersistence.js';\n\nconst DEFAULT_IDLE_MS = 5 * 60 * 1000; // 5 minutes of inactivity closes a version, roughly matching how Google Docs groups edits into one revision\nconst DEFAULT_MAX_VERSIONS = 200;\n\n/**\n * Automatic, Google Docs-style version history — no \"type a label and save\"\n * step. Listens to `store.subscribeToHistory()` (`store` must be a\n * `History` instance, not a plain `EditorStore` — this needs `getHistoryLog()`)\n * and, after `idleMs` of no further edits, closes the \"window\" of edits\n * that just happened and saves one snapshot for it: who made them\n * (`authorId`/`authorIds`, read straight off each entry's `actorId` — see\n * History's `defaultActorId`/`useEditor`'s `currentUserId`, no separate\n * identity plumbing needed here), roughly what changed (`summary`, a\n * lightweight count of distinct blocks touched — not a full diff), and the\n * full document snapshot itself for restore/preview.\n *\n * A version is never named/labeled up front — `DocumentVersion.label`\n * still exists for callers who want to rename one afterward, but nothing\n * in this module asks for one.\n */\nexport function createAutoVersionHistory({ store, docId, idleMs = DEFAULT_IDLE_MS, maxVersions = DEFAULT_MAX_VERSIONS, onSnapshot, onError }) {\n let idleTimer = null;\n let windowStart = store.getHistoryLog().length; // index into historyLog where the current open window begins\n let hasPendingActivity = false;\n\n function clearIdleTimer() {\n if (idleTimer) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n }\n\n async function finalizeWindow() {\n clearIdleTimer();\n if (!hasPendingActivity) return;\n hasPendingActivity = false;\n\n const log = store.getHistoryLog();\n const entries = log.slice(windowStart);\n windowStart = log.length;\n if (entries.length === 0) return; // e.g. only an undo/redo happened, nothing new was appended to the log\n\n const touchedIds = new Set(entries.map((e) => e.id).filter(Boolean));\n const authorIds = [...new Set(entries.map((e) => e.actorId).filter(Boolean))];\n const authorId = entries[entries.length - 1].actorId ?? null; // whoever made the most recent edit in this window\n\n try {\n const doc = JSON.parse(exportDocumentJSON(store)); // exportDocumentJSON returns a JSON *string* -- parse it into the plain object DocumentVersion.doc expects\n const version = {\n id: crypto.randomUUID(),\n docId,\n timestamp: Date.now(),\n authorId,\n authorIds,\n summary: `${touchedIds.size} block${touchedIds.size === 1 ? '' : 's'} changed`,\n doc,\n };\n await saveDocumentVersion(version);\n onSnapshot?.(version);\n\n const all = await listDocumentVersions(docId); // newest first\n if (all.length > maxVersions) {\n const excess = all.slice(maxVersions);\n await Promise.all(excess.map((v) => deleteDocumentVersion(v.id)));\n }\n } catch (err) {\n onError?.(err);\n }\n }\n\n const unsubscribe = store.subscribeToHistory(() => {\n hasPendingActivity = true;\n clearIdleTimer();\n idleTimer = setTimeout(finalizeWindow, idleMs);\n });\n\n return {\n /** Stops listening. Does NOT flush a final in-progress window -- call `flush()` first if you want that (e.g. right before navigating away). */\n stop() {\n clearIdleTimer();\n unsubscribe();\n },\n /** Closes and saves the current window immediately, without waiting for `idleMs` of inactivity. A no-op if nothing's happened since the last save. */\n flush: finalizeWindow,\n };\n}\n","/**\n * Word-level LCS diff between two strings. Not a full Myers diff, but\n * version-history edits are typically a handful of scattered word changes\n * inside otherwise-unchanged paragraphs, so this is enough to render\n * accurate insertions/deletions instead of just \"this whole block changed.\"\n * Whitespace runs are kept as their own tokens so re-joining segments\n * reproduces the original spacing exactly.\n */\nexport function diffWords(oldText, newText) {\n const oldTokens = tokenize(oldText);\n const newTokens = tokenize(newText);\n const n = oldTokens.length;\n const m = newTokens.length;\n\n const dp = Array.from({ length: n + 1 }, () => new Uint32Array(m + 1));\n for (let i = n - 1; i >= 0; i -= 1) {\n for (let j = m - 1; j >= 0; j -= 1) {\n dp[i][j] = oldTokens[i] === newTokens[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);\n }\n }\n\n const segments = [];\n const push = (type, text) => {\n const last = segments[segments.length - 1];\n if (last && last.type === type) last.text += text;\n else segments.push({ type, text });\n };\n\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (oldTokens[i] === newTokens[j]) {\n push('equal', oldTokens[i]);\n i += 1;\n j += 1;\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\n push('removed', oldTokens[i]);\n i += 1;\n } else {\n push('added', newTokens[j]);\n j += 1;\n }\n }\n while (i < n) {\n push('removed', oldTokens[i]);\n i += 1;\n }\n while (j < m) {\n push('added', newTokens[j]);\n j += 1;\n }\n return segments;\n}\n\nfunction tokenize(text) {\n return (text ?? '').match(/\\s+|[^\\s]+/g) ?? [];\n}\n\nconst ESCAPE_MAP = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' };\nfunction escapeHtml(text) {\n return text.replace(/[&<>\"']/g, (ch) => ESCAPE_MAP[ch]);\n}\n\n/**\n * Flattens a DocumentJSON into an ordered list of its text-bearing blocks\n * (paragraphs, headings, list items, ...), keyed by block id. Only blocks\n * whose content resolves directly to text runs are collected -- container\n * blocks (page, columns, ...) are walked through but not themselves\n * represented, matching how they render (no text of their own to diff).\n */\nfunction extractTextBlocks(doc) {\n const blockById = new Map(doc.blocks.map((b) => [b.id, b]));\n const runById = new Map(doc.runs.map((r) => [r.id, r]));\n const result = [];\n\n const textFromRunIds = (ids) => ids.map((id) => runById.get(id)?.value ?? '').join('');\n\n const walk = (id) => {\n const block = blockById.get(id);\n if (!block) return;\n const titleRunIds = block.props?.titleRunIds;\n if (Array.isArray(titleRunIds) && titleRunIds.length > 0) {\n result.push({ id, text: textFromRunIds(titleRunIds) });\n } else if (block.contentIds.length > 0 && block.contentIds.every((cid) => runById.has(cid))) {\n result.push({ id, text: textFromRunIds(block.contentIds) });\n }\n for (const childId of block.contentIds) {\n if (!runById.has(childId)) walk(childId);\n }\n };\n walk(doc.rootId);\n return result;\n}\n\nconst EMPTY_DOC = {\n rootId: 'root',\n blocks: [{ id: 'root', type: 'page', parentId: null, contentIds: [], props: {} }],\n runs: [],\n};\n\n/**\n * Renders an HTML diff of `nextDoc` against `prevDoc` (Google Docs-style\n * \"show changes\" view) -- blocks that only exist in `nextDoc` render fully\n * highlighted as added, blocks that only existed in `prevDoc` render fully\n * struck-through as removed (appended after the surviving blocks, since\n * this is about surfacing *what* changed, not reproducing exact block\n * reordering), and blocks present in both get word-level diffed. Pass\n * `null`/`undefined` as `prevDoc` for \"this is the first version\" (everything\n * shows as added).\n */\nexport function diffDocumentsHTML(prevDoc, nextDoc) {\n const prevBlocks = extractTextBlocks(prevDoc ?? EMPTY_DOC);\n const nextBlocks = extractTextBlocks(nextDoc ?? EMPTY_DOC);\n const prevById = new Map(prevBlocks.map((b) => [b.id, b]));\n const nextIds = new Set(nextBlocks.map((b) => b.id));\n\n const parts = [];\n\n for (const block of nextBlocks) {\n const prevBlock = prevById.get(block.id);\n if (!prevBlock) {\n const text = escapeHtml(block.text) || '&nbsp;';\n parts.push(`<p class=\"be-version-diff-block\"><span class=\"be-version-diff-added\">${text}</span></p>`);\n continue;\n }\n if (prevBlock.text === block.text) {\n parts.push(`<p class=\"be-version-diff-block\">${escapeHtml(block.text) || '&nbsp;'}</p>`);\n continue;\n }\n const segments = diffWords(prevBlock.text, block.text);\n const html = segments\n .map((seg) => {\n const escaped = escapeHtml(seg.text);\n if (seg.type === 'added') return `<span class=\"be-version-diff-added\">${escaped}</span>`;\n if (seg.type === 'removed') return `<span class=\"be-version-diff-removed\">${escaped}</span>`;\n return escaped;\n })\n .join('');\n parts.push(`<p class=\"be-version-diff-block\">${html}</p>`);\n }\n\n for (const block of prevBlocks) {\n if (!nextIds.has(block.id)) {\n const text = escapeHtml(block.text) || '&nbsp;';\n parts.push(`<p class=\"be-version-diff-block\"><span class=\"be-version-diff-removed\">${text}</span></p>`);\n }\n }\n\n if (parts.length === 0) return '<p class=\"be-version-diff-empty\">No text changes.</p>';\n return parts.join('');\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { listDocumentVersions } from '../persistence/indexedDbPersistence.js';\n\n/**\n * Reactive access to the stored version history for one document (see\n * saveDocumentVersion/loadDocumentVersion/deleteDocumentVersion/\n * listDocumentVersions) — for building a version list UI backed by\n * IndexedDB. Loads on mount and whenever `docId` changes; `refresh()`\n * re-queries on demand (e.g. right after a saveDocumentVersion/\n * deleteDocumentVersion call made elsewhere, since nothing here subscribes\n * to storage writes automatically). Restoring a version is not part of\n * this hook -- pass the loaded version's `doc` to `applyDocumentTemplate`.\n */\nexport function useDocumentVersions(docId) {\n const [versions, setVersions] = useState([]);\n const [isLoaded, setIsLoaded] = useState(false);\n\n const refresh = useCallback(() => {\n if (!docId) return Promise.resolve();\n setIsLoaded(false);\n return listDocumentVersions(docId).then((all) => {\n setVersions(all);\n setIsLoaded(true);\n });\n }, [docId]);\n\n useEffect(() => {\n if (!docId) {\n setVersions([]);\n setIsLoaded(true);\n return undefined;\n }\n let cancelled = false;\n setIsLoaded(false);\n listDocumentVersions(docId).then((all) => {\n if (cancelled) return;\n setVersions(all);\n setIsLoaded(true);\n });\n return () => {\n cancelled = true;\n };\n }, [docId]);\n\n return { versions, isLoaded, refresh };\n}\n","export default \"/*\\r\\n * noteloom's default theme — minimal, clean, modern SaaS-adjacent.\\r\\n *\\r\\n * Ships as plain CSS custom properties on :root (not scoped to a wrapper\\r\\n * element) deliberately: several of this package's own pieces — Select's\\r\\n * popover, SlashMenu, FloatingToolbar, the table header menu, the block\\r\\n * gutter/range menus, Modal — are portaled to document.body, so they are\\r\\n * NOT DOM descendants of whatever element renders the editor itself.\\r\\n * Scoping variables to a wrapper class would silently fail to reach any\\r\\n * of those. `--noteloom-*` is a distinctive enough prefix that defining\\r\\n * these on :root won't collide with a host app's own custom properties.\\r\\n *\\r\\n * This file is auto-injected at runtime by <EditorProvider> (see\\r\\n * react/injectDefaultStyles.js) — you do NOT need to import this\\r\\n * yourself. It's still published standalone at `noteloom/style.css` for:\\r\\n * - passing `theme=\\\"none\\\"` to <EditorProvider> and importing this\\r\\n * explicitly instead (e.g. to control load order, or for SSR/CSP\\r\\n * setups where runtime <style> injection isn't allowed)\\r\\n * - copying as a starting point for your own from-scratch theme\\r\\n *\\r\\n * Retheme by overriding these variables in your own CSS (after the\\r\\n * default theme loads) — every rule below reads from them, nothing is\\r\\n * hardcoded. Override individual `.be-*` classes too, same as any other\\r\\n * library's default styles.\\r\\n */\\r\\n\\r\\n:root {\\r\\n --noteloom-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, sans-serif;\\r\\n --noteloom-text: #0f172a;\\r\\n --noteloom-text-muted: #64748b;\\r\\n --noteloom-text-faint: #94a3b8;\\r\\n --noteloom-bg: #ffffff;\\r\\n --noteloom-bg-subtle: #f8fafc;\\r\\n --noteloom-bg-hover: #f1f5f9;\\r\\n --noteloom-border: #e2e8f0;\\r\\n --noteloom-accent: #6366f1;\\r\\n --noteloom-accent-text: #ffffff;\\r\\n --noteloom-accent-soft: rgba(99, 102, 241, 0.1);\\r\\n --noteloom-accent-soft-hover: rgba(99, 102, 241, 0.16);\\r\\n --noteloom-danger: #dc2626;\\r\\n --noteloom-danger-soft: #fef2f2;\\r\\n --noteloom-radius-sm: 6px;\\r\\n --noteloom-radius-md: 8px;\\r\\n --noteloom-radius-lg: 12px;\\r\\n --noteloom-radius-xl: 16px;\\r\\n --noteloom-shadow: 0 12px 24px -8px rgba(15, 23, 42, 0.12), 0 4px 8px -4px rgba(15, 23, 42, 0.06);\\r\\n --noteloom-code-bg: #0f172a;\\r\\n --noteloom-code-text: #e2e8f0;\\r\\n}\\r\\n\\r\\n@media (prefers-color-scheme: dark) {\\r\\n :root {\\r\\n --noteloom-text: #f1f5f9;\\r\\n --noteloom-text-muted: #94a3b8;\\r\\n --noteloom-text-faint: #64748b;\\r\\n --noteloom-bg: #1c1932;\\r\\n --noteloom-bg-subtle: rgba(255, 255, 255, 0.03);\\r\\n --noteloom-bg-hover: rgba(255, 255, 255, 0.06);\\r\\n --noteloom-border: rgba(255, 255, 255, 0.1);\\r\\n --noteloom-accent-soft: rgba(99, 102, 241, 0.18);\\r\\n --noteloom-accent-soft-hover: rgba(99, 102, 241, 0.26);\\r\\n --noteloom-danger-soft: rgba(220, 38, 38, 0.15);\\r\\n --noteloom-code-bg: #13111f;\\r\\n }\\r\\n}\\r\\n\\r\\n/* Explicit overrides win either direction — a host toggling dark mode via\\r\\n a class rather than the OS setting can set [data-theme=\\\"dark\\\"/\\\"light\\\"]\\r\\n on any ancestor (e.g. <html>), overriding the media query above. */\\r\\n[data-theme='dark'] {\\r\\n --noteloom-text: #f1f5f9;\\r\\n --noteloom-text-muted: #94a3b8;\\r\\n --noteloom-text-faint: #64748b;\\r\\n --noteloom-bg: #1c1932;\\r\\n --noteloom-bg-subtle: rgba(255, 255, 255, 0.03);\\r\\n --noteloom-bg-hover: rgba(255, 255, 255, 0.06);\\r\\n --noteloom-border: rgba(255, 255, 255, 0.1);\\r\\n --noteloom-accent-soft: rgba(99, 102, 241, 0.18);\\r\\n --noteloom-accent-soft-hover: rgba(99, 102, 241, 0.26);\\r\\n --noteloom-danger-soft: rgba(220, 38, 38, 0.15);\\r\\n --noteloom-code-bg: #13111f;\\r\\n}\\r\\n\\r\\n[data-theme='light'] {\\r\\n --noteloom-text: #0f172a;\\r\\n --noteloom-text-muted: #64748b;\\r\\n --noteloom-text-faint: #94a3b8;\\r\\n --noteloom-bg: #ffffff;\\r\\n --noteloom-bg-subtle: #f8fafc;\\r\\n --noteloom-bg-hover: #f1f5f9;\\r\\n --noteloom-border: #e2e8f0;\\r\\n --noteloom-accent-soft: rgba(99, 102, 241, 0.1);\\r\\n --noteloom-accent-soft-hover: rgba(99, 102, 241, 0.16);\\r\\n --noteloom-danger-soft: #fef2f2;\\r\\n --noteloom-code-bg: #0f172a;\\r\\n}\\r\\n\\r\\n.be-root {\\r\\n font-family: var(--noteloom-font);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-editable {\\r\\n /* Block-level and full-width so the whole line (including the blank\\r\\n trailing space after short text, and an empty line's full height) is\\r\\n part of the actual contentEditable hit-test box. Left inline/sized to\\r\\n content, a click on that blank area lands on the non-editable wrapper\\r\\n div instead of this element: the browser's native \\\"nothing focused\\r\\n yet\\\" resolution still finds it on a first click, but re-clicking the\\r\\n same dead-zone point while this element already holds the selection\\r\\n collapses/clears it instead, since there's nothing here to re-anchor\\r\\n the caret onto. */\\r\\n display: block;\\r\\n width: 100%;\\r\\n min-height: 1em;\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n/* A run with marks.commentIds set (see src/comments/commentMarks.js) --\\r\\n presence/absence only, no per-comment value to vary the color by.\\r\\n cursor: pointer hints that it opens CommentPopover on click. */\\r\\n.be-comment-highlight {\\r\\n background: rgba(234, 179, 8, 0.2);\\r\\n border-bottom: 2px solid rgba(234, 179, 8, 0.6);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n/* Echoes a hover from the panel/popover back onto the actual text -- see useHoveredComment. */\\r\\n.be-comment-highlight-active {\\r\\n background: rgba(234, 179, 8, 0.4);\\r\\n}\\r\\n\\r\\n/* --- basic leaf blocks --- */\\r\\n\\r\\n.be-paragraph {\\r\\n position: relative;\\r\\n margin: 0.25rem 0;\\r\\n line-height: 1.6;\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n.be-heading {\\r\\n position: relative;\\r\\n font-weight: 600;\\r\\n margin: 1.25rem 0 0.25rem;\\r\\n outline: none;\\r\\n letter-spacing: -0.01em;\\r\\n}\\r\\n\\r\\n/* Explicit per-level sizing, each in its own overridable class — without\\r\\n this, h1/h2/h3 only differ via the browser's own UA-stylesheet defaults\\r\\n (inconsistent across browsers, and not something a host can target\\r\\n independently without fighting tag-selector specificity). Override just\\r\\n one level with `.be-heading-1 { font-size: ...; }` in your own CSS, same\\r\\n as any other .be-* class. */\\r\\n.be-heading-1 {\\r\\n font-size: 1.9em;\\r\\n}\\r\\n\\r\\n.be-heading-2 {\\r\\n font-size: 1.5em;\\r\\n}\\r\\n\\r\\n.be-heading-3 {\\r\\n font-size: 1.2em;\\r\\n}\\r\\n\\r\\n.be-divider {\\r\\n border: none;\\r\\n border-top: 1px solid var(--noteloom-border);\\r\\n margin: 1.5em 0;\\r\\n cursor: default;\\r\\n}\\r\\n\\r\\n.be-blockquote {\\r\\n position: relative;\\r\\n margin: 0.5em 0;\\r\\n padding-left: 0.9em;\\r\\n border-left: 3px solid var(--noteloom-border);\\r\\n color: var(--noteloom-text-muted);\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n.be-blockquote[dir='rtl'] {\\r\\n padding-left: 0;\\r\\n padding-right: 0.9em;\\r\\n border-left: none;\\r\\n border-right: 3px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n/* --- callout --- */\\r\\n\\r\\n.be-callout {\\r\\n position: relative;\\r\\n display: flex;\\r\\n gap: 0.7em;\\r\\n align-items: flex-start;\\r\\n background: var(--noteloom-bg-subtle);\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n padding: 0.9em 1em;\\r\\n margin: 0.5em 0;\\r\\n}\\r\\n\\r\\n.be-callout[data-color='gray'] { background: rgba(148, 163, 184, 0.16); }\\r\\n.be-callout[data-color='blue'] { background: rgba(99, 102, 241, 0.12); }\\r\\n.be-callout[data-color='green'] { background: rgba(34, 197, 94, 0.14); }\\r\\n.be-callout[data-color='yellow'] { background: rgba(234, 179, 8, 0.16); }\\r\\n.be-callout[data-color='orange'] { background: rgba(249, 115, 22, 0.14); }\\r\\n.be-callout[data-color='red'] { background: rgba(239, 68, 68, 0.13); }\\r\\n.be-callout[data-color='purple'] { background: rgba(168, 85, 247, 0.13); }\\r\\n.be-callout[data-color='pink'] { background: rgba(236, 72, 153, 0.13); }\\r\\n\\r\\n.be-callout-icon-wrap {\\r\\n flex: none;\\r\\n}\\r\\n\\r\\n.be-callout-icon-input,\\r\\n.be-callout-icon {\\r\\n width: 2em;\\r\\n height: 2em;\\r\\n border: none;\\r\\n background: var(--noteloom-bg);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);\\r\\n font-size: 1.15em;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n padding: 0;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-callout-icon-input {\\r\\n outline: none;\\r\\n text-align: center;\\r\\n cursor: text;\\r\\n}\\r\\n\\r\\n.be-callout-content {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n padding-right: 1.6em; /* keeps text from running under the color-swatch trigger */\\r\\n}\\r\\n\\r\\n/* First child reads as the card's title; every child after it is the\\r\\n description — see CalloutBlock.jsx's comment for why this is a CSS\\r\\n convention over the content, not a separate title/description field. */\\r\\n.be-callout-content > :first-child {\\r\\n font-weight: 600;\\r\\n}\\r\\n\\r\\n.be-callout-content > :not(:first-child) {\\r\\n color: var(--noteloom-text-muted);\\r\\n font-size: 0.92em;\\r\\n}\\r\\n\\r\\n.be-callout-color-wrap {\\r\\n position: absolute;\\r\\n top: 0.6em;\\r\\n right: 0.6em;\\r\\n}\\r\\n\\r\\n.be-callout-color-trigger {\\r\\n border: none;\\r\\n background: none;\\r\\n padding: 3px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n display: flex;\\r\\n}\\r\\n\\r\\n.be-callout-color-trigger:hover {\\r\\n background: rgba(15, 23, 42, 0.06);\\r\\n}\\r\\n\\r\\n.be-callout-color-dot {\\r\\n width: 12px;\\r\\n height: 12px;\\r\\n border-radius: 50%;\\r\\n border: 1px solid rgba(15, 23, 42, 0.12);\\r\\n}\\r\\n\\r\\n.be-callout-color-dot-gray { background: #94a3b8; }\\r\\n.be-callout-color-dot-blue { background: #6366f1; }\\r\\n.be-callout-color-dot-green { background: #22c55e; }\\r\\n.be-callout-color-dot-yellow { background: #eab308; }\\r\\n.be-callout-color-dot-orange { background: #f97316; }\\r\\n.be-callout-color-dot-red { background: #ef4444; }\\r\\n.be-callout-color-dot-purple { background: #a855f7; }\\r\\n.be-callout-color-dot-pink { background: #ec4899; }\\r\\n\\r\\n.be-callout-color-picker {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n right: 0;\\r\\n margin-top: 4px;\\r\\n z-index: 1000;\\r\\n display: grid;\\r\\n grid-template-columns: repeat(4, 1fr);\\r\\n gap: 4px;\\r\\n padding: 6px;\\r\\n background: var(--noteloom-bg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n}\\r\\n\\r\\n.be-callout-color-option {\\r\\n width: 22px;\\r\\n height: 22px;\\r\\n border-radius: 50%;\\r\\n border: 2px solid transparent;\\r\\n cursor: pointer;\\r\\n padding: 0;\\r\\n}\\r\\n\\r\\n.be-callout-color-option-gray { background: #94a3b8; }\\r\\n.be-callout-color-option-blue { background: #6366f1; }\\r\\n.be-callout-color-option-green { background: #22c55e; }\\r\\n.be-callout-color-option-yellow { background: #eab308; }\\r\\n.be-callout-color-option-orange { background: #f97316; }\\r\\n.be-callout-color-option-red { background: #ef4444; }\\r\\n.be-callout-color-option-purple { background: #a855f7; }\\r\\n.be-callout-color-option-pink { background: #ec4899; }\\r\\n\\r\\n.be-callout-color-option-active {\\r\\n border-color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n/* --- code block --- */\\r\\n\\r\\n.be-code-block {\\r\\n margin: 0.6em 0;\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n overflow: hidden;\\r\\n background: var(--noteloom-code-bg);\\r\\n color: var(--noteloom-code-text);\\r\\n}\\r\\n\\r\\n.be-code-block-header {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: flex-end;\\r\\n gap: 4px;\\r\\n padding: 6px 10px;\\r\\n background: rgba(255, 255, 255, 0.04);\\r\\n}\\r\\n\\r\\n.be-code-block-delete {\\r\\n appearance: none;\\r\\n -webkit-appearance: none;\\r\\n border: none;\\r\\n outline: none;\\r\\n background: transparent;\\r\\n box-shadow: none;\\r\\n color: var(--noteloom-text-faint);\\r\\n width: 24px;\\r\\n height: 24px;\\r\\n margin: 0;\\r\\n padding: 0;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-code-block-delete:hover {\\r\\n background: rgba(255, 255, 255, 0.1);\\r\\n color: #fca5a5;\\r\\n}\\r\\n\\r\\n.be-code-block-language {\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-faint);\\r\\n border: none;\\r\\n font-size: 0.8rem;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-code-block-pre {\\r\\n margin: 0;\\r\\n padding: 0.9em 1em;\\r\\n overflow-x: auto;\\r\\n font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;\\r\\n font-size: 0.88rem;\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n.be-code-block-pre code {\\r\\n position: relative;\\r\\n display: block;\\r\\n}\\r\\n\\r\\n/* --- list items (bulleted / numbered / to-do / toggle) --- */\\r\\n\\r\\n.be-list-item {\\r\\n margin: 0.1rem 0;\\r\\n}\\r\\n\\r\\n.be-list-item-row {\\r\\n display: flex;\\r\\n align-items: flex-start;\\r\\n gap: 0.4em;\\r\\n}\\r\\n\\r\\n.be-list-checkbox {\\r\\n margin-top: 0.3em;\\r\\n width: 16px;\\r\\n height: 16px;\\r\\n flex: none;\\r\\n accent-color: var(--noteloom-accent);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-list-toggle-marker {\\r\\n border: none;\\r\\n background: none;\\r\\n cursor: pointer;\\r\\n padding: 2px;\\r\\n margin-top: 0.1em;\\r\\n color: var(--noteloom-text-faint);\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n height: 30px;\\r\\n width: 30px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n}\\r\\n\\r\\n.be-list-toggle-marker:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-list-marker {\\r\\n min-width: 1.2em;\\r\\n margin-top: 0.1em;\\r\\n text-align: center;\\r\\n color: var(--noteloom-text-faint);\\r\\n user-select: none;\\r\\n flex: none;\\r\\n}\\r\\n\\r\\n.be-list-item-title {\\r\\n position: relative;\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n outline: none;\\r\\n line-height: 1.6;\\r\\n}\\r\\n\\r\\n.be-list-item-children {\\r\\n margin-left: 2.1em;\\r\\n}\\r\\n\\r\\n/* --- toggle heading --- */\\r\\n\\r\\n.be-toggle-heading {\\r\\n margin: 1.25rem 0 0.25rem;\\r\\n}\\r\\n\\r\\n.be-toggle-heading-row {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 0.15em;\\r\\n}\\r\\n\\r\\n.be-toggle-heading-marker {\\r\\n border: none;\\r\\n background: none;\\r\\n cursor: pointer;\\r\\n color: var(--noteloom-text-faint);\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 30px;\\r\\n height: 30px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n}\\r\\n\\r\\n.be-toggle-heading-marker:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-toggle-heading-title {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n}\\r\\n\\r\\n.be-toggle-heading-children {\\r\\n margin-left: 2.1em;\\r\\n}\\r\\n\\r\\n/* --- layout (multi-column) --- */\\r\\n\\r\\n.be-layout {\\r\\n margin: 0.6em 0;\\r\\n}\\r\\n\\r\\n.be-layout-column {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n}\\r\\n\\r\\n/* --- button block --- */\\r\\n\\r\\n.be-button-block {\\r\\n margin: 0.6em 0;\\r\\n}\\r\\n\\r\\n.be-button-block-pill {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: 0.4em;\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 0.5em 1em;\\r\\n color: var(--noteloom-accent-text);\\r\\n}\\r\\n\\r\\n.be-button-block-label {\\r\\n position: relative;\\r\\n outline: none;\\r\\n min-width: 2em;\\r\\n}\\r\\n\\r\\n/* --- generic empty-state placeholder for editable leaf content ---\\r\\n Note: this can't use :empty — an \\\"empty\\\" run still holds a zero-width\\r\\n space text node (see EMPTY_RUN_PLACEHOLDER) inside its host span, so the\\r\\n wrapper element is never actually childless. data-empty (kept in sync by\\r\\n EditableBlockContent's syncEmptyAttr against the *logical* run content,\\r\\n not the DOM) is the real signal. */\\r\\n\\r\\n[data-placeholder][data-empty]:focus-within::before {\\r\\n content: attr(data-placeholder);\\r\\n position: absolute;\\r\\n color: var(--noteloom-text-faint);\\r\\n font-weight: 400;\\r\\n font-style: normal;\\r\\n opacity: 0.85;\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n.be-button-block-open,\\r\\n.be-button-block-settings {\\r\\n flex: none;\\r\\n border: none;\\r\\n background: rgba(255, 255, 255, 0.16);\\r\\n color: inherit;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n width: 24px;\\r\\n height: 24px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-button-block-open:disabled {\\r\\n opacity: 0.5;\\r\\n cursor: not-allowed;\\r\\n}\\r\\n\\r\\n.be-button-block-open:hover:not(:disabled),\\r\\n.be-button-block-settings:hover {\\r\\n background: rgba(255, 255, 255, 0.28);\\r\\n}\\r\\n\\r\\n/* --- embed (image/video/audio/file) --- */\\r\\n\\r\\n.be-embed {\\r\\n margin: 0.6em 0;\\r\\n}\\r\\n\\r\\n.be-embed-preview {\\r\\n position: relative;\\r\\n display: flex;\\r\\n}\\r\\n\\r\\n.be-embed-align-left {\\r\\n justify-content: flex-start;\\r\\n}\\r\\n\\r\\n.be-embed-align-center {\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n.be-embed-align-right {\\r\\n justify-content: flex-end;\\r\\n}\\r\\n\\r\\n.be-embed-frame {\\r\\n position: relative;\\r\\n max-width: 100%;\\r\\n overflow: visible;\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n}\\r\\n\\r\\n.be-embed-image,\\r\\n.be-embed-video {\\r\\n border: 1px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n.be-embed-image,\\r\\n.be-embed-video {\\r\\n max-width: 100%;\\r\\n display: block;\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n}\\r\\n\\r\\n.be-embed-audio {\\r\\n width: 100%;\\r\\n}\\r\\n\\r\\n.be-embed-file-link {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 0.5em;\\r\\n padding: 0.75em 1em;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-xl);\\r\\n text-decoration: none;\\r\\n color: var(--noteloom-accent);\\r\\n font-weight: 500;\\r\\n font-size: 0.9rem;\\r\\n}\\r\\n\\r\\n.be-embed-file-link:hover {\\r\\n background: var(--noteloom-bg-subtle);\\r\\n}\\r\\n\\r\\n.be-embed-toolbar {\\r\\n position: absolute;\\r\\n top: 8px;\\r\\n right: 8px;\\r\\n z-index: 2;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 2px;\\r\\n padding: 3px;\\r\\n background: rgba(15, 23, 42, 0.72);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n opacity: 0;\\r\\n transition: opacity 0.12s ease;\\r\\n}\\r\\n\\r\\n.be-embed-preview:hover .be-embed-toolbar,\\r\\n.be-embed-toolbar:focus-within {\\r\\n opacity: 1;\\r\\n}\\r\\n\\r\\n.be-embed-toolbar-btn {\\r\\n border: none;\\r\\n background: transparent;\\r\\n width: 24px;\\r\\n height: 24px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n color: rgba(255, 255, 255, 0.8);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-embed-toolbar-btn:hover {\\r\\n background: rgba(255, 255, 255, 0.16);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n.be-embed-toolbar-btn-active {\\r\\n background: var(--noteloom-accent);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n.be-embed-alt-text-btn {\\r\\n width: auto;\\r\\n padding: 0 8px;\\r\\n font-size: 0.75rem;\\r\\n}\\r\\n\\r\\n.be-embed-remove {\\r\\n border: none;\\r\\n background: transparent;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n padding: 0 8px;\\r\\n height: 24px;\\r\\n color: rgba(255, 255, 255, 0.8);\\r\\n font-size: 0.75rem;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-embed-remove:hover {\\r\\n background: rgba(255, 255, 255, 0.16);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n.be-embed-resize-handle {\\r\\n position: absolute;\\r\\n bottom: 4px;\\r\\n right: 4px;\\r\\n width: 12px;\\r\\n height: 12px;\\r\\n cursor: nwse-resize;\\r\\n border-radius: 2px;\\r\\n border: 1px solid #fff;\\r\\n background: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-embed-dropzone {\\r\\n border: 1.5px dashed var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-xl);\\r\\n padding: 2.2em;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n gap: 0.6em;\\r\\n text-align: center;\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-embed-dropzone-active {\\r\\n border-color: var(--noteloom-accent);\\r\\n background: var(--noteloom-accent-soft);\\r\\n color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-embed-upload-btn {\\r\\n background: var(--noteloom-accent);\\r\\n color: var(--noteloom-accent-text);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 0.5em 1.1em;\\r\\n cursor: pointer;\\r\\n font-size: 0.85rem;\\r\\n font-weight: 500;\\r\\n}\\r\\n\\r\\n.be-embed-upload-btn input {\\r\\n display: none;\\r\\n}\\r\\n\\r\\n.be-embed-dropzone-hint {\\r\\n font-size: 0.8rem;\\r\\n color: var(--noteloom-text-faint);\\r\\n}\\r\\n\\r\\n.be-embed-url-row {\\r\\n display: flex;\\r\\n gap: 6px;\\r\\n width: 100%;\\r\\n max-width: 360px;\\r\\n}\\r\\n\\r\\n.be-embed-url-input {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 0.45em 0.7em;\\r\\n background: transparent;\\r\\n color: inherit;\\r\\n font: inherit;\\r\\n font-size: 0.85rem;\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n.be-embed-url-input:focus {\\r\\n border-color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-embed-url-commit {\\r\\n border: none;\\r\\n background: var(--noteloom-accent);\\r\\n color: var(--noteloom-accent-text);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 0.45em 0.9em;\\r\\n cursor: pointer;\\r\\n font-size: 0.85rem;\\r\\n font-weight: 500;\\r\\n}\\r\\n\\r\\n/* --- canvas (freehand drawing) --- */\\r\\n\\r\\n.be-canvas {\\r\\n position: relative;\\r\\n display: inline-block;\\r\\n margin: 0.6em 0;\\r\\n line-height: 0; /* avoids extra inline-block whitespace gap below the <svg> */\\r\\n}\\r\\n\\r\\n.be-canvas-surface {\\r\\n display: block;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n background: var(--noteloom-bg);\\r\\n max-width: 100%;\\r\\n touch-action: none; /* the surface owns its own pointer gestures (drawing/panning), not the browser's default scroll/zoom */\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar {\\r\\n position: absolute;\\r\\n top: 8px;\\r\\n right: 8px;\\r\\n z-index: 2;\\r\\n display: flex;\\r\\n flex-wrap: wrap;\\r\\n justify-content: flex-end;\\r\\n max-width: calc(100% - 16px);\\r\\n align-items: center;\\r\\n gap: 2px;\\r\\n padding: 3px;\\r\\n background: rgba(15, 23, 42, 0.72);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n opacity: 0;\\r\\n transition: opacity 0.12s ease;\\r\\n}\\r\\n\\r\\n.be-canvas:hover .be-canvas-toolbar,\\r\\n.be-canvas-toolbar:focus-within {\\r\\n opacity: 1;\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar-btn {\\r\\n border: none;\\r\\n background: transparent;\\r\\n width: 28px;\\r\\n height: 24px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n color: rgba(255, 255, 255, 0.8);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar-btn:hover {\\r\\n background: rgba(255, 255, 255, 0.16);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar-btn-active {\\r\\n background: var(--noteloom-accent);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar-btn:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: default;\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar-btn:disabled:hover {\\r\\n background: transparent;\\r\\n}\\r\\n\\r\\n.be-canvas-zoom-label {\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.8);\\r\\n font-size: 0.75rem;\\r\\n min-width: 2.8em;\\r\\n padding: 0 2px;\\r\\n cursor: pointer;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n}\\r\\n\\r\\n.be-canvas-zoom-label:hover {\\r\\n background: rgba(255, 255, 255, 0.16);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar-divider {\\r\\n width: 1px;\\r\\n height: 16px;\\r\\n background: rgba(255, 255, 255, 0.24);\\r\\n margin: 0 2px;\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar-swatch {\\r\\n border: 2px solid transparent;\\r\\n width: 18px;\\r\\n height: 18px;\\r\\n border-radius: 50%;\\r\\n cursor: pointer;\\r\\n padding: 0;\\r\\n}\\r\\n\\r\\n.be-canvas-toolbar-swatch-active {\\r\\n border-color: #fff;\\r\\n}\\r\\n\\r\\n.be-canvas-picker-wrap {\\r\\n position: relative;\\r\\n}\\r\\n\\r\\n.be-canvas-picker {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n right: 0;\\r\\n margin-top: 8px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n padding: 8px;\\r\\n background: rgba(15, 23, 42, 0.92);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n z-index: 3;\\r\\n}\\r\\n\\r\\n.be-canvas-shape-picker {\\r\\n flex-wrap: wrap;\\r\\n max-width: 132px;\\r\\n}\\r\\n\\r\\n.be-canvas-color-trigger-dot {\\r\\n display: block;\\r\\n width: 14px;\\r\\n height: 14px;\\r\\n border-radius: 50%;\\r\\n border: 1px solid rgba(255, 255, 255, 0.6);\\r\\n}\\r\\n\\r\\n.be-canvas-fill-trigger-dot {\\r\\n display: block;\\r\\n width: 14px;\\r\\n height: 14px;\\r\\n border-radius: 50%;\\r\\n border: 1px solid rgba(255, 255, 255, 0.6);\\r\\n}\\r\\n\\r\\n.be-canvas-fill-trigger-dot-none,\\r\\n.be-canvas-fill-swatch-none {\\r\\n background: repeating-conic-gradient(rgba(255, 255, 255, 0.5) 0% 25%, transparent 0% 50%) 50% / 8px 8px;\\r\\n}\\r\\n\\r\\n.be-canvas-custom-swatch {\\r\\n width: 18px;\\r\\n height: 18px;\\r\\n border-radius: 50%;\\r\\n overflow: hidden;\\r\\n border: 1px dashed rgba(255, 255, 255, 0.6);\\r\\n display: inline-flex;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n}\\r\\n\\r\\n.be-canvas-custom-swatch input[type='color'] {\\r\\n width: 150%;\\r\\n height: 150%;\\r\\n margin: -25%;\\r\\n border: none;\\r\\n padding: 0;\\r\\n cursor: pointer;\\r\\n background: none;\\r\\n}\\r\\n\\r\\n/* Live size-preview popover: dot grows/shrinks together with the slider as it's dragged. */\\r\\n.be-canvas-size-picker {\\r\\n min-width: 160px;\\r\\n}\\r\\n\\r\\n.be-canvas-size-trigger-dot {\\r\\n display: block;\\r\\n border-radius: 50%;\\r\\n background: #fff;\\r\\n}\\r\\n\\r\\n.be-canvas-size-preview {\\r\\n flex-shrink: 0;\\r\\n width: 44px;\\r\\n height: 44px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n.be-canvas-size-preview-dot {\\r\\n display: block;\\r\\n border-radius: 50%;\\r\\n background: #fff;\\r\\n}\\r\\n\\r\\n.be-canvas-size-slider {\\r\\n flex: 1;\\r\\n min-width: 80px;\\r\\n}\\r\\n\\r\\n.be-canvas-font-size-trigger {\\r\\n display: block;\\r\\n font-size: 13px;\\r\\n font-weight: 600;\\r\\n line-height: 1;\\r\\n color: rgba(255, 255, 255, 0.85);\\r\\n}\\r\\n\\r\\n.be-canvas-font-size-preview-letter {\\r\\n display: block;\\r\\n line-height: 1;\\r\\n color: #fff;\\r\\n font-weight: 600;\\r\\n}\\r\\n\\r\\n.be-canvas-size-value {\\r\\n flex-shrink: 0;\\r\\n min-width: 2.5em;\\r\\n text-align: right;\\r\\n font-size: 0.8rem;\\r\\n color: rgba(255, 255, 255, 0.85);\\r\\n}\\r\\n\\r\\n.be-canvas[data-tool='eraser'] .be-canvas-surface {\\r\\n cursor: cell;\\r\\n}\\r\\n\\r\\n.be-canvas[data-tool='select'] .be-canvas-surface {\\r\\n cursor: default;\\r\\n}\\r\\n\\r\\n.be-canvas-selection-box {\\r\\n stroke: var(--noteloom-accent);\\r\\n stroke-width: 1.5;\\r\\n stroke-dasharray: 6 4;\\r\\n vector-effect: non-scaling-stroke;\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n.be-canvas-selection-handle {\\r\\n fill: #fff;\\r\\n stroke: var(--noteloom-accent);\\r\\n stroke-width: 1.5;\\r\\n vector-effect: non-scaling-stroke;\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n.be-canvas-rotate-handle {\\r\\n fill: var(--noteloom-accent);\\r\\n stroke: #fff;\\r\\n stroke-width: 1.5;\\r\\n vector-effect: non-scaling-stroke;\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n.be-canvas-marquee {\\r\\n fill: color-mix(in srgb, var(--noteloom-accent) 12%, transparent);\\r\\n stroke: var(--noteloom-accent);\\r\\n stroke-width: 1.5;\\r\\n stroke-dasharray: 6 4;\\r\\n vector-effect: non-scaling-stroke;\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n.be-canvas-grid-background {\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n.be-canvas-grid-dot {\\r\\n fill: rgba(255, 255, 255, 0.18);\\r\\n}\\r\\n\\r\\n.be-canvas-text-editor {\\r\\n width: 100%;\\r\\n height: 100%;\\r\\n margin: 0;\\r\\n padding: 0;\\r\\n border: 1px dashed var(--noteloom-accent);\\r\\n outline: none;\\r\\n background: transparent;\\r\\n resize: none;\\r\\n overflow: hidden;\\r\\n line-height: 1.3;\\r\\n font-family: inherit;\\r\\n white-space: pre-wrap;\\r\\n word-break: break-word;\\r\\n}\\r\\n\\r\\n.be-canvas-resize-handle {\\r\\n position: absolute;\\r\\n bottom: 4px;\\r\\n right: 4px;\\r\\n width: 12px;\\r\\n height: 12px;\\r\\n cursor: nwse-resize;\\r\\n border-radius: 2px;\\r\\n border: 1px solid #fff;\\r\\n background: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n/* --- table --- */\\r\\n\\r\\n.be-table-scroll {\\r\\n max-width: 100%;\\r\\n overflow-x: auto;\\r\\n}\\r\\n\\r\\n.be-table-wrapper {\\r\\n margin: 0.9em 0;\\r\\n overflow-x: auto;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n width: max-content;\\r\\n}\\r\\n\\r\\n.be-table {\\r\\n border-collapse: collapse;\\r\\n table-layout: fixed;\\r\\n /* Deliberately no width:100% — combined with table-layout:fixed and each\\r\\n column's own <col> width, that would make the browser redistribute\\r\\n leftover space proportionally across columns, fighting individual\\r\\n column resize (see be-table-col-resize-handle). */\\r\\n}\\r\\n\\r\\n.be-table-header-row {\\r\\n background: var(--noteloom-bg-subtle);\\r\\n}\\r\\n\\r\\n.be-table-header-cell {\\r\\n position: relative;\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n border-right: 1px solid var(--noteloom-border);\\r\\n padding: 6px 10px;\\r\\n}\\r\\n\\r\\n.be-table-header-label {\\r\\n display: block;\\r\\n width: 100%;\\r\\n border: none;\\r\\n background: none;\\r\\n font: inherit;\\r\\n font-weight: 600;\\r\\n font-size: 0.78rem;\\r\\n color: var(--noteloom-text-muted);\\r\\n outline: none;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n padding: 2px 0;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-trigger {\\r\\n position: absolute;\\r\\n right: 4px;\\r\\n top: 50%;\\r\\n transform: translateY(-50%);\\r\\n visibility: hidden;\\r\\n border: none;\\r\\n background: transparent;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n padding: 2px;\\r\\n color: var(--noteloom-text-faint);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-table-header-cell:hover .be-table-header-menu-trigger {\\r\\n visibility: visible;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-trigger:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-table-col-resize-handle {\\r\\n position: absolute;\\r\\n top: 0;\\r\\n right: -3px;\\r\\n width: 6px;\\r\\n height: 100%;\\r\\n cursor: col-resize;\\r\\n z-index: 1;\\r\\n}\\r\\n\\r\\n.be-table-col-resize-handle:hover,\\r\\n.be-table-col-resize-handle:active {\\r\\n background: var(--noteloom-accent-soft-hover);\\r\\n}\\r\\n\\r\\n.be-table-header-spacer {\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n.be-table-header-spacer-col {\\r\\n width: 32px;\\r\\n}\\r\\n\\r\\n.be-table-header-menu {\\r\\n z-index: 1000;\\r\\n width: 224px;\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n background: var(--noteloom-bg);\\r\\n padding: 4px;\\r\\n font-size: 0.88rem;\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n}\\r\\n\\r\\n.be-table-header-menu-options {\\r\\n z-index: 1000;\\r\\n padding: 4px;\\r\\n font-size: 0.88rem;\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n margin-bottom: 4px;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-type {\\r\\n display: flex;\\r\\n flex-direction: row;\\r\\n justify-content: space-between;\\r\\n padding: 6px;\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n margin-bottom: 4px;\\r\\n}\\r\\n\\r\\n.be-table-header-type-select {\\r\\n width: 100%;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n padding: 6px 8px;\\r\\n background: transparent;\\r\\n color: inherit;\\r\\n font: inherit;\\r\\n font-size: 0.85rem;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-item {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 8px;\\r\\n width: 100%;\\r\\n text-align: left;\\r\\n border: none;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n background: transparent;\\r\\n padding: 6px 10px;\\r\\n font: inherit;\\r\\n font-size: 0.88rem;\\r\\n color: var(--noteloom-text);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-item:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-table-header-menu-item-danger {\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n.be-table-header-menu-item-danger:hover {\\r\\n background: var(--noteloom-danger-soft);\\r\\n}\\r\\n\\r\\n.be-table-header-menu-options-label {\\r\\n font-size: 0.68rem;\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.04em;\\r\\n font-weight: 600;\\r\\n color: var(--noteloom-text-faint);\\r\\n padding: 6px 8px 2px;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-option-row {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n padding: 2px 4px;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-option-swatch {\\r\\n width: 14px;\\r\\n height: 14px;\\r\\n border-radius: 50%;\\r\\n flex: none;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-option-input {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: inherit;\\r\\n font: inherit;\\r\\n font-size: 0.85rem;\\r\\n padding: 4px 6px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n.be-table-header-menu-option-input:focus {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-table-header-menu-option-remove,\\r\\n.be-table-header-menu-option-add {\\r\\n flex: none;\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-faint);\\r\\n cursor: pointer;\\r\\n padding: 3px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n}\\r\\n\\r\\n.be-table-header-menu-option-remove:hover {\\r\\n background: var(--noteloom-danger-soft);\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n.be-table-header-menu-option-add {\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-table-header-menu-option-add:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-table-row:hover {\\r\\n background: var(--noteloom-bg-subtle);\\r\\n}\\r\\n\\r\\n.be-table-cell {\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n border-right: 1px solid var(--noteloom-border);\\r\\n padding: 6px 10px;\\r\\n vertical-align: top;\\r\\n outline: none;\\r\\n font-size: 0.92rem;\\r\\n /* table-layout: fixed already keeps the COLUMN width from growing to fit\\r\\n content — this is what stops a long unbroken string (a URL, one giant\\r\\n word) from visually overflowing past that fixed width instead of\\r\\n wrapping onto a new line within the cell. */\\r\\n max-width: 0;\\r\\n overflow-wrap: anywhere;\\r\\n word-break: break-word;\\r\\n}\\r\\n\\r\\n.be-table-cell:focus-within {\\r\\n box-shadow: inset 0 0 0 2px var(--noteloom-accent);\\r\\n border-radius: 2px;\\r\\n}\\r\\n\\r\\n.be-table-row-actions {\\r\\n width: 32px;\\r\\n text-align: center;\\r\\n vertical-align: middle;\\r\\n border: none;\\r\\n background: transparent;\\r\\n padding: 0;\\r\\n}\\r\\n\\r\\n.be-table-delete-row {\\r\\n visibility: hidden;\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-faint);\\r\\n cursor: pointer;\\r\\n width: 24px;\\r\\n height: 24px;\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n}\\r\\n\\r\\ntr.be-table-row:hover .be-table-delete-row {\\r\\n visibility: visible;\\r\\n}\\r\\n\\r\\n.be-table-delete-row:hover {\\r\\n background: var(--noteloom-danger-soft);\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n.be-table-add-row {\\r\\n display: block;\\r\\n width: 100%;\\r\\n border: none;\\r\\n background: transparent;\\r\\n text-align: left;\\r\\n padding: 8px 12px;\\r\\n color: var(--noteloom-text-faint);\\r\\n cursor: pointer;\\r\\n font: inherit;\\r\\n font-size: 0.85rem;\\r\\n font-weight: 500;\\r\\n}\\r\\n\\r\\n.be-table-add-row:hover {\\r\\n background: var(--noteloom-bg-subtle);\\r\\n color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-inline-table-select {\\r\\n display: block;\\r\\n}\\r\\n\\r\\n.be-inline-table-select .be-select {\\r\\n width: 100%;\\r\\n}\\r\\n\\r\\n.be-inline-table-select .be-select .be-select-tag {\\r\\n width: -webkit-fill-available;\\r\\n}\\r\\n\\r\\n.be-inline-table-select .be-select-trigger {\\r\\n display: flex;\\r\\n width: 100%;\\r\\n min-width: 0;\\r\\n min-height: 0;\\r\\n border: none;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n background: transparent;\\r\\n padding: 0;\\r\\n font: inherit;\\r\\n font-size: 0.92rem;\\r\\n}\\r\\n\\r\\n.be-inline-table-select .be-select-trigger:hover,\\r\\n.be-inline-table-select .be-select-trigger[aria-expanded='true'] {\\r\\n background: var(--noteloom-bg-hover);\\r\\n box-shadow: none;\\r\\n}\\r\\n\\r\\n/* --- per-block hover gutter (+ / drag-handle / menu) --- */\\r\\n\\r\\n.be-block-row {\\r\\n position: relative;\\r\\n}\\r\\n\\r\\n.be-block-row-hidden {\\r\\n opacity: 0.4;\\r\\n}\\r\\n\\r\\n.be-block-gutter {\\r\\n position: absolute;\\r\\n left: -56px;\\r\\n top: 0.15em;\\r\\n display: flex;\\r\\n gap: 2px;\\r\\n opacity: 0;\\r\\n transition: opacity 0.1s ease;\\r\\n user-select: none; /* it's a drag handle (see useBlockRangeDrag) — never let its own space become selectable text */\\r\\n}\\r\\n\\r\\n/* `left`/`right` are physical, not logical, properties — unlike the list\\r\\n marker's flexbox position (which flips for free via dir inheritance),\\r\\n this absolute offset needs an explicit RTL override to sit on the\\r\\n correct side of the block. */\\r\\n[dir='rtl'] .be-block-gutter {\\r\\n left: auto;\\r\\n right: -56px;\\r\\n}\\r\\n\\r\\n.be-block-row:hover .be-block-gutter,\\r\\n.be-block-gutter-active {\\r\\n opacity: 1;\\r\\n}\\r\\n\\r\\n.be-block-gutter-btn {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 24px;\\r\\n height: 24px;\\r\\n border: none;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-faint);\\r\\n cursor: pointer;\\r\\n transition: background-color 0.12s ease, color 0.12s ease;\\r\\n}\\r\\n\\r\\n/* Touch: no hover state exists to reveal the gutter at all, and its\\r\\n desktop position (left: -56px, sitting in the page's own side margin)\\r\\n would be off-screen on a narrow phone/tablet viewport regardless — so\\r\\n rather than force it into the row itself, its two actions (Add block,\\r\\n block options menu) live inside MobileActionBar instead (see\\r\\n MobileActionBar.jsx), pinned above the keyboard where they're always\\r\\n reachable. `.be-touch-input` is set by useCoarsePointer.js, based on\\r\\n real pointerdown activity, not just a static device-capability guess —\\r\\n see that file for why a plain `pointer: coarse` media query alone isn't\\r\\n enough (touchscreen laptops, etc.). */\\r\\n.be-touch-input .be-block-gutter {\\r\\n display: none;\\r\\n}\\r\\n\\r\\n.be-block-gutter-btn:hover,\\r\\n.be-block-gutter-btn[aria-expanded='true'] {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-block-gutter-menu,\\r\\n.be-block-range-menu {\\r\\n z-index: 1000;\\r\\n min-width: 200px;\\r\\n background: var(--noteloom-bg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n padding: 4px;\\r\\n}\\r\\n\\r\\n.be-block-gutter-menu-item,\\r\\n.be-block-range-menu-item {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 8px;\\r\\n width: 100%;\\r\\n text-align: left;\\r\\n border: none;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n background: transparent;\\r\\n padding: 7px 10px;\\r\\n font: inherit;\\r\\n font-size: 0.88rem;\\r\\n color: var(--noteloom-text);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-block-gutter-menu-item:hover,\\r\\n.be-block-range-menu-item:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-block-gutter-menu-item-danger,\\r\\n.be-block-range-menu-item-danger {\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n.be-block-gutter-menu-item-danger:hover,\\r\\n.be-block-range-menu-item-danger:hover {\\r\\n background: var(--noteloom-danger-soft);\\r\\n}\\r\\n\\r\\n/* --- drag-in-the-margin block range selection --- */\\r\\n\\r\\n.be-block-row-range-selected {\\r\\n background: var(--noteloom-accent-soft);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n margin: 0 -8px;\\r\\n padding: 0 8px;\\r\\n}\\r\\n\\r\\n.be-block-range-dragging,\\r\\n.be-block-range-dragging * {\\r\\n user-select: none !important;\\r\\n}\\r\\n\\r\\n/* --- whole-document select-all / single non-editable block selected --- */\\r\\n\\r\\n.be-surface--all-selected .be-block-row-content > [data-block-id] {\\r\\n background: var(--noteloom-accent-soft);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n}\\r\\n\\r\\n.be-block-selected {\\r\\n outline: 2px solid var(--noteloom-accent);\\r\\n outline-offset: 2px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n}\\r\\n\\r\\n/* --- document export (view source) --- */\\r\\n\\r\\n.be-export-trigger {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n background: var(--noteloom-bg);\\r\\n color: var(--noteloom-text-muted);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n padding: 5px 10px;\\r\\n font-size: 0.85rem;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-export-trigger:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-export-tabs {\\r\\n display: flex;\\r\\n gap: 4px;\\r\\n margin-bottom: 10px;\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n.be-export-tab {\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-muted);\\r\\n padding: 6px 10px;\\r\\n margin-bottom: -1px;\\r\\n border-bottom: 2px solid transparent;\\r\\n font-size: 0.85rem;\\r\\n font-weight: 500;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-export-tab:hover {\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-export-tab-active {\\r\\n color: var(--noteloom-accent);\\r\\n border-bottom-color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-export-pre {\\r\\n max-height: 50vh;\\r\\n overflow: auto;\\r\\n margin: 0;\\r\\n padding: 0.9em 1em;\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n background: var(--noteloom-code-bg);\\r\\n color: var(--noteloom-code-text);\\r\\n font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;\\r\\n font-size: 0.8rem;\\r\\n line-height: 1.5;\\r\\n white-space: pre-wrap;\\r\\n overflow-wrap: anywhere;\\r\\n}\\r\\n\\r\\n/* --- trailing click-to-continue space --- */\\r\\n\\r\\n.be-trailing-space {\\r\\n cursor: text;\\r\\n width: 100%;\\r\\n min-height: 180px;\\r\\n}\\r\\n\\r\\n/* --- modal (button editor, field type editor) --- */\\r\\n\\r\\n.be-modal-overlay {\\r\\n position: fixed;\\r\\n inset: 0;\\r\\n background: rgba(15, 23, 42, 0.45);\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n z-index: 2000;\\r\\n padding: 1em;\\r\\n}\\r\\n\\r\\n.be-modal {\\r\\n background: var(--noteloom-bg);\\r\\n color: var(--noteloom-text);\\r\\n border-radius: var(--noteloom-radius-xl);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n padding: 1.4em;\\r\\n width: 100%;\\r\\n max-width: 380px;\\r\\n max-height: 85vh;\\r\\n overflow-y: auto;\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n}\\r\\n\\r\\n.be-modal-large {\\r\\n max-width: 640px;\\r\\n}\\r\\n\\r\\n/* Bottom sheet variant (mobile block picker) — anchored to the bottom edge\\r\\n instead of centered, rounded only on top, full page width. */\\r\\n.be-modal-overlay-sheet {\\r\\n align-items: flex-end;\\r\\n padding: 0;\\r\\n}\\r\\n\\r\\n.be-modal-sheet {\\r\\n max-width: 100%;\\r\\n width: 100%;\\r\\n max-height: 70vh;\\r\\n border-radius: var(--noteloom-radius-xl) var(--noteloom-radius-xl) 0 0;\\r\\n border-bottom: none;\\r\\n padding-bottom: max(1.4em, env(safe-area-inset-bottom));\\r\\n}\\r\\n\\r\\n.be-mobile-picker-list {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 2px;\\r\\n}\\r\\n\\r\\n.be-mobile-picker-item {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n width: 100%;\\r\\n border: none;\\r\\n background: transparent;\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 12px 10px;\\r\\n font: inherit;\\r\\n font-size: 0.95rem;\\r\\n color: var(--noteloom-text);\\r\\n text-align: left;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-mobile-picker-item:hover,\\r\\n.be-mobile-picker-item:active {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-mobile-picker-item-danger {\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n.be-mobile-picker-item-danger:hover,\\r\\n.be-mobile-picker-item-danger:active {\\r\\n background: var(--noteloom-danger-soft);\\r\\n}\\r\\n\\r\\n.be-mobile-picker-item-danger .be-mobile-picker-item-icon {\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n/* --- template picker (see TemplatePicker.jsx) --- */\\r\\n\\r\\n.be-template-picker {\\r\\n list-style: none;\\r\\n margin: 0;\\r\\n padding: 0;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 6px;\\r\\n}\\r\\n\\r\\n.be-template-picker-empty {\\r\\n color: var(--noteloom-text-faint);\\r\\n font-size: 0.88rem;\\r\\n}\\r\\n\\r\\n.be-template-card {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n gap: 12px;\\r\\n padding: 10px 12px;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n background: var(--noteloom-bg);\\r\\n}\\r\\n\\r\\n.be-template-card-body {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 2px;\\r\\n min-width: 0;\\r\\n}\\r\\n\\r\\n.be-template-card-name {\\r\\n font-weight: 600;\\r\\n font-size: 0.92rem;\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-template-card-description {\\r\\n font-size: 0.82rem;\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-template-card-select {\\r\\n flex: none;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n background: var(--noteloom-bg-subtle);\\r\\n color: var(--noteloom-text);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n padding: 5px 12px;\\r\\n font-size: 0.85rem;\\r\\n font-weight: 500;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-template-card-select:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n/* --- mobile action bar (pinned above the on-screen keyboard) --- */\\r\\n\\r\\n.be-mobile-action-bar {\\r\\n position: fixed;\\r\\n left: 0;\\r\\n right: 0;\\r\\n z-index: 1500;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 2px;\\r\\n padding: 6px calc(6px + env(safe-area-inset-right)) 6px calc(6px + env(safe-area-inset-left));\\r\\n background: var(--noteloom-bg);\\r\\n border-top: 1px solid var(--noteloom-border);\\r\\n overflow-x: auto;\\r\\n}\\r\\n\\r\\n.be-mobile-bar-btn {\\r\\n flex: none;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n gap: 4px;\\r\\n min-width: 40px;\\r\\n height: 40px;\\r\\n padding: 0 10px;\\r\\n border: none;\\r\\n background: transparent;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n color: var(--noteloom-text);\\r\\n font-size: 0.85rem;\\r\\n font-weight: 500;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-mobile-bar-btn:disabled {\\r\\n opacity: 0.4;\\r\\n}\\r\\n\\r\\n.be-mobile-bar-btn-active {\\r\\n background: var(--noteloom-accent-soft);\\r\\n color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-mobile-bar-spacer {\\r\\n flex: 1;\\r\\n}\\r\\n\\r\\n.be-mobile-bar-select {\\r\\n flex: none;\\r\\n}\\r\\n\\r\\n.be-mobile-bar-swatches {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n padding: 0 6px;\\r\\n}\\r\\n\\r\\n.be-mobile-picker-item-icon {\\r\\n flex: none;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 32px;\\r\\n height: 32px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n background: var(--noteloom-bg-subtle);\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-modal-title {\\r\\n font-weight: 600;\\r\\n font-size: 1.05rem;\\r\\n margin-bottom: 1em;\\r\\n}\\r\\n\\r\\n.be-modal-field {\\r\\n display: block;\\r\\n margin-bottom: 1em;\\r\\n}\\r\\n\\r\\n.be-modal-field > span {\\r\\n display: block;\\r\\n font-size: 0.8rem;\\r\\n color: var(--noteloom-text-muted);\\r\\n margin-bottom: 5px;\\r\\n}\\r\\n\\r\\n.be-modal-field input[type='text'],\\r\\n.be-modal-field input[type='url'] {\\r\\n width: 100%;\\r\\n box-sizing: border-box;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 0.55em 0.75em;\\r\\n background: transparent;\\r\\n color: inherit;\\r\\n font: inherit;\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n.be-modal-field input[type='text']:focus,\\r\\n.be-modal-field input[type='url']:focus {\\r\\n border-color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-modal-field select {\\r\\n width: 100%;\\r\\n box-sizing: border-box;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 0.55em 0.75em;\\r\\n background: transparent;\\r\\n color: inherit;\\r\\n font: inherit;\\r\\n font-size: 0.9rem;\\r\\n}\\r\\n\\r\\n.be-modal-field select:focus {\\r\\n border-color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-modal-color-row {\\r\\n display: flex;\\r\\n gap: 8px;\\r\\n flex-wrap: wrap;\\r\\n}\\r\\n\\r\\n.be-modal-color-swatch {\\r\\n width: 26px;\\r\\n height: 26px;\\r\\n border-radius: 50%;\\r\\n border: 2px solid transparent;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-modal-color-swatch-active {\\r\\n border-color: var(--noteloom-accent);\\r\\n box-shadow: 0 0 0 2px var(--noteloom-bg), 0 0 0 4px var(--noteloom-accent-soft);\\r\\n}\\r\\n\\r\\n.be-modal-attr-row {\\r\\n display: flex;\\r\\n gap: 6px;\\r\\n margin-bottom: 6px;\\r\\n align-items: center;\\r\\n}\\r\\n\\r\\n.be-modal-attr-row input {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n padding: 0.4em 0.6em;\\r\\n background: transparent;\\r\\n color: inherit;\\r\\n font: inherit;\\r\\n font-size: 0.85rem;\\r\\n}\\r\\n\\r\\n.be-modal-attr-remove {\\r\\n flex: none;\\r\\n border: none;\\r\\n background: none;\\r\\n color: var(--noteloom-text-faint);\\r\\n cursor: pointer;\\r\\n padding: 2px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n}\\r\\n\\r\\n.be-modal-attr-remove:hover {\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n.be-modal-actions {\\r\\n display: flex;\\r\\n justify-content: flex-end;\\r\\n gap: 8px;\\r\\n margin-top: 20px;\\r\\n}\\r\\n\\r\\n.be-modal-delete {\\r\\n margin-right: auto; /* pushes Cancel/Save to the right, Delete stays on its own at the left */\\r\\n}\\r\\n\\r\\n.be-modal-cancel,\\r\\n.be-modal-save,\\r\\n.be-modal-delete {\\r\\n border: none;\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 7px 16px;\\r\\n font-size: 0.85rem;\\r\\n font-weight: 500;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-modal-delete {\\r\\n background: var(--noteloom-danger-soft);\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n.be-modal-cancel {\\r\\n background: var(--noteloom-bg-subtle);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-modal-cancel:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-modal-save {\\r\\n background: var(--noteloom-accent);\\r\\n color: var(--noteloom-accent-text);\\r\\n}\\r\\n\\r\\n.be-modal-save:hover {\\r\\n opacity: 0.9;\\r\\n}\\r\\n\\r\\n.be-modal-save:disabled {\\r\\n opacity: 0.5;\\r\\n cursor: not-allowed;\\r\\n}\\r\\n\\r\\n/* --- slash (\\\"/\\\") / emoji (\\\":\\\") / mention (\\\"@\\\") command menu --- */\\r\\n\\r\\n.be-slash-menu {\\r\\n z-index: 1000;\\r\\n width: 260px;\\r\\n max-height: 320px;\\r\\n overflow-y: auto;\\r\\n background: var(--noteloom-bg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n padding: 6px;\\r\\n}\\r\\n\\r\\n.be-slash-menu-item {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n padding: 7px 8px;\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n cursor: pointer;\\r\\n font-size: 0.9rem;\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-slash-menu-item-active,\\r\\n.be-slash-menu-item:hover {\\r\\n background: var(--noteloom-accent-soft);\\r\\n}\\r\\n\\r\\n.be-slash-menu-item-icon {\\r\\n flex: none;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 28px;\\r\\n height: 28px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-slash-menu-item-label {\\r\\n flex: 1;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n}\\r\\n\\r\\n/* --- searchable Select (inline select/date/checkbox widgets, custom field types, table column type) --- */\\r\\n\\r\\n.be-select {\\r\\n display: inline-flex;\\r\\n}\\r\\n\\r\\n.be-select-trigger {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n min-height: 28px;\\r\\n min-width: 6em;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n background: var(--noteloom-bg);\\r\\n color: var(--noteloom-text);\\r\\n font: inherit;\\r\\n font-size: 0.88rem;\\r\\n padding: 4px 8px;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-select-trigger:hover {\\r\\n border-color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-select-trigger[aria-expanded='true'] {\\r\\n border-color: var(--noteloom-accent);\\r\\n box-shadow: 0 0 0 2px var(--noteloom-accent-soft);\\r\\n}\\r\\n\\r\\n.be-select-trigger-tag {\\r\\n min-width: 0;\\r\\n min-height: 0;\\r\\n border: none;\\r\\n background: transparent;\\r\\n padding: 2px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n outline: none;\\r\\n border: none;\\r\\n}\\r\\n\\r\\n.be-select-trigger-tag:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-select-trigger-tag[aria-expanded='true'] {\\r\\n background: var(--noteloom-bg-hover);\\r\\n box-shadow: none;\\r\\n}\\r\\n\\r\\n.be-select-value-placeholder {\\r\\n color: var(--noteloom-text-faint);\\r\\n}\\r\\n\\r\\n.be-select-tag {\\r\\n display: inline-flex;\\r\\n flex: none;\\r\\n max-width: 100%;\\r\\n padding: 2px 9px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n font-size: 0.82em;\\r\\n font-weight: 500;\\r\\n line-height: 1.4;\\r\\n /* Wraps rather than truncates — a fixed-width popover (see\\r\\n .be-select-popover) or table cell (see .be-table-cell) combined with\\r\\n nowrap+ellipsis let long option text silently overflow its box\\r\\n instead of actually being clipped; wrapping sidesteps that entirely. */\\r\\n white-space: normal;\\r\\n overflow-wrap: anywhere;\\r\\n word-break: break-word;\\r\\n}\\r\\n\\r\\n.be-select-value {\\r\\n flex: 1;\\r\\n text-align: left;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n}\\r\\n\\r\\n.be-select-chevron {\\r\\n flex: none;\\r\\n color: var(--noteloom-text-faint);\\r\\n}\\r\\n\\r\\n.be-select-popover {\\r\\n z-index: 1000;\\r\\n width: 224px;\\r\\n background: var(--noteloom-bg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n overflow: hidden;\\r\\n}\\r\\n\\r\\n.be-select-search {\\r\\n display: block;\\r\\n width: 100%;\\r\\n box-sizing: border-box;\\r\\n border: none;\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n background: transparent;\\r\\n color: inherit;\\r\\n padding: 10px 12px;\\r\\n font: inherit;\\r\\n font-size: 0.88rem;\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n.be-select-options {\\r\\n max-height: 220px;\\r\\n overflow-y: auto;\\r\\n overflow-x: hidden;\\r\\n padding: 4px;\\r\\n}\\r\\n\\r\\n.be-select-option {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n min-width: 0;\\r\\n padding: 7px 8px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n font-size: 0.88rem;\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n/* A tag-variant option list (colored pills — e.g. Priority/Assignee) must\\r\\n read at the exact same size/weight as a plain default-variant list\\r\\n (Diagnosis) — only the colored-chip background should differ between\\r\\n them, not the typography. .be-select-tag's own font-size/weight (sized\\r\\n down for when it's squeezed into a trigger button) would otherwise make\\r\\n tag-variant options look smaller/bolder than plain ones for no reason. */\\r\\n.be-select-option .be-select-tag {\\r\\n font-size: inherit;\\r\\n font-weight: inherit;\\r\\n line-height: inherit;\\r\\n width: -webkit-fill-available;\\r\\n}\\r\\n\\r\\n.be-select-option-active {\\r\\n background: var(--noteloom-accent-soft);\\r\\n}\\r\\n\\r\\n.be-select-option-selected {\\r\\n font-weight: 600;\\r\\n}\\r\\n\\r\\n.be-select-option-selected:not(.be-select-option-active) {\\r\\n background: var(--noteloom-bg-subtle);\\r\\n}\\r\\n\\r\\n.be-select-option-selected .be-select-tag {\\r\\n font-weight: 500;\\r\\n box-shadow: inset 0 0 0 1.5px rgba(0, 0, 0, 0.2);\\r\\n}\\r\\n\\r\\n.be-select-empty {\\r\\n padding: 10px 12px;\\r\\n color: var(--noteloom-text-faint);\\r\\n font-size: 0.85rem;\\r\\n text-align: center;\\r\\n}\\r\\n\\r\\n.be-select-error {\\r\\n color: var(--noteloom-danger);\\r\\n}\\r\\n\\r\\n.be-select-manage-options {\\r\\n display: block;\\r\\n width: 100%;\\r\\n box-sizing: border-box;\\r\\n border: none;\\r\\n border-top: 1px solid var(--noteloom-border);\\r\\n background: transparent;\\r\\n padding: 9px 12px;\\r\\n font: inherit;\\r\\n font-size: 0.82rem;\\r\\n font-weight: 500;\\r\\n color: var(--noteloom-accent);\\r\\n text-align: left;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-select-manage-options:hover {\\r\\n background: var(--noteloom-accent-soft);\\r\\n}\\r\\n\\r\\n.be-inline-select,\\r\\n.be-inline-date,\\r\\n.be-inline-checkbox {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n vertical-align: middle;\\r\\n}\\r\\n\\r\\n/* Inline chips sit in running text — match the surrounding line's own font\\r\\n size instead of the smaller size used for the Select component elsewhere\\r\\n (menus, table column type dropdown), where a compact UI size is right. */\\r\\n.be-inline-select .be-select-trigger {\\r\\n min-height: 0;\\r\\n font-size: 1em;\\r\\n padding: 1px 8px;\\r\\n}\\r\\n\\r\\n.be-inline-select .be-select-tag {\\r\\n font-size: 0.92em;\\r\\n}\\r\\n\\r\\n/* A mention reads as highlighted text sitting inline in the paragraph, not\\r\\n a bulky standalone pill/button — minimal padding, small radius, no extra\\r\\n chrome from the trigger button wrapping it. */\\r\\n.be-inline-select .be-select-trigger-mention {\\r\\n padding: 0 !important;\\r\\n border-radius: 3px;\\r\\n}\\r\\n\\r\\n/* A mention chip always uses this one fixed color, not each option's own\\r\\n tag color — \\\"@mentions are one consistent color\\\" is the common\\r\\n convention rather than a per-person palette. */\\r\\n.be-select-tag-mention {\\r\\n background: var(--noteloom-accent-soft);\\r\\n color: var(--noteloom-accent);\\r\\n font-weight: 500;\\r\\n padding: 0 3px;\\r\\n border-radius: 3px;\\r\\n line-height: inherit;\\r\\n}\\r\\n\\r\\n.be-inline-date input[type='date'] {\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n background: var(--noteloom-bg);\\r\\n color: inherit;\\r\\n padding: 4px 8px;\\r\\n font: inherit;\\r\\n font-size: 0.88rem;\\r\\n}\\r\\n\\r\\n.be-inline-checkbox {\\r\\n gap: 6px;\\r\\n}\\r\\n\\r\\n.be-inline-checkbox-input {\\r\\n flex: none;\\r\\n width: 16px;\\r\\n height: 16px;\\r\\n margin: 0;\\r\\n accent-color: var(--noteloom-accent);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-inline-checkbox-label {\\r\\n min-width: 0;\\r\\n flex: 1;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n background: transparent;\\r\\n color: inherit;\\r\\n font: inherit;\\r\\n padding: 2px 8px;\\r\\n outline: none;\\r\\n}\\r\\n\\r\\n.be-inline-checkbox-label:focus {\\r\\n border-color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n/* In a table cell (checkbox column), the browser's default text-input\\r\\n width (~170px+) is wider than most columns, forcing the input — and with\\r\\n it, the whole table — past the cell's own bounds. Constraining the\\r\\n inline-flex row to the cell's actual width lets the label's flex:1 +\\r\\n min-width:0 (above) do their job and shrink the input to fit instead. */\\r\\n.be-table-cell .be-inline-checkbox {\\r\\n display: flex;\\r\\n width: 100%;\\r\\n}\\r\\n\\r\\n.be-inline-checkbox-label::placeholder {\\r\\n color: var(--noteloom-text-faint);\\r\\n}\\r\\n\\r\\n/* --- floating (selection) format toolbar --- */\\r\\n\\r\\n.be-floating-toolbar {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 2px;\\r\\n background: var(--noteloom-text);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 4px;\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n z-index: 1000;\\r\\n}\\r\\n\\r\\n.be-floating-toolbar-btn {\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: rgba(255, 255, 255, 0.85);\\r\\n width: 30px;\\r\\n height: 30px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-floating-toolbar-btn:hover {\\r\\n background: rgba(255, 255, 255, 0.14);\\r\\n}\\r\\n\\r\\n.be-floating-toolbar-btn-active {\\r\\n background: var(--noteloom-accent);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n.be-floating-toolbar-divider {\\r\\n width: 1px;\\r\\n height: 20px;\\r\\n background: rgba(255, 255, 255, 0.2);\\r\\n margin: 0 4px;\\r\\n}\\r\\n\\r\\n.be-floating-toolbar-picker-wrap {\\r\\n position: relative;\\r\\n}\\r\\n\\r\\n.be-floating-toolbar-picker {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n left: 0;\\r\\n margin-top: 8px;\\r\\n display: flex;\\r\\n gap: 4px;\\r\\n background: var(--noteloom-bg);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 6px;\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n}\\r\\n\\r\\n.be-floating-toolbar-swatch {\\r\\n width: 22px;\\r\\n height: 22px;\\r\\n border-radius: 50%;\\r\\n border: 1px solid rgba(0, 0, 0, 0.1);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n/* --- link hover card (edit/remove an existing link mark) --- */\\r\\n\\r\\n.be-link-hover-card {\\r\\n z-index: 1000;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 2px;\\r\\n max-width: 320px;\\r\\n background: var(--noteloom-bg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 5px 6px 5px 10px;\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n font-size: 0.85rem;\\r\\n}\\r\\n\\r\\n.be-link-hover-card-url {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n color: var(--noteloom-accent);\\r\\n text-decoration: none;\\r\\n}\\r\\n\\r\\n.be-link-hover-card-url:hover {\\r\\n text-decoration: underline;\\r\\n}\\r\\n\\r\\n.be-link-hover-card-btn {\\r\\n flex: none;\\r\\n width: 24px;\\r\\n height: 24px;\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-muted);\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-link-hover-card-btn:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n/* --- comments: avatar, header, composer, thread card, click/hover popover, right-side panel --- */\\r\\n\\r\\n.be-comment-avatar {\\r\\n flex: none;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border-radius: 50%;\\r\\n color: #fff;\\r\\n font-weight: 700;\\r\\n line-height: 1;\\r\\n}\\r\\n\\r\\n/* Shared by CommentPopover and FloatingToolbar's standalone composer (see\\r\\n CommentPopoverHeader.jsx) -- title on the left, an explicit close button\\r\\n on the right so dismissing doesn't rely solely on Escape/outside-click. */\\r\\n.be-comment-popover-header {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n gap: 8px;\\r\\n margin-bottom: 10px;\\r\\n padding-bottom: 10px;\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n.be-comment-popover-title {\\r\\n font-weight: 700;\\r\\n font-size: 0.9rem;\\r\\n}\\r\\n\\r\\n.be-comment-popover-close {\\r\\n flex: none;\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-muted);\\r\\n width: 22px;\\r\\n height: 22px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-comment-popover-close:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n/* Overrides the dark `.be-floating-toolbar` chrome it also carries (see\\r\\n FloatingToolbar.jsx's own comment on why that base class stays) -- a\\r\\n comment composer reads better as a light card than white text on the\\r\\n toolbar's own near-black background. */\\r\\n.be-floating-toolbar.be-floating-toolbar-comment-standalone {\\r\\n display: block;\\r\\n background: var(--noteloom-bg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n padding: 10px 12px 12px;\\r\\n width: 300px;\\r\\n}\\r\\n\\r\\n.be-comment-composer {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 10px;\\r\\n margin-top: 10px;\\r\\n}\\r\\n\\r\\n.be-comment-composer-input-row {\\r\\n display: flex;\\r\\n align-items: flex-start;\\r\\n gap: 8px;\\r\\n}\\r\\n\\r\\n.be-comment-composer-textarea {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n box-sizing: border-box;\\r\\n resize: none;\\r\\n /* ~2 lines to start, grows with content (see CommentComposer's own\\r\\n resizeToContent) up to ~5 lines, then scrolls. */\\r\\n min-height: 2.8em;\\r\\n max-height: 7.2em;\\r\\n overflow-y: auto;\\r\\n padding: 8px 10px;\\r\\n font: inherit;\\r\\n font-size: 0.85rem;\\r\\n line-height: 1.4;\\r\\n color: var(--noteloom-text);\\r\\n background: var(--noteloom-bg-subtle);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n}\\r\\n\\r\\n.be-comment-composer-textarea:focus {\\r\\n outline: none;\\r\\n border-color: var(--noteloom-accent);\\r\\n}\\r\\n\\r\\n.be-comment-composer-actions {\\r\\n display: flex;\\r\\n justify-content: flex-end;\\r\\n gap: 8px;\\r\\n}\\r\\n\\r\\n.be-comment-composer-cancel,\\r\\n.be-comment-composer-submit {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n border: none;\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 6px 12px;\\r\\n font-size: 0.8rem;\\r\\n font-weight: 600;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-comment-composer-cancel {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-comment-composer-submit {\\r\\n background: var(--noteloom-accent);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n.be-comment-composer-submit:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n}\\r\\n\\r\\n.be-comment-thread {\\r\\n font-size: 0.85rem;\\r\\n}\\r\\n\\r\\n.be-comment-thread + .be-comment-thread {\\r\\n margin-top: 16px;\\r\\n padding-top: 16px;\\r\\n border-top: 1px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n.be-comment-thread-resolved {\\r\\n opacity: 0.6;\\r\\n}\\r\\n\\r\\n/* Echoes a hover from the highlighted text back onto this card -- see useHoveredComment. */\\r\\n.be-comment-thread-hovered {\\r\\n background: var(--noteloom-bg-hover);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n margin: -6px;\\r\\n padding: 6px;\\r\\n}\\r\\n\\r\\n.be-comment-message {\\r\\n display: flex;\\r\\n align-items: flex-start;\\r\\n gap: 10px;\\r\\n}\\r\\n\\r\\n.be-comment-message + .be-comment-message {\\r\\n margin-top: 10px;\\r\\n}\\r\\n\\r\\n.be-comment-message-body {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n}\\r\\n\\r\\n.be-comment-message-header {\\r\\n display: flex;\\r\\n align-items: baseline;\\r\\n gap: 6px;\\r\\n}\\r\\n\\r\\n.be-comment-message-author {\\r\\n font-weight: 600;\\r\\n font-size: 0.78rem;\\r\\n}\\r\\n\\r\\n.be-comment-message-time {\\r\\n font-size: 0.72rem;\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-comment-message-text {\\r\\n margin: 3px 0 0;\\r\\n line-height: 1.45;\\r\\n white-space: pre-wrap;\\r\\n word-break: break-word;\\r\\n}\\r\\n\\r\\n/* Replies (every message after the thread's first) get a connecting\\r\\n vertical line + indent, chat-thread style -- our data model has no\\r\\n deeper nesting than \\\"root message + flat replies\\\", so one indent level\\r\\n is all this needs. */\\r\\n.be-comment-thread-replies {\\r\\n margin: 10px 0 0 13px;\\r\\n padding-left: 14px;\\r\\n border-left: 2px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n.be-comment-thread-actions {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n margin-top: 10px;\\r\\n opacity: 0;\\r\\n transition: opacity 0.1s ease;\\r\\n}\\r\\n\\r\\n.be-comment-thread:hover .be-comment-thread-actions,\\r\\n.be-comment-thread:focus-within .be-comment-thread-actions {\\r\\n opacity: 1;\\r\\n}\\r\\n\\r\\n.be-comment-thread-actions button {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-muted);\\r\\n font-size: 0.78rem;\\r\\n padding: 4px 8px;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-comment-thread-actions button:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-comment-thread-delete {\\r\\n margin-left: auto;\\r\\n}\\r\\n\\r\\n/* --- comments: click/hover popover over existing highlighted text --- */\\r\\n\\r\\n.be-comment-popover {\\r\\n z-index: 1000;\\r\\n width: 300px;\\r\\n max-width: calc(100vw - 24px);\\r\\n background: var(--noteloom-bg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-lg);\\r\\n padding: 12px 14px 14px;\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n}\\r\\n\\r\\n/* --- comments: opt-in right-side panel (NoteloomEditor showCommentsPanel) --- */\\r\\n\\r\\n/* Deliberately no border/shadow/box background here, or on\\r\\n .be-comments-panel-item below -- comments float directly on the page\\r\\n like margin notes, not a boxed widget, matching how most other editors'\\r\\n own comment sidebars read. */\\r\\n/* No overflow/scrolling of its own on purpose -- each card's position\\r\\n already tracks the PAGE's scroll (see CommentsPanel's recompute()), so\\r\\n the panel scrolling independently would fight that: a wheel gesture over\\r\\n it needs to fall through and scroll the page, not the panel's own box,\\r\\n or cards visually detach from the text they're anchored to. Cards whose\\r\\n anchor has scrolled off-screen just go negative/beyond the viewport and\\r\\n aren't painted -- no clipping box needed for that. */\\r\\n.be-comments-panel {\\r\\n position: fixed;\\r\\n top: 80px;\\r\\n right: 24px;\\r\\n width: 320px;\\r\\n overflow: visible;\\r\\n background: transparent;\\r\\n padding: 0 12px;\\r\\n font-size: 0.85rem;\\r\\n z-index: 500;\\r\\n pointer-events: none;\\r\\n}\\r\\n\\r\\n.be-comments-panel-item,\\r\\n.be-comments-panel-empty {\\r\\n pointer-events: auto;\\r\\n}\\r\\n\\r\\n.be-comments-panel-empty {\\r\\n color: var(--noteloom-text-muted);\\r\\n font-size: 0.82rem;\\r\\n margin: 0;\\r\\n}\\r\\n\\r\\n/* Each .be-comments-panel-item is absolutely positioned (top set inline by\\r\\n CommentsPanel, aligned with its thread's own anchored text, margin-comment\\r\\n style) inside this relatively-positioned container -- height is also set\\r\\n inline, sized to fit the lowest card. */\\r\\n.be-comments-panel-list {\\r\\n position: relative;\\r\\n}\\r\\n\\r\\n.be-comments-panel-item {\\r\\n position: absolute;\\r\\n left: 0;\\r\\n right: 0;\\r\\n padding: 8px 12px;\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n transition: top 0.15s ease, background-color 0.1s ease;\\r\\n}\\r\\n\\r\\n.be-comments-panel-item:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n@media (max-width: 900px) {\\r\\n .be-comments-panel {\\r\\n display: none;\\r\\n }\\r\\n}\\r\\n\\r\\n/* --- version history: trigger button + drawer (VersionHistory) --- */\\r\\n\\r\\n.be-version-history-trigger {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n border: 1px solid var(--noteloom-border);\\r\\n background: var(--noteloom-bg);\\r\\n color: var(--noteloom-text);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 5px 10px;\\r\\n font-size: 0.85rem;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-version-history-trigger:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-version-history-backdrop {\\r\\n position: fixed;\\r\\n inset: 0;\\r\\n background: rgba(15, 23, 42, 0.25);\\r\\n z-index: 1400;\\r\\n}\\r\\n\\r\\n.be-version-history-drawer {\\r\\n position: fixed;\\r\\n top: 0;\\r\\n right: 0;\\r\\n bottom: 0;\\r\\n width: 360px;\\r\\n max-width: 100vw;\\r\\n background: var(--noteloom-bg);\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n z-index: 1401;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n}\\r\\n\\r\\n.be-version-history-header {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n padding: 14px 16px;\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n font-weight: 700;\\r\\n font-size: 0.95rem;\\r\\n}\\r\\n\\r\\n.be-version-history-close {\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-muted);\\r\\n width: 24px;\\r\\n height: 24px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-version-history-close:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-version-history-list {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 8px 0;\\r\\n}\\r\\n\\r\\n.be-version-history-empty {\\r\\n color: var(--noteloom-text-muted);\\r\\n font-size: 0.85rem;\\r\\n padding: 16px;\\r\\n margin: 0;\\r\\n}\\r\\n\\r\\n.be-version-history-group-label {\\r\\n font-weight: 600;\\r\\n font-size: 0.78rem;\\r\\n color: var(--noteloom-text-muted);\\r\\n padding: 10px 16px 4px;\\r\\n}\\r\\n\\r\\n.be-version-history-item {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n width: 100%;\\r\\n border: none;\\r\\n background: transparent;\\r\\n padding: 8px 16px;\\r\\n text-align: left;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-version-history-item:hover {\\r\\n background: var(--noteloom-bg-hover);\\r\\n}\\r\\n\\r\\n.be-version-history-item-body {\\r\\n min-width: 0;\\r\\n}\\r\\n\\r\\n.be-version-history-item-author {\\r\\n font-weight: 600;\\r\\n font-size: 0.85rem;\\r\\n}\\r\\n\\r\\n.be-version-history-item-meta {\\r\\n font-size: 0.78rem;\\r\\n color: var(--noteloom-text-muted);\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n}\\r\\n\\r\\n.be-version-history-preview {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n min-height: 0;\\r\\n}\\r\\n\\r\\n.be-version-history-preview-meta {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n padding: 12px 16px;\\r\\n border-bottom: 1px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n.be-version-history-preview-author {\\r\\n font-weight: 600;\\r\\n font-size: 0.85rem;\\r\\n}\\r\\n\\r\\n.be-version-history-preview-time {\\r\\n font-size: 0.78rem;\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-version-history-view-toggle {\\r\\n display: flex;\\r\\n gap: 4px;\\r\\n padding: 8px 16px 0;\\r\\n}\\r\\n\\r\\n.be-version-history-view-toggle button {\\r\\n border: none;\\r\\n background: transparent;\\r\\n color: var(--noteloom-text-muted);\\r\\n font-size: 0.78rem;\\r\\n font-weight: 600;\\r\\n padding: 5px 10px;\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-version-history-view-toggle button.is-active {\\r\\n background: var(--noteloom-bg-subtle);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-version-history-diff-legend {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n padding: 10px 16px 0;\\r\\n font-size: 0.75rem;\\r\\n}\\r\\n\\r\\n.be-version-history-diff-legend-note {\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-version-history-preview-body {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 16px;\\r\\n font-size: 0.9rem;\\r\\n line-height: 1.6;\\r\\n}\\r\\n\\r\\n.be-version-history-diff-body :is(p.be-version-diff-block) {\\r\\n margin: 0 0 0.6em;\\r\\n}\\r\\n\\r\\n/* Google Docs-style change highlighting: additions get a green underline/background,\\r\\n removals a struck-through red one -- self-evident at a glance, no legend required\\r\\n to understand the individual spans (the legend row above just labels the colors). */\\r\\n.be-version-diff-added {\\r\\n background: rgba(34, 197, 94, 0.18);\\r\\n color: var(--noteloom-text);\\r\\n text-decoration: underline;\\r\\n text-decoration-color: rgba(34, 197, 94, 0.6);\\r\\n border-radius: 2px;\\r\\n padding: 0 1px;\\r\\n}\\r\\n\\r\\n.be-version-diff-removed {\\r\\n background: rgba(239, 68, 68, 0.14);\\r\\n color: var(--noteloom-text-muted);\\r\\n text-decoration: line-through;\\r\\n text-decoration-color: rgba(239, 68, 68, 0.6);\\r\\n border-radius: 2px;\\r\\n padding: 0 1px;\\r\\n}\\r\\n\\r\\n.be-version-history-diff-legend .be-version-diff-added,\\r\\n.be-version-history-diff-legend .be-version-diff-removed {\\r\\n padding: 2px 6px;\\r\\n text-decoration: none;\\r\\n font-weight: 600;\\r\\n}\\r\\n\\r\\n/* exportDocumentHTML emits plain semantic HTML (<p>/<h1-3>/<ul>/<blockquote>/...),\\r\\n not this package's own be-* block classes, so the preview needs its own\\r\\n basic typography rather than inheriting the live editor's block styling. */\\r\\n.be-version-history-preview-body :is(h1, h2, h3) {\\r\\n margin: 0.6em 0 0.3em;\\r\\n}\\r\\n\\r\\n.be-version-history-preview-body p {\\r\\n margin: 0 0 0.6em;\\r\\n}\\r\\n\\r\\n.be-version-history-preview-body :is(ul, ol) {\\r\\n margin: 0 0 0.6em;\\r\\n padding-left: 1.4em;\\r\\n}\\r\\n\\r\\n.be-version-history-preview-body blockquote {\\r\\n margin: 0 0 0.6em;\\r\\n padding-left: 0.8em;\\r\\n border-left: 3px solid var(--noteloom-border);\\r\\n color: var(--noteloom-text-muted);\\r\\n}\\r\\n\\r\\n.be-version-history-preview-body pre {\\r\\n background: var(--noteloom-bg-subtle);\\r\\n border-radius: var(--noteloom-radius-sm);\\r\\n padding: 10px;\\r\\n overflow-x: auto;\\r\\n}\\r\\n\\r\\n.be-version-history-preview-actions {\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n align-items: center;\\r\\n gap: 8px;\\r\\n padding: 12px 16px;\\r\\n border-top: 1px solid var(--noteloom-border);\\r\\n}\\r\\n\\r\\n.be-version-history-preview-actions button {\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 6px 12px;\\r\\n font-size: 0.82rem;\\r\\n font-weight: 600;\\r\\n cursor: pointer;\\r\\n}\\r\\n\\r\\n.be-version-history-preview-actions button:first-child {\\r\\n border: 1px solid var(--noteloom-border);\\r\\n background: var(--noteloom-bg);\\r\\n color: var(--noteloom-text);\\r\\n}\\r\\n\\r\\n.be-version-history-restore {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n border: none;\\r\\n background: var(--noteloom-accent);\\r\\n color: #fff;\\r\\n}\\r\\n\\r\\n/* --- voice typing: caret-anchored listening/processing indicator --- */\\r\\n\\r\\n.be-voice-indicator {\\r\\n z-index: 1000;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 5px;\\r\\n background: var(--noteloom-bg);\\r\\n border: 1px solid var(--noteloom-border);\\r\\n border-radius: var(--noteloom-radius-md);\\r\\n padding: 4px 9px;\\r\\n box-shadow: var(--noteloom-shadow);\\r\\n font-size: 0.78rem;\\r\\n color: var(--noteloom-text-muted);\\r\\n white-space: nowrap;\\r\\n pointer-events: none;\\r\\n animation: be-voice-indicator-in 0.12s ease-out;\\r\\n}\\r\\n\\r\\n@keyframes be-voice-indicator-in {\\r\\n from {\\r\\n opacity: 0;\\r\\n transform: translate(-50%, calc(-100% + 4px));\\r\\n }\\r\\n to {\\r\\n opacity: 1;\\r\\n transform: translate(-50%, -100%);\\r\\n }\\r\\n}\\r\\n\\r\\n.be-voice-indicator-dot {\\r\\n width: 7px;\\r\\n height: 7px;\\r\\n border-radius: 50%;\\r\\n background: var(--noteloom-danger, #dc2626);\\r\\n flex: none;\\r\\n animation: be-voice-indicator-pulse 1.4s ease-in-out infinite;\\r\\n}\\r\\n\\r\\n.be-voice-indicator-processing .be-voice-indicator-dot {\\r\\n background: var(--noteloom-accent);\\r\\n animation-duration: 0.6s;\\r\\n}\\r\\n\\r\\n@keyframes be-voice-indicator-pulse {\\r\\n 0%,\\r\\n 100% {\\r\\n opacity: 1;\\r\\n box-shadow: 0 0 0 0 currentColor;\\r\\n }\\r\\n 50% {\\r\\n opacity: 0.5;\\r\\n box-shadow: 0 0 0 4px transparent;\\r\\n }\\r\\n}\\r\\n\\r\\n/* --- print --- */\\r\\n/*\\r\\n * Printing (or \\\"Save as PDF\\\" via the browser's own print dialog — this\\r\\n * package deliberately doesn't bundle a PDF-generation library, which\\r\\n * would conflict with staying zero-runtime-dependency) always renders a\\r\\n * clean, chrome-free document: every piece of editing-only UI is hidden\\r\\n * here, regardless of whether the app happens to be in preview mode at\\r\\n * the moment of printing. `.be-block-row-hidden` is included on purpose —\\r\\n * a block hidden via \\\"Hide in preview\\\" stays in the DOM (just dimmed) in\\r\\n * edit mode, so without this rule printing while NOT toggled into preview\\r\\n * mode would print blocks the user explicitly marked as hidden. A host\\r\\n * app's own outer chrome (nav bars, its own toolbar) needs its own print\\r\\n * rules the same way — see examples/basic's own style.css for a worked\\r\\n * example, since that chrome lives outside this package entirely.\\r\\n */\\r\\n@media print {\\r\\n .be-block-gutter,\\r\\n .be-block-gutter-menu,\\r\\n .be-block-gutter-menu-item,\\r\\n .be-block-range-menu,\\r\\n .be-block-range-menu-item,\\r\\n .be-block-row-hidden,\\r\\n .be-slash-menu,\\r\\n #be-emoji-menu,\\r\\n #be-at-menu,\\r\\n .be-floating-toolbar,\\r\\n .be-link-hover-card,\\r\\n .be-comment-popover,\\r\\n .be-comments-panel,\\r\\n .be-voice-indicator,\\r\\n .be-table-header-menu-trigger,\\r\\n .be-table-header-menu,\\r\\n .be-table-col-resize-handle,\\r\\n .be-table-delete-row,\\r\\n .be-table-add-row,\\r\\n .be-embed-toolbar,\\r\\n .be-embed-remove,\\r\\n .be-embed-resize-handle,\\r\\n .be-embed-dropzone,\\r\\n .be-embed-upload-btn,\\r\\n .be-embed-url-row,\\r\\n .be-canvas-toolbar,\\r\\n .be-canvas-resize-handle,\\r\\n .be-callout-color-wrap,\\r\\n .be-modal-overlay,\\r\\n .be-mobile-action-bar,\\r\\n .be-mobile-picker-list,\\r\\n .be-export-trigger,\\r\\n .be-export-tabs,\\r\\n .be-trailing-space,\\r\\n .be-select-popover {\\r\\n display: none !important;\\r\\n }\\r\\n\\r\\n /* .be-block-row-range-selected and .be-block-selected mark real content\\r\\n (the row/block itself, not a standalone chrome element) with a\\r\\n highlight background/outline — reset just that styling rather than\\r\\n hiding the element the way the chrome above is hidden, or printing\\r\\n mid-drag-selection would print blank space instead of the block's own\\r\\n content. */\\r\\n .be-block-row-range-selected {\\r\\n background: none !important;\\r\\n }\\r\\n\\r\\n .be-block-selected {\\r\\n outline: none !important;\\r\\n }\\r\\n\\r\\n /* No background colors/shadows on paper, and text that's always legible\\r\\n regardless of the screen theme the page happened to be rendered in\\r\\n (dark mode's near-white text would otherwise print as barely-there). */\\r\\n .be-editable,\\r\\n .be-paragraph,\\r\\n .be-heading,\\r\\n .be-list-item,\\r\\n .be-blockquote,\\r\\n .be-code-block,\\r\\n .be-callout,\\r\\n .be-table-cell {\\r\\n background: none !important;\\r\\n box-shadow: none !important;\\r\\n color: #000 !important;\\r\\n }\\r\\n\\r\\n /* Don't split a table/code block/callout/image awkwardly across a page\\r\\n boundary when it would otherwise fit on one page. */\\r\\n .be-table,\\r\\n .be-code-block,\\r\\n .be-callout,\\r\\n .be-embed-image {\\r\\n break-inside: avoid;\\r\\n }\\r\\n}\\r\\n\"","import defaultThemeCSS from '../style.css?raw';\n\n// Vite's `?raw` suffix resolves this at build time to the file's contents\n// as a plain string — no CSS-loader/runtime dependency involved, so this\n// stays true to \"zero runtime dependencies\" even though the theme itself\n// is authored as a .css file. Both the ESM and CJS library builds embed\n// the string directly; nothing is fetched or resolved at runtime.\nconst STYLE_TAG_ID = 'noteloom-default-styles';\n\n/**\n * Inserts the default theme as a single <style> tag in <head>, once —\n * idempotent (checked by id) so mounting more than one <EditorProvider>,\n * or re-mounting one, never duplicates it. Called from EditorProvider's\n * own effect; see its `theme` prop to opt out entirely.\n */\nexport function injectDefaultStyles() {\n if (typeof document === 'undefined') return; // SSR guard — inject on the client only\n if (document.getElementById(STYLE_TAG_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_TAG_ID;\n style.textContent = defaultThemeCSS;\n document.head.appendChild(style);\n}\n","import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';\r\nimport { injectDefaultStyles } from './injectDefaultStyles.js';\r\n\r\nconst EditorContext = createContext(null);\r\n\r\n/**\r\n * `theme` (default `'default'`) auto-injects the package's own default\r\n * theme as a single <style> tag in <head> the first time any\r\n * <EditorProvider> mounts — see injectDefaultStyles.js — so a working,\r\n * styled editor needs no separate `import 'noteloom/style.css'` line.\r\n * Pass `theme=\"none\"` to skip this entirely (e.g. to import the CSS file\r\n * yourself for load-order control, or to ship a fully custom theme with\r\n * no default as a starting point).\r\n *\r\n * `className`/`style`, if given, wrap `children` in one `<div>` (with the\r\n * base `be-root` class alongside your own) — the natural \"editor root\"\r\n * customization hook for scoping your own overrides\r\n * (`.my-editor .be-paragraph { ... }`) or overriding the `--noteloom-*`\r\n * CSS custom properties the default theme itself reads from (see\r\n * style.css) for just this one editor instance. Deliberately NOT rendered\r\n * unconditionally: most existing usage doesn't need an extra wrapper\r\n * element in the DOM, so one is only added when you actually ask for it.\r\n *\r\n * `getBlockClassName(block)`, if given, is the \"internal\" counterpart —\r\n * every block component appends whatever string this returns onto its own\r\n * root element's class list (see useBlockClassName), so individual blocks\r\n * (by type, id, or props — the whole block object is passed in) can be\r\n * customized too, not just the editor's outer wrapper.\r\n */\r\nexport function EditorProvider({\r\n store,\r\n registry,\r\n inlineRegistry = null,\r\n history = null,\r\n className,\r\n style,\r\n theme = 'default',\r\n getBlockClassName,\r\n commentAuthorId,\r\n children,\r\n}) {\r\n useEffect(() => {\r\n if (theme !== 'none') injectDefaultStyles();\r\n }, [theme]);\r\n\r\n // `store` may be a plain EditorStore or a History instance (same read/write\r\n // surface) — components call useEditorStore() and get whichever was given,\r\n // undo/redo-aware or not, without caring which.\r\n //\r\n // isWholeDocumentSelected is ephemeral UI interaction state, not document\r\n // data — deliberately plain useState here, not part of the store. It's\r\n // the \"select everything\" flag a second Ctrl+A press sets (see\r\n // useEditorKeyboardShortcuts + useWholeDocumentSelection): every block\r\n // lives in its own separate contentEditable region, and browsers don't\r\n // reliably support a native Selection/Range spanning multiple independent\r\n // contentEditable islands constructed via script — so cross-block \"select\r\n // all\" is its own custom selection model instead of a native one, the\r\n // same way a block editor's whole-block selection isn't native browser text\r\n // selection either. This package ships no default styling, so rendering\r\n // the corresponding highlight is left to the host app (see this hook's\r\n // own doc comment).\r\n const [isWholeDocumentSelected, setIsWholeDocumentSelected] = useState(false);\r\n\r\n // Which comment thread (by id) is currently hovered, wherever that\r\n // happened -- the highlighted text in the editor, or a thread's card in\r\n // the panel -- so the OTHER side can echo the same emphasis. Plain\r\n // useState is fine: hover changes are infrequent relative to typing.\r\n const [hoveredCommentId, setHoveredCommentId] = useState(null);\r\n\r\n // A contiguous run of top-level block ids selected by dragging from the\r\n // gutter margin (see useBlockRangeDrag/BlockGutterRow) — the familiar \"drag\r\n // in the margin to select several blocks\" gesture. `[]` means nothing is\r\n // range-selected. Kept in DOCUMENT order (matches root.contentIds), not\r\n // drag order, so Move up/down and Delete don't need to re-sort it.\r\n // Ephemeral UI state, same rationale as isWholeDocumentSelected above —\r\n // this is a *different* selection mechanism from that one (an arbitrary\r\n // contiguous slice vs. literally everything), so they're independent,\r\n // non-overlapping bits of state.\r\n const [selectedBlockRange, setSelectedBlockRange] = useState([]);\r\n\r\n // Preview-mode toggle — also ephemeral UI state, not document data (a\r\n // reload always starts back in edit mode). While true, BlockChildren\r\n // skips rendering the per-block gutter entirely and omits any block\r\n // whose own props.hidden is true, instead of rendering it dimmed the way\r\n // edit mode does (see BlockGutterRow's Hide/Show menu item) — the whole\r\n // point of \"hidden\" is that it disappears from the preview a reader\r\n // eventually sees, while staying editable (just visually dimmed) for\r\n // whoever's still writing it.\r\n const [isPreviewMode, setIsPreviewMode] = useState(false);\r\n\r\n // Ephemeral \"which custom field type is the create/edit modal open for\"\r\n // state — null (closed), the string 'new' (create flow), or an existing\r\n // fieldTypes id (edit flow). See useFieldTypeEditor + FieldTypeEditorModal\r\n // (inlineTypes/customSelect): kept here, not in that module, so this core\r\n // file never has to import anything from a concrete inline type — the\r\n // modal itself is host-mounted (same pattern as EditorTrailingSpace),\r\n // reading this shared open/closed target via the hook below.\r\n const [fieldTypeEditorTarget, setFieldTypeEditorTarget] = useState(null);\r\n const openCreateFieldType = useCallback(() => setFieldTypeEditorTarget('new'), []);\r\n const openEditFieldType = useCallback((id) => setFieldTypeEditorTarget(id), []);\r\n const closeFieldTypeEditor = useCallback(() => setFieldTypeEditorTarget(null), []);\r\n\r\n // A single non-editable/contentless block (image, divider, etc.) that's\r\n // \"selected\" pending a second Backspace/Delete to actually remove it —\r\n // a common convention for atomic nodes: the first press\r\n // adjacent to one just highlights it, the second one deletes it.\r\n //\r\n // Deliberately NOT React state: this can be set on every single\r\n // Backspace/Delete press throughout ordinary typing near a non-editable\r\n // block, and putting it in the same memoized context value as\r\n // store/registry/etc. would re-render every block in the whole document\r\n // on every such press (unlike isWholeDocumentSelected above, which only\r\n // ever changes on a deliberate, rare \"select everything\" action). A\r\n // plain ref plus a stable setter that imperatively toggles a DOM class\r\n // avoids that entirely — the same imperative-DOM-update discipline\r\n // EditableBlockContent already uses for its own host nodes.\r\n const selectedBlockIdRef = useRef(null);\r\n\r\n const getSelectedBlockId = useCallback(() => selectedBlockIdRef.current, []);\r\n\r\n const setSelectedBlockId = useCallback((id) => {\r\n const prevId = selectedBlockIdRef.current;\r\n if (prevId === id) return;\r\n if (prevId) document.querySelector(`[data-block-id=\"${prevId}\"]`)?.classList.remove('be-block-selected');\r\n selectedBlockIdRef.current = id;\r\n if (id) document.querySelector(`[data-block-id=\"${id}\"]`)?.classList.add('be-block-selected');\r\n }, []);\r\n\r\n const value = useMemo(\r\n () => ({\r\n store,\r\n registry,\r\n inlineRegistry,\r\n history,\r\n isWholeDocumentSelected,\r\n setIsWholeDocumentSelected,\r\n selectedBlockRange,\r\n setSelectedBlockRange,\r\n getSelectedBlockId,\r\n setSelectedBlockId,\r\n isPreviewMode,\r\n setIsPreviewMode,\r\n fieldTypeEditorTarget,\r\n openCreateFieldType,\r\n openEditFieldType,\r\n closeFieldTypeEditor,\r\n getBlockClassName,\r\n commentAuthorId,\r\n hoveredCommentId,\r\n setHoveredCommentId,\r\n }),\r\n [\r\n store,\r\n registry,\r\n inlineRegistry,\r\n history,\r\n isWholeDocumentSelected,\r\n selectedBlockRange,\r\n getSelectedBlockId,\r\n setSelectedBlockId,\r\n isPreviewMode,\r\n fieldTypeEditorTarget,\r\n openCreateFieldType,\r\n openEditFieldType,\r\n closeFieldTypeEditor,\r\n getBlockClassName,\r\n commentAuthorId,\r\n hoveredCommentId,\r\n ],\r\n );\r\n const content =\r\n className || style ? (\r\n <div className={className ? `be-root ${className}` : 'be-root'} style={style}>\r\n {children}\r\n </div>\r\n ) : (\r\n children\r\n );\r\n\r\n return <EditorContext.Provider value={value}>{content}</EditorContext.Provider>;\r\n}\r\n\r\nexport function useEditorContext() {\r\n const ctx = useContext(EditorContext);\r\n if (!ctx) {\r\n throw new Error('Editor hooks must be used within an <EditorProvider>');\r\n }\r\n return ctx;\r\n}\r\n\r\nexport function useEditorStore() {\r\n return useEditorContext().store;\r\n}\r\n\r\nexport function useBlockRegistry() {\r\n return useEditorContext().registry;\r\n}\r\n\r\nexport function useInlineRegistry() {\r\n return useEditorContext().inlineRegistry;\r\n}\r\n\r\n/**\r\n * `[isWholeDocumentSelected, setIsWholeDocumentSelected]` — the custom\r\n * \"select all\" state (see EditorProvider's doc comment for why this isn't\r\n * a native Selection). A host app renders the highlight itself, typically\r\n * by conditionally adding a class to its surface element and styling\r\n * `.that-class > [data-block-id]` — every top-level block is a direct DOM\r\n * child of whatever rendered `<BlockChildren parentId={rootId} />`, so a\r\n * plain CSS child-combinator is enough; no wrapper markup is needed.\r\n */\r\nexport function useWholeDocumentSelection() {\r\n const { isWholeDocumentSelected, setIsWholeDocumentSelected } = useEditorContext();\r\n return [isWholeDocumentSelected, setIsWholeDocumentSelected];\r\n}\r\n\r\n/**\r\n * `[selectedBlockRange, setSelectedBlockRange]` — the drag-selected\r\n * contiguous run of top-level block ids (see EditorProvider's doc comment).\r\n * `setSelectedBlockRange([])` clears it. A host app renders the highlight\r\n * itself (see be-block-row-range-selected in the example app's CSS) and\r\n * mounts `<BlockRangeActionMenu />` once anywhere under the provider to get\r\n * the Copy/Cut/Delete/Move/Hide action menu that appears once a drag\r\n * finishes — see useBlockRangeDrag for the drag mechanics themselves.\r\n */\r\nexport function useBlockRangeSelection() {\r\n const { selectedBlockRange, setSelectedBlockRange } = useEditorContext();\r\n return [selectedBlockRange, setSelectedBlockRange];\r\n}\r\n\r\n/**\r\n * `{ getSelectedBlockId, setSelectedBlockId }` — the single-block\r\n * \"selected, pending a second Backspace/Delete to remove it\" state (see\r\n * EditorProvider's doc comment on selectedBlockIdRef for why this is a\r\n * ref-backed pair of stable functions rather than React state: reading it\r\n * inside an event handler via `getSelectedBlockId()` always returns the\r\n * current value without subscribing to it, so setting it doesn't\r\n * re-render every block in the document). `setSelectedBlockId` also\r\n * imperatively toggles the `be-block-selected` CSS class on the relevant\r\n * block's own `[data-block-id]` element; a host app can restyle that\r\n * class however it likes (e.g. a highlighted border).\r\n */\r\nexport function useSelectedBlock() {\r\n const { getSelectedBlockId, setSelectedBlockId } = useEditorContext();\r\n return { getSelectedBlockId, setSelectedBlockId };\r\n}\r\n\r\n/**\r\n * `[isPreviewMode, setIsPreviewMode]` — toggles the whole editor between\r\n * edit mode (every block renders normally, hidden ones dimmed via\r\n * BlockGutterRow's own styling) and preview mode (BlockChildren renders\r\n * without the per-block gutter at all, and skips any block whose\r\n * `props.hidden` is true entirely — see BlockChildren's doc comment). A\r\n * host app wires its own toggle button/keyboard shortcut to this, same as\r\n * useWholeDocumentSelection.\r\n */\r\nexport function usePreviewMode() {\r\n const { isPreviewMode, setIsPreviewMode } = useEditorContext();\r\n return [isPreviewMode, setIsPreviewMode];\r\n}\r\n\r\n/**\r\n * `{ target, openCreate, openEdit, close }` — shared open/closed state for\r\n * the custom field type create/edit modal (see\r\n * inlineTypes/customSelect/FieldTypeEditorModal.jsx). `target` is `null`\r\n * when closed, `'new'` while creating, or an existing fieldTypes id while\r\n * editing one. A host app renders `<FieldTypeEditorModal />` once anywhere\r\n * under the provider (it reads this hook itself) and wires its own \"+ New\r\n * field type\" button to `openCreate()`; a field type's own chips call\r\n * `openEdit(id)` from their \"Manage options…\" popover entry (see\r\n * createSelectFieldType's `onManage`).\r\n */\r\n/**\r\n * Combines a block type's own fixed base class (e.g. \"be-paragraph\") with\r\n * whatever extra class name the host app's `getBlockClassName` prop (on\r\n * EditorProvider) returns for this specific block — the \"internal\"\r\n * customization hook, complementing EditorProvider's own `className`/\r\n * `style` props (which only style the editor's root wrapper). Every block\r\n * component calls this once for its own root element, passing its own base\r\n * class and its `block` (as returned by useBlock — may be null on the\r\n * render right before a block unmounts, handled gracefully here).\r\n *\r\n * `getBlockClassName(block)` receives the full block object (`type`, `id`,\r\n * `props`, ...), so a host can target specific types, specific ids, or\r\n * inspect props (e.g. give every `callout` with `props.color === 'red'` an\r\n * extra class) — as fine- or coarse-grained as the callback wants.\r\n */\r\nexport function useBlockClassName(baseClassName, block) {\r\n const { getBlockClassName } = useEditorContext();\r\n const extra = block && getBlockClassName ? getBlockClassName(block) : undefined;\r\n return extra ? `${baseClassName} ${extra}` : baseClassName;\r\n}\r\n\r\n/**\r\n * The current user's id for AUTHORING comments through the package's own\r\n * built-in UI (CommentPopover's reply composer, CommentsPanel) — see\r\n * NoteloomEditor's `commentAuthorId` prop. `undefined` when not configured,\r\n * in which case those surfaces still show existing threads (view/resolve/\r\n * delete need no identity) but hide the reply composer, since there's no\r\n * author to attribute a new message to.\r\n */\r\nexport function useCommentAuthorId() {\r\n return useEditorContext().commentAuthorId;\r\n}\r\n\r\n/** `[hoveredCommentId, setHoveredCommentId]` -- lets a hover in the editor's highlighted text and a hover over a thread card in the panel echo each other, same idea as useWholeDocumentSelection. */\r\nexport function useHoveredComment() {\r\n const { hoveredCommentId, setHoveredCommentId } = useEditorContext();\r\n return [hoveredCommentId, setHoveredCommentId];\r\n}\r\n\r\nexport function useFieldTypeEditor() {\r\n const { fieldTypeEditorTarget, openCreateFieldType, openEditFieldType, closeFieldTypeEditor } = useEditorContext();\r\n return {\r\n target: fieldTypeEditorTarget,\r\n openCreate: openCreateFieldType,\r\n openEdit: openEditFieldType,\r\n close: closeFieldTypeEditor,\r\n };\r\n}\r\n","// Same five colors FloatingToolbar's own text-color picker already offers\n// (see TEXT_COLORS in FloatingToolbar.jsx) — reused here rather than a new\n// palette, so an author's avatar color and any text color a user might pick\n// come from the same small, already-approved set.\nconst AVATAR_COLORS = ['#e03131', '#e8590c', '#2f9e44', '#1971c2', '#9c36b5'];\n\n/**\n * Deterministically picks one of AVATAR_COLORS for `authorId` — this\n * package has no identity system of its own (no profile pictures, no\n * stored user records), so every avatar is generated from the id/name\n * string alone, and needs to land on the SAME color every time for the\n * same author without any lookup.\n */\nexport function getAvatarColor(authorId) {\n let hash = 0;\n const str = String(authorId ?? '');\n for (let i = 0; i < str.length; i += 1) hash = (hash * 31 + str.charCodeAt(i)) | 0;\n return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length];\n}\n\n/** \"Bailey Chen\" -> \"BC\", \"alice\" -> \"AL\", \"\" -> \"?\". */\nexport function getInitials(authorId) {\n const str = String(authorId ?? '').trim();\n if (!str) return '?';\n const parts = str.split(/\\s+/).filter(Boolean);\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();\n return str.slice(0, 2).toUpperCase();\n}\n\nconst MINUTE_MS = 60 * 1000;\nconst HOUR_MS = 60 * MINUTE_MS;\nconst DAY_MS = 24 * HOUR_MS;\n\n/**\n * \"just now\" / \"5 min ago\" / \"3 hours ago\" / \"2 days ago\", falling back to\n * a plain locale date beyond a week — a display-only nicety computed fresh\n * on each render; `CommentMessage.createdAt` itself stays a plain epoch-ms\n * number everywhere else (storage, collab envelopes, exports).\n */\nexport function formatRelativeTime(timestamp, now = Date.now()) {\n const diff = now - timestamp;\n if (diff < MINUTE_MS) return 'just now';\n if (diff < HOUR_MS) {\n const m = Math.floor(diff / MINUTE_MS);\n return `${m} min${m === 1 ? '' : 's'} ago`;\n }\n if (diff < DAY_MS) {\n const h = Math.floor(diff / HOUR_MS);\n return `${h} hour${h === 1 ? '' : 's'} ago`;\n }\n if (diff < 7 * DAY_MS) {\n const d = Math.floor(diff / DAY_MS);\n return `${d} day${d === 1 ? '' : 's'} ago`;\n }\n return new Date(timestamp).toLocaleDateString();\n}\n","import { getAvatarColor, getInitials } from './commentFormatting.js';\n\n/**\n * A small colored circle with the author's initials — this package has no\n * profile-picture/identity concept at all (see EditorProvider's\n * `commentAuthorId`), so every avatar is generated purely from the author\n * id/name string rather than a real image, the same \"no identity, just an\n * id string\" stance `authorId` already takes everywhere else in comments.\n */\nexport function CommentAvatar({ authorId, size = 26 }) {\n return (\n <span\n className=\"be-comment-avatar\"\n style={{ width: size, height: size, fontSize: Math.max(10, size * 0.4), background: getAvatarColor(authorId) }}\n aria-hidden=\"true\"\n >\n {getInitials(authorId)}\n </span>\n );\n}\n","/**\r\n * One shared icon family for every interactive control across the editor —\r\n * outline style (24x24 viewBox, 2px stroke, no fill, round caps/joins,\r\n * matching the common Feather/Lucide convention) so every icon inherits its\r\n * color from surrounding text via stroke=\"currentColor\" and scales via the\r\n * `size` prop, instead of the previously ad-hoc mix of unicode characters\r\n * (▸ ▾ × 📎 +) and single-letter text labels (B/I/U/S) each block used to\r\n * render on its own.\r\n */\r\nfunction Icon({ children, size = 16, strokeWidth = 2, ...rest }) {\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n aria-hidden=\"true\"\r\n focusable=\"false\"\r\n {...rest}\r\n >\r\n {children}\r\n </svg>\r\n );\r\n}\r\n\r\nexport function ChevronRightIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <polyline points=\"9 18 15 12 9 6\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ChevronDownIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <polyline points=\"6 9 12 15 18 9\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function XIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function MoreHorizontalIcon(props) {\r\n return (\r\n <Icon {...props} fill=\"currentColor\" stroke=\"none\">\r\n <circle cx=\"5\" cy=\"12\" r=\"1.6\" />\r\n <circle cx=\"12\" cy=\"12\" r=\"1.6\" />\r\n <circle cx=\"19\" cy=\"12\" r=\"1.6\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function PaperclipIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function PlusIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\r\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function BoldIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\" />\r\n <path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ItalicIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\" />\r\n <line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\" />\r\n <line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function UnderlineIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M6 3v7a6 6 0 0 0 12 0V3\" />\r\n <line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function PencilIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M12 20h9\" />\r\n <path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\" />\r\n </Icon>\r\n );\r\n}\r\n\r\n/** A freehand squiggle — the \"Canvas\" slash-command icon, distinct from PencilIcon (used elsewhere for text/link editing) since this represents drawing, not editing text. */\r\nexport function ScribbleIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M3 17c2-4 4-4 6 0s4 4 6 0 4-4 6 0\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function LinkIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\r\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function CommentIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" />\r\n </Icon>\r\n );\r\n}\r\n\r\n/** A clock with a counter-clockwise arrow around it -- \"version history\", same glyph most other editors use for it. */\r\nexport function ClockHistoryIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M3 12a9 9 0 1 0 3-6.7\" />\r\n <polyline points=\"3 5 3 10 8 10\" />\r\n <polyline points=\"12 7 12 12 16 14\" />\r\n </Icon>\r\n );\r\n}\r\n\r\n/** A plain counter-clockwise circular arrow -- \"restore this version\". */\r\nexport function RestoreIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M3 12a9 9 0 1 0 2.6-6.3\" />\r\n <polyline points=\"3 4 3 9 8 9\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function CheckIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <polyline points=\"20 6 9 17 4 12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function SendIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\r\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function StrikethroughIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M16 4H9a3 3 0 0 0-2.83 4\" />\r\n <path d=\"M14 12a4 4 0 0 1 0 8H6\" />\r\n <line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function AlignLeftIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\" />\r\n <line x1=\"17\" y1=\"10\" x2=\"3\" y2=\"10\" />\r\n <line x1=\"21\" y1=\"14\" x2=\"3\" y2=\"14\" />\r\n <line x1=\"17\" y1=\"18\" x2=\"3\" y2=\"18\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function AlignCenterIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\" />\r\n <line x1=\"18\" y1=\"10\" x2=\"6\" y2=\"10\" />\r\n <line x1=\"21\" y1=\"14\" x2=\"3\" y2=\"14\" />\r\n <line x1=\"18\" y1=\"18\" x2=\"6\" y2=\"18\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function AlignRightIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\" />\r\n <line x1=\"21\" y1=\"10\" x2=\"7\" y2=\"10\" />\r\n <line x1=\"21\" y1=\"14\" x2=\"3\" y2=\"14\" />\r\n <line x1=\"21\" y1=\"18\" x2=\"7\" y2=\"18\" />\r\n </Icon>\r\n );\r\n}\r\n\r\n// A 2x3 grid of solid dots (drag-handle convention) — unlike every other\r\n// icon here, these are filled, not stroked outlines: a 1px-radius circle\r\n// with only a stroke renders as a barely-visible ring at this size, so each\r\n// dot overrides the shared Icon wrapper's fill=\"none\"/stroke defaults\r\n// directly rather than inheriting them.\r\nexport function GripVerticalIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n {[5, 12, 19].flatMap((cy) =>\r\n [9, 15].map((cx) => <circle key={`${cx}-${cy}`} cx={cx} cy={cy} r=\"1.3\" fill=\"currentColor\" stroke=\"none\" />),\r\n )}\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function TrashIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <polyline points=\"3 6 5 6 21 6\" />\r\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\r\n <line x1=\"10\" y1=\"11\" x2=\"10\" y2=\"17\" />\r\n <line x1=\"14\" y1=\"11\" x2=\"14\" y2=\"17\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function CopyIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"9\" y=\"9\" width=\"12\" height=\"12\" rx=\"2\" />\r\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ArrowUpIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"5\" />\r\n <polyline points=\"5 12 12 5 19 12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ArrowDownIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\r\n <polyline points=\"19 12 12 19 5 12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function SquareIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function CircleIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ArrowDiagonalIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"6\" y1=\"18\" x2=\"18\" y2=\"6\" />\r\n <polyline points=\"9 6 18 6 18 15\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function DiamondIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <polygon points=\"12 3 21 12 12 21 3 12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function TriangleIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <polygon points=\"12 4 20 20 4 20\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function StarIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <polygon points=\"12 3 14.7 9.4 21.5 9.9 16.3 14.4 17.9 21 12 17.4 6.1 21 7.7 14.4 2.5 9.9 9.3 9.4\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function CursorIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M5 3l14 8-6 2-2 6-6-16z\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function EraserIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M19 20H9l-6-6a1.5 1.5 0 0 1 0-2l9-9a1.5 1.5 0 0 1 2 0l7 7a1.5 1.5 0 0 1 0 2l-7 7\" />\r\n <path d=\"M6.5 12.5 13 19\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function DownloadIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M12 3v12\" />\r\n <path d=\"M7 10l5 5 5-5\" />\r\n <path d=\"M4 19h16\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function MagnetIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M6 15V9a6 6 0 0 1 12 0v6\" />\r\n <path d=\"M6 15a3 3 0 0 0 6 0v-4\" />\r\n <path d=\"M18 15a3 3 0 0 1-6 0v-4\" />\r\n <line x1=\"3\" y1=\"9\" x2=\"6\" y2=\"9\" />\r\n <line x1=\"3\" y1=\"15\" x2=\"6\" y2=\"15\" />\r\n <line x1=\"18\" y1=\"9\" x2=\"21\" y2=\"9\" />\r\n <line x1=\"18\" y1=\"15\" x2=\"21\" y2=\"15\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ScissorsIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <circle cx=\"6\" cy=\"6\" r=\"3\" />\r\n <circle cx=\"6\" cy=\"18\" r=\"3\" />\r\n <line x1=\"20\" y1=\"4\" x2=\"8.12\" y2=\"15.88\" />\r\n <line x1=\"14.47\" y1=\"14.48\" x2=\"20\" y2=\"20\" />\r\n <line x1=\"8.12\" y1=\"8.12\" x2=\"12\" y2=\"12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\n// --- Slash-menu command icons ---------------------------------------------\r\n// One icon per command so the \"/\" menu reads like a familiar block editor's\r\n// (glyph + label, not label-only) — see SlashMenu.jsx and each block/\r\n// inline type's own `slashCommand(s)` definition for where these attach.\r\n\r\nexport function TextIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"17\" y1=\"6\" x2=\"3\" y2=\"6\" />\r\n <line x1=\"21\" y1=\"12\" x2=\"3\" y2=\"12\" />\r\n <line x1=\"15\" y1=\"18\" x2=\"3\" y2=\"18\" />\r\n </Icon>\r\n );\r\n}\r\n\r\n/** Parameterized by `level` (1-3) — a single \"H\" + digit, filled text rather than the shared stroke-only glyphs above. */\r\nexport function HeadingIcon({ level = 1, size = 16, ...rest }) {\r\n return (\r\n <svg width={size} height={size} viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\" {...rest}>\r\n <text x=\"2\" y=\"18\" fontSize=\"14\" fontWeight=\"700\" fill=\"currentColor\" fontFamily=\"inherit\">\r\n H{level}\r\n </text>\r\n </svg>\r\n );\r\n}\r\n\r\n// Fixed-level wrappers around HeadingIcon — plain-.js command definitions\r\n// (e.g. blocks/heading/index.js) can't write JSX to pass `level` themselves,\r\n// so each level gets its own importable component instead.\r\nexport function Heading1Icon(props) {\r\n return <HeadingIcon level={1} {...props} />;\r\n}\r\nexport function Heading2Icon(props) {\r\n return <HeadingIcon level={2} {...props} />;\r\n}\r\nexport function Heading3Icon(props) {\r\n return <HeadingIcon level={3} {...props} />;\r\n}\r\n\r\nexport function QuoteIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M7 7a3 3 0 0 0-3 3v3a2 2 0 0 0 2 2h2a1 1 0 0 0 1-1v-4a1 1 0 0 0-1-1H6a3 3 0 0 1 3-3z\" />\r\n <path d=\"M17 7a3 3 0 0 0-3 3v3a2 2 0 0 0 2 2h2a1 1 0 0 0 1-1v-4a1 1 0 0 0-1-1h-2a3 3 0 0 1 3-3z\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function CodeIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <polyline points=\"9 8 4 12 9 16\" />\r\n <polyline points=\"15 8 20 12 15 16\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function DividerIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function CalloutIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M4 5h16a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H9l-4 4v-4H4a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z\" />\r\n <line x1=\"7\" y1=\"9\" x2=\"17\" y2=\"9\" />\r\n <line x1=\"7\" y1=\"12.5\" x2=\"13\" y2=\"12.5\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ButtonIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"3\" y=\"8\" width=\"18\" height=\"8\" rx=\"3\" />\r\n <line x1=\"8\" y1=\"12\" x2=\"16\" y2=\"12\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function TableIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"1\" />\r\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" />\r\n <line x1=\"3\" y1=\"16\" x2=\"21\" y2=\"16\" />\r\n <line x1=\"9\" y1=\"4\" x2=\"9\" y2=\"20\" />\r\n <line x1=\"15\" y1=\"4\" x2=\"15\" y2=\"20\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ColumnsIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"1\" />\r\n <line x1=\"9\" y1=\"4\" x2=\"9\" y2=\"20\" />\r\n <line x1=\"15\" y1=\"4\" x2=\"15\" y2=\"20\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function BulletedListIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <circle cx=\"4.5\" cy=\"6\" r=\"1.2\" fill=\"currentColor\" stroke=\"none\" />\r\n <circle cx=\"4.5\" cy=\"12\" r=\"1.2\" fill=\"currentColor\" stroke=\"none\" />\r\n <circle cx=\"4.5\" cy=\"18\" r=\"1.2\" fill=\"currentColor\" stroke=\"none\" />\r\n <line x1=\"9\" y1=\"6\" x2=\"21\" y2=\"6\" />\r\n <line x1=\"9\" y1=\"12\" x2=\"21\" y2=\"12\" />\r\n <line x1=\"9\" y1=\"18\" x2=\"21\" y2=\"18\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function NumberedListIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"10\" y1=\"6\" x2=\"21\" y2=\"6\" />\r\n <line x1=\"10\" y1=\"12\" x2=\"21\" y2=\"12\" />\r\n <line x1=\"10\" y1=\"18\" x2=\"21\" y2=\"18\" />\r\n <text x=\"2\" y=\"8.5\" fontSize=\"7\" fontWeight=\"700\" fill=\"currentColor\" stroke=\"none\">\r\n 1\r\n </text>\r\n <text x=\"2\" y=\"14.5\" fontSize=\"7\" fontWeight=\"700\" fill=\"currentColor\" stroke=\"none\">\r\n 2\r\n </text>\r\n <text x=\"2\" y=\"20.5\" fontSize=\"7\" fontWeight=\"700\" fill=\"currentColor\" stroke=\"none\">\r\n 3\r\n </text>\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function CheckboxIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"3\" />\r\n <polyline points=\"8 12 11 15 16 9\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function MentionIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\r\n <path d=\"M16 12v1.5a2.5 2.5 0 0 0 5 0V12a9 9 0 1 0-4.5 7.79\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function DateIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\" />\r\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" />\r\n <line x1=\"8\" y1=\"3\" x2=\"8\" y2=\"7\" />\r\n <line x1=\"16\" y1=\"3\" x2=\"16\" y2=\"7\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function SelectIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M12 3h7a2 2 0 0 1 2 2v7a2 2 0 0 1-.59 1.41l-8 8a2 2 0 0 1-2.82 0l-7-7a2 2 0 0 1 0-2.82l8-8A2 2 0 0 1 12 3z\" />\r\n <circle cx=\"15.5\" cy=\"8.5\" r=\"1.2\" fill=\"currentColor\" stroke=\"none\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function ImageIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\" />\r\n <circle cx=\"9\" cy=\"10\" r=\"1.5\" fill=\"currentColor\" stroke=\"none\" />\r\n <path d=\"M4 17l5-5 4 4 4-5 4 6\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function VideoIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <rect x=\"3\" y=\"5\" width=\"14\" height=\"14\" rx=\"2\" />\r\n <path d=\"M17 10l4-2.5v9L17 14\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function EyeIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z\" />\r\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function EyeOffIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M17.94 17.94A10.94 10.94 0 0 1 12 19c-6.5 0-10-7-10-7a18.5 18.5 0 0 1 5.06-5.94M9.9 4.24A10.94 10.94 0 0 1 12 4c6.5 0 10 7 10 7a18.5 18.5 0 0 1-2.16 3.19\" />\r\n <path d=\"M14.12 14.12a3 3 0 1 1-4.24-4.24\" />\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function AudioIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <line x1=\"4\" y1=\"10\" x2=\"4\" y2=\"14\" />\r\n <line x1=\"8\" y1=\"7\" x2=\"8\" y2=\"17\" />\r\n <line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\" />\r\n <line x1=\"16\" y1=\"7\" x2=\"16\" y2=\"17\" />\r\n <line x1=\"20\" y1=\"10\" x2=\"20\" y2=\"14\" />\r\n </Icon>\r\n );\r\n}\r\n\r\nexport function MicIcon(props) {\r\n return (\r\n <Icon {...props}>\r\n <path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\" />\r\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\r\n <line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\" />\r\n <line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\" />\r\n </Icon>\r\n );\r\n}\r\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useEditorStore, useBlockRegistry, useInlineRegistry } from './EditorProvider.jsx';\nimport { useDocumentVersions } from './useDocumentVersions.js';\nimport { createAutoVersionHistory } from '../versions/autoVersionHistory.js';\nimport { diffDocumentsHTML } from '../versions/diffVersions.js';\nimport { applyDocumentTemplate } from '../templates/blockTemplates.js';\nimport { exportDocumentHTML } from '../clipboard/exportDocument.js';\nimport { EditorStore } from '../store/EditorStore.js';\nimport { CommentAvatar } from './CommentAvatar.jsx';\nimport { formatRelativeTime } from './commentFormatting.js';\nimport { ClockHistoryIcon, RestoreIcon, XIcon } from './icons.jsx';\n\nfunction formatDayLabel(timestamp) {\n const d = new Date(timestamp);\n const now = new Date();\n const startOfDay = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n const diffDays = Math.round((startOfDay(now) - startOfDay(d)) / (24 * 60 * 60 * 1000));\n if (diffDays === 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n return d.toLocaleDateString(undefined, {\n month: 'long',\n day: 'numeric',\n year: d.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n });\n}\n\n/**\n * Google Docs-style version history — no \"name it and save\" step. Mount\n * this once anywhere under an `<EditorProvider>` (`store` must be a\n * `History` instance, not a plain `EditorStore` — see `createAutoVersionHistory`)\n * and it both quietly captures automatic snapshots (one saved after each\n * burst of edits settles, attributed to whoever made them via History's\n * `defaultActorId`/`useEditor`'s `currentUserId`, no separate identity\n * plumbing needed here) AND renders the \"Version history\" button + drawer\n * UI for browsing/previewing/restoring them.\n *\n * The drawer's preview is a static HTML render (`exportDocumentHTML` against\n * a throwaway `EditorStore` built from that version's snapshot) — read-only\n * by construction, not a second live nested editor.\n */\nexport function VersionHistory({ docId, idleMs, maxVersions }) {\n const store = useEditorStore();\n const registry = useBlockRegistry();\n const inlineRegistry = useInlineRegistry();\n const { versions, isLoaded, refresh } = useDocumentVersions(docId);\n const [isOpen, setIsOpen] = useState(false);\n const [selectedId, setSelectedId] = useState(null);\n const [viewMode, setViewMode] = useState('changes'); // 'changes' | 'preview'\n const drawerRef = useRef(null);\n\n useEffect(() => {\n if (typeof store.getHistoryLog !== 'function') return undefined; // needs a History instance, not a plain EditorStore\n const autoHistory = createAutoVersionHistory({ store, docId, idleMs, maxVersions, onSnapshot: refresh });\n return () => autoHistory.stop();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [store, docId]);\n\n function close() {\n setIsOpen(false);\n setSelectedId(null);\n setViewMode('changes');\n }\n\n useEffect(() => {\n if (!isOpen) return undefined;\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') close();\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n const selectedIndex = versions.findIndex((v) => v.id === selectedId);\n const selected = selectedIndex >= 0 ? versions[selectedIndex] : null;\n // versions is newest-first, so the version right before this one chronologically is the next array entry.\n const previousVersion = selectedIndex >= 0 ? (versions[selectedIndex + 1] ?? null) : null;\n\n const previewHtml = useMemo(() => {\n if (!selected) return '';\n const previewStore = new EditorStore(selected.doc);\n return exportDocumentHTML(previewStore, registry, inlineRegistry);\n }, [selected, registry, inlineRegistry]);\n\n const diffHtml = useMemo(() => {\n if (!selected) return '';\n return diffDocumentsHTML(previousVersion?.doc ?? null, selected.doc);\n }, [selected, previousVersion]);\n\n function handleRestore() {\n if (!selected) return;\n if (!window.confirm('Restore this version? This replaces the current document.')) return;\n applyDocumentTemplate(store, selected.doc);\n close();\n }\n\n // Groups by day, preserving useDocumentVersions' own newest-first order.\n const groups = [];\n for (const version of versions) {\n const label = formatDayLabel(version.timestamp);\n let group = groups[groups.length - 1];\n if (!group || group.label !== label) {\n group = { label, versions: [] };\n groups.push(group);\n }\n group.versions.push(version);\n }\n\n return (\n <>\n <button type=\"button\" className=\"be-version-history-trigger\" onClick={() => setIsOpen(true)} title=\"Version history\">\n <ClockHistoryIcon size={15} />\n Version history\n </button>\n {isOpen &&\n createPortal(\n <>\n <div className=\"be-version-history-backdrop\" onClick={close} />\n <div ref={drawerRef} className=\"be-version-history-drawer\" role=\"dialog\" aria-label=\"Version history\">\n <div className=\"be-version-history-header\">\n <span>{selected ? 'Preview' : 'Version history'}</span>\n <button type=\"button\" className=\"be-version-history-close\" onClick={close} aria-label=\"Close\">\n <XIcon size={14} />\n </button>\n </div>\n\n {selected ? (\n <div className=\"be-version-history-preview\">\n <div className=\"be-version-history-preview-meta\">\n <CommentAvatar authorId={selected.authorId} size={24} />\n <div>\n <div className=\"be-version-history-preview-author\">{selected.authorId ?? 'Unknown'}</div>\n <div className=\"be-version-history-preview-time\">\n {new Date(selected.timestamp).toLocaleString()} · {selected.summary}\n </div>\n </div>\n </div>\n\n <div className=\"be-version-history-view-toggle\" role=\"tablist\" aria-label=\"View mode\">\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={viewMode === 'changes'}\n className={viewMode === 'changes' ? 'is-active' : ''}\n onClick={() => setViewMode('changes')}\n >\n Changes\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={viewMode === 'preview'}\n className={viewMode === 'preview' ? 'is-active' : ''}\n onClick={() => setViewMode('preview')}\n >\n Preview\n </button>\n </div>\n\n {viewMode === 'changes' && (\n <>\n <div className=\"be-version-history-diff-legend\">\n <span className=\"be-version-diff-added\">Added</span>\n <span className=\"be-version-diff-removed\">Removed</span>\n {!previousVersion && <span className=\"be-version-history-diff-legend-note\">First saved version — everything shown is new.</span>}\n </div>\n {/* Word-level diff against the previous version, rendered from plain text -- deliberately simpler than the live editor's own formatting (see diffDocumentsHTML). */}\n <div className=\"be-version-history-preview-body be-version-history-diff-body\" dangerouslySetInnerHTML={{ __html: diffHtml }} />\n </>\n )}\n {viewMode === 'preview' && (\n // Static HTML from a throwaway store (see previewHtml above) -- inherently read-only, not a second live editor.\n <div className=\"be-version-history-preview-body\" dangerouslySetInnerHTML={{ __html: previewHtml }} />\n )}\n\n <div className=\"be-version-history-preview-actions\">\n <button\n type=\"button\"\n onClick={() => {\n setSelectedId(null);\n setViewMode('changes');\n }}\n >\n Back\n </button>\n <button type=\"button\" className=\"be-version-history-restore\" onClick={handleRestore}>\n <RestoreIcon size={13} />\n Restore this version\n </button>\n </div>\n </div>\n ) : (\n <div className=\"be-version-history-list\">\n {!isLoaded && <p className=\"be-version-history-empty\">Loading…</p>}\n {isLoaded && versions.length === 0 && (\n <p className=\"be-version-history-empty\">No versions yet — one is saved automatically after you make some edits and pause.</p>\n )}\n {groups.map((group) => (\n <div key={group.label} className=\"be-version-history-group\">\n <div className=\"be-version-history-group-label\">{group.label}</div>\n {group.versions.map((version) => (\n <button key={version.id} type=\"button\" className=\"be-version-history-item\" onClick={() => setSelectedId(version.id)}>\n <CommentAvatar authorId={version.authorId} size={24} />\n <div className=\"be-version-history-item-body\">\n <div className=\"be-version-history-item-author\">{version.authorId ?? 'Unknown'}</div>\n <div className=\"be-version-history-item-meta\">\n {formatRelativeTime(version.timestamp)} · {version.summary}\n </div>\n </div>\n </button>\n ))}\n </div>\n ))}\n </div>\n )}\n </div>\n </>,\n document.body,\n )}\n </>\n );\n}\n","import { genId } from '../utils/idGen.js';\nimport { replaceRunSpan } from '../store/operations.js';\n\nfunction getBlockRunIds(store, blockId) {\n const block = store.getBlock(blockId);\n return block.props?.titleRunIds ?? block.contentIds;\n}\n\n/** Appends `commentId` to a run's `marks.commentIds`, idempotently -- never clobbers other marks or other comment ids already on the run. */\nfunction appendCommentMark(marks, commentId) {\n const existing = marks?.commentIds ?? [];\n if (existing.includes(commentId)) return marks ?? {};\n return { ...marks, commentIds: [...existing, commentId] };\n}\n\n/** Removes `commentId` from a run's `marks.commentIds`, dropping the key entirely once empty. */\nfunction removeCommentMark(marks, commentId) {\n const existing = marks?.commentIds ?? [];\n if (!existing.includes(commentId)) return marks ?? {};\n const next = { ...marks };\n const remaining = existing.filter((id) => id !== commentId);\n if (remaining.length > 0) next.commentIds = remaining;\n else delete next.commentIds;\n return next;\n}\n\n/** Same single-run split as markCommands.js's applyPatchToSingleRun, but appending a comment id instead of applying a flat marks patch -- see this module's own doc comment for why it isn't shared with markCommands.js. Returns the op to apply (never applies it itself -- see addCommentMarkOverRange). */\nfunction appendCommentToSingleRunOp(blockId, run, from, to, commentId) {\n const nextMarks = appendCommentMark(run.marks, commentId);\n\n if (from === 0 && to === run.value.length) {\n return { type: 'updateRun', id: run.id, patch: { marks: nextMarks } };\n }\n\n const before = run.value.slice(0, from);\n const middle = run.value.slice(from, to);\n const after = run.value.slice(to);\n\n const newRuns = [];\n if (before) newRuns.push({ id: genId(), type: 'text', value: before, marks: { ...run.marks } });\n newRuns.push({ id: genId(), type: 'text', value: middle, marks: nextMarks });\n if (after) newRuns.push({ id: genId(), type: 'text', value: after, marks: { ...run.marks } });\n\n return replaceRunSpan(blockId, [run.id], newRuns);\n}\n\n/**\n * Computes the single operation that marks every run (or run slice) within\n * `{ blockId, startRunId, startOffset, endRunId, endOffset }` as belonging\n * to `commentId`, by appending it to each affected run's `marks.commentIds`\n * array -- but does NOT apply it (returns the op, or `null` for a\n * collapsed/unresolvable range), so callers (see src/comments/comments.js's\n * addComment) can batch it with the comment-thread-creation op as one\n * atomic undo step via `store.performBatch`.\n *\n * Mirrors markCommands.js's applyMarksPatchOverRunSpan's run-resolution/\n * splitting logic, but is a deliberately separate, new function rather\n * than a change to that shared, well-tested mark-toggle path -- marks\n * today are a flat `next[markName] = value` replace (see markCommands.js's\n * own applyMarksPatch), and comments need *append* semantics since\n * multiple comments can overlap the same text.\n *\n * The resulting op is an ordinary `replaceRunSpan`/`updateRun` -- the same\n * ops every other formatting command already uses, with the same\n * pre-existing local-only-in-collaboration scope (see EditorStore's\n * REPLACE_RUN_SPAN case) rather than a new op type.\n */\nexport function addCommentMarkOverRange(store, { blockId, startRunId, startOffset, endRunId, endOffset }, commentId) {\n const runIds = getBlockRunIds(store, blockId);\n const startIndex = runIds.indexOf(startRunId);\n const endIndex = runIds.indexOf(endRunId);\n if (startIndex === -1 || endIndex === -1) return null;\n\n const [fromIndex, toIndex] = startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\n const fromOffset = startIndex <= endIndex ? startOffset : endOffset;\n const toOffset = startIndex <= endIndex ? endOffset : startOffset;\n\n const rangeRunIds = runIds.slice(fromIndex, toIndex + 1);\n const rangeRuns = rangeRunIds.map((id) => store.getRun(id));\n\n if (fromIndex === toIndex) {\n const run = rangeRuns[0];\n if (run.type !== 'text') return null;\n const from = Math.max(0, Math.min(fromOffset, toOffset));\n const to = Math.min(run.value.length, Math.max(fromOffset, toOffset));\n if (from === to) return null;\n return appendCommentToSingleRunOp(blockId, run, from, to, commentId);\n }\n\n const newRuns = [];\n rangeRuns.forEach((run, i) => {\n if (run.type !== 'text') {\n newRuns.push(run); // atomic: pass through untouched\n return;\n }\n\n const isFirst = i === 0;\n const isLast = i === rangeRuns.length - 1;\n const sliceStart = isFirst ? fromOffset : 0;\n const sliceEnd = isLast ? toOffset : run.value.length;\n\n const before = run.value.slice(0, sliceStart);\n const middle = run.value.slice(sliceStart, sliceEnd);\n const after = run.value.slice(sliceEnd);\n\n if (before) newRuns.push({ id: genId(), type: 'text', value: before, marks: { ...run.marks } });\n newRuns.push({ id: genId(), type: 'text', value: middle, marks: appendCommentMark(run.marks, commentId) });\n if (after) newRuns.push({ id: genId(), type: 'text', value: after, marks: { ...run.marks } });\n });\n\n return replaceRunSpan(blockId, rangeRunIds, newRuns);\n}\n\n/**\n * Computes the ops that strip `commentId` from every run in the whole\n * document that carries it (via store.getAllRunIds(), not just the range\n * it was originally added over -- a later formatting edit may have split/\n * re-minted run ids since, see the package README's documented limitation\n * on `anchorRunIds`) -- does NOT apply them (returns the op list), for the\n * same batching reason as addCommentMarkOverRange (see src/comments/\n * comments.js's deleteComment). Each op is a plain `updateRun({ marks })`\n * -- `marks` is a whole-field LWW key (only a text run's lone `value` key\n * is routed through the character CRDT), so this is the same primitive\n * every other mark removal already uses.\n */\nexport function removeCommentMarkEverywhere(store, commentId) {\n const ops = [];\n for (const runId of store.getAllRunIds()) {\n const run = store.getRun(runId);\n if (!run?.marks?.commentIds?.includes(commentId)) continue;\n ops.push({ type: 'updateRun', id: runId, patch: { marks: removeCommentMark(run.marks, commentId) } });\n }\n return ops;\n}\n","import { genId } from '../utils/idGen.js';\nimport {\n addCommentThread as addCommentThreadOp,\n removeCommentThread as removeCommentThreadOp,\n addCommentReply as addCommentReplyOp,\n resolveComment as resolveCommentOp,\n} from '../store/operations.js';\nimport { addCommentMarkOverRange, removeCommentMarkEverywhere } from './commentMarks.js';\n\nfunction applyOps(store, ops) {\n if (typeof store.performBatch === 'function') store.performBatch(ops);\n else for (const op of ops) store.applyOperation(op);\n}\n\n/**\n * Creates a comment thread anchored to `range` ({ blockId, startRunId,\n * startOffset, endRunId, endOffset }, the same shape markCommands.js's\n * setMarksOverSelection takes) — highlights the range (appending this\n * comment's id to each covered run's `marks.commentIds`, see\n * commentMarks.js) and creates the thread's metadata as one atomic undo\n * step. `authorId` is always caller-supplied — this package has no\n * identity concept of its own (same convention as `History.perform(op, {\n * actorId })`).\n *\n * The highlighted range is local-only in collaboration for v1 (inherits\n * the pre-existing scope of every `replaceRunSpan`-based formatting\n * operation — see EditorStore's REPLACE_RUN_SPAN case); the thread's own\n * metadata (text/author/replies/resolved) IS collaboration-aware and\n * broadcasts live to connected peers.\n *\n * Returns the new comment's id.\n */\nexport function addComment(store, range, { authorId, text }) {\n const commentId = genId();\n const markOp = addCommentMarkOverRange(store, range, commentId);\n const thread = {\n id: commentId,\n blockId: range.blockId,\n anchorRunIds: [range.startRunId, range.endRunId],\n resolved: false,\n messages: [{ id: genId(), authorId, text, createdAt: Date.now() }],\n };\n const ops = markOp ? [markOp, addCommentThreadOp(thread)] : [addCommentThreadOp(thread)];\n applyOps(store, ops);\n return commentId;\n}\n\n/** Appends a reply to an existing thread — one undo step. */\nexport function replyToComment(store, commentId, { authorId, text }) {\n const message = { id: genId(), authorId, text, createdAt: Date.now() };\n store.applyOperation(addCommentReplyOp(commentId, message));\n return message.id;\n}\n\n/** Flips a thread's resolved flag (`resolved` defaults to `true`) — one undo step. */\nexport function resolveComment(store, commentId, resolved = true) {\n store.applyOperation(resolveCommentOp(commentId, resolved));\n}\n\n/** Removes a thread's metadata AND strips its highlight from every run that still carries it — one atomic undo step. */\nexport function deleteComment(store, commentId) {\n const markRemovalOps = removeCommentMarkEverywhere(store, commentId);\n applyOps(store, [...markRemovalOps, removeCommentThreadOp(commentId)]);\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useEditorStore } from './EditorProvider.jsx';\n\nconst COMMENTS_KEY = '$comments';\n\n/**\n * Subscribes to the store's comment threads (see src/comments/comments.js's\n * addComment/replyToComment/resolveComment/deleteComment) — reactive so a\n * comments sidebar/panel re-renders after any of those, the same way\n * useFieldTypes re-renders a field-type list.\n *\n * store.getComments() returns a referentially-stable array (cached,\n * invalidated only by a comments op) — required by useSyncExternalStore,\n * same contract as useFieldTypes/useBlock/useRun.\n */\nexport function useComments() {\n const store = useEditorStore();\n const subscribe = useCallback((onStoreChange) => store.subscribe(COMMENTS_KEY, onStoreChange), [store]);\n const getSnapshot = useCallback(() => store.getComments(), [store]);\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import { useRef, useState } from 'react';\nimport { CommentAvatar } from './CommentAvatar.jsx';\nimport { SendIcon } from './icons.jsx';\n\n/**\n * Avatar + auto-growing textarea, with a Send (and optional Cancel) button\n * on their own row below — the one shared \"compose a comment message\" UI\n * used for both a brand-new comment (FloatingToolbar's Comment button, once\n * an authorId is configured) and a reply (CommentThreadCard). Deliberately\n * not a modal: it's meant to sit inline inside a small popover/panel,\n * matching the \"minimal UI\" goal rather than interrupting with a full\n * dialog the way LinkEditModal does for a fundamentally different, rarer\n * action (editing a URL).\n *\n * The textarea starts at 2 rows and grows with content up to 5 (see\n * `.be-comment-composer-textarea`'s min/max-height plus the resize-on-input\n * below), then scrolls — comfortable for more than a one-line reply without\n * the composer itself growing unbounded.\n *\n * `authorId` only renders the composer's own avatar (a preview of who's\n * about to post) — it does NOT decide who the message is attributed to;\n * the caller still passes `authorId` to `addComment`/`replyToComment`\n * itself. Ctrl/Cmd+Enter submits, Escape cancels (if `onCancel` is given)\n * — a plain Enter stays newline-friendly now that there's room for more\n * than one line.\n */\nexport function CommentComposer({ authorId, placeholder = 'Add a comment…', autoFocus = false, onSubmit, onCancel }) {\n const [text, setText] = useState('');\n const textareaRef = useRef(null);\n const trimmed = text.trim();\n\n function resizeToContent() {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = 'auto';\n el.style.height = `${el.scrollHeight}px`;\n }\n\n function handleChange(event) {\n setText(event.target.value);\n resizeToContent();\n }\n\n function handleSubmit(event) {\n event.preventDefault();\n if (!trimmed) return;\n onSubmit(trimmed);\n setText('');\n if (textareaRef.current) textareaRef.current.style.height = '';\n }\n\n return (\n <form className=\"be-comment-composer\" onSubmit={handleSubmit}>\n <div className=\"be-comment-composer-input-row\">\n <CommentAvatar authorId={authorId} size={26} />\n <textarea\n ref={textareaRef}\n className=\"be-comment-composer-textarea\"\n value={text}\n onChange={handleChange}\n placeholder={placeholder}\n rows={2}\n autoFocus={autoFocus}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) handleSubmit(event);\n else if (event.key === 'Escape' && onCancel) onCancel();\n }}\n />\n </div>\n <div className=\"be-comment-composer-actions\">\n {onCancel && (\n <button type=\"button\" className=\"be-comment-composer-cancel\" onClick={onCancel}>\n Cancel\n </button>\n )}\n <button type=\"submit\" className=\"be-comment-composer-submit\" disabled={!trimmed}>\n <SendIcon size={13} />\n Send\n </button>\n </div>\n </form>\n );\n}\n","import { useState } from 'react';\nimport { replyToComment, resolveComment, deleteComment } from '../comments/comments.js';\nimport { CommentComposer } from './CommentComposer.jsx';\nimport { CommentAvatar } from './CommentAvatar.jsx';\nimport { formatRelativeTime } from './commentFormatting.js';\nimport { CommentIcon, CheckIcon, TrashIcon } from './icons.jsx';\nimport { useHoveredComment } from './EditorProvider.jsx';\n\nfunction CommentMessageRow({ message, size = 26 }) {\n return (\n <div className=\"be-comment-message\">\n <CommentAvatar authorId={message.authorId} size={size} />\n <div className=\"be-comment-message-body\">\n <div className=\"be-comment-message-header\">\n <span className=\"be-comment-message-author\">{message.authorId}</span>\n <span className=\"be-comment-message-time\">{formatRelativeTime(message.createdAt)}</span>\n </div>\n <p className=\"be-comment-message-text\">{message.text}</p>\n </div>\n </div>\n );\n}\n\n/**\n * One comment thread — the original message, then any replies (visually\n * indented with a connecting line, chat-thread style), then either a Reply\n * composer (once clicked) or the Reply/Resolve/Delete action row. Shared by\n * both places a thread can be viewed: CommentPopover (click/hover on the\n * highlighted text) and CommentsPanel (the opt-in right-side sidebar) —\n * one implementation, so the two surfaces can't drift apart.\n *\n * Resolve/Delete act on the whole thread (this package's data model has no\n * per-reply resolve/delete — see CommentThread in the README), so the\n * action row sits once below every message, not per message.\n *\n * `authorId`, if not given, hides the Reply action entirely (composing a\n * message needs an author; resolving/deleting don't, so those stay\n * available either way) — see NoteloomEditor's `commentAuthorId` prop.\n *\n * Hovering the card echoes the highlight onto the actual text in the\n * editor (see useHoveredComment); `onJumpToText`, if given (CommentsPanel\n * passes it, CommentPopover doesn't need to -- you're already looking at\n * the text there), is called when the messages themselves are clicked, for\n * scrolling to and briefly re-highlighting the anchored text.\n */\nexport function CommentThreadCard({ store, thread, authorId, onJumpToText }) {\n const [isReplying, setIsReplying] = useState(false);\n const [hoveredCommentId, setHoveredCommentId] = useHoveredComment();\n const [rootMessage, ...replies] = thread.messages;\n\n function handleReplySubmit(text) {\n replyToComment(store, thread.id, { authorId, text });\n setIsReplying(false);\n }\n\n return (\n <div\n className={`be-comment-thread${thread.resolved ? ' be-comment-thread-resolved' : ''}${hoveredCommentId === thread.id ? ' be-comment-thread-hovered' : ''}`}\n onMouseEnter={() => setHoveredCommentId(thread.id)}\n onMouseLeave={() => setHoveredCommentId(null)}\n >\n {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}\n <div onClick={onJumpToText ? () => onJumpToText(thread.id) : undefined} style={onJumpToText ? { cursor: 'pointer' } : undefined}>\n <CommentMessageRow message={rootMessage} />\n </div>\n\n {replies.length > 0 && (\n <div className=\"be-comment-thread-replies\">\n {replies.map((m) => (\n <CommentMessageRow key={m.id} message={m} size={22} />\n ))}\n </div>\n )}\n\n {isReplying ? (\n <CommentComposer authorId={authorId} placeholder=\"Reply…\" autoFocus onSubmit={handleReplySubmit} onCancel={() => setIsReplying(false)} />\n ) : (\n <div className=\"be-comment-thread-actions\">\n {/* No literal space between the icon and label -- CSS gap (see\n .be-comment-thread-actions button) handles the visual spacing,\n so button.textContent stays exactly \"Reply\"/\"Resolve\"/\"Reopen\". */}\n {authorId && (\n <button type=\"button\" onClick={() => setIsReplying(true)}>\n <CommentIcon size={13} />\n Reply\n </button>\n )}\n <button type=\"button\" onClick={() => resolveComment(store, thread.id, !thread.resolved)}>\n <CheckIcon size={13} />\n {thread.resolved ? 'Reopen' : 'Resolve'}\n </button>\n <button\n type=\"button\"\n className=\"be-comment-thread-delete\"\n onClick={() => deleteComment(store, thread.id)}\n aria-label=\"Delete comment\"\n title=\"Delete comment\"\n >\n <TrashIcon size={13} />\n </button>\n </div>\n )}\n </div>\n );\n}\n","import { useLayoutEffect, useRef, useState } from 'react';\nimport { useEditorStore, useHoveredComment } from './EditorProvider.jsx';\nimport { useComments } from './useComments.js';\nimport { CommentThreadCard } from './CommentThreadCard.jsx';\n\n/** Best-effort DOM lookup for where a thread's highlight actually lives right now -- anchorRunIds first (cheap, usually still right), falling back to a full scan (see removeCommentMarkEverywhere's own reasoning on why anchorRunIds can go stale). */\nfunction findAnchorEl(store, thread) {\n for (const id of thread.anchorRunIds ?? []) {\n const el = document.querySelector(`[data-run-id=\"${id}\"]`);\n if (el) return el;\n }\n for (const runId of store.getAllRunIds()) {\n if (store.getRun(runId)?.marks?.commentIds?.includes(thread.id)) {\n const el = document.querySelector(`[data-run-id=\"${runId}\"]`);\n if (el) return el;\n }\n }\n return null;\n}\n\nfunction scrollToComment(store, commentId, setHoveredCommentId) {\n const thread = store.getComment(commentId);\n if (!thread) return;\n const el = findAnchorEl(store, thread);\n if (!el) return;\n el.scrollIntoView({ behavior: 'smooth', block: 'center' });\n setHoveredCommentId(commentId);\n setTimeout(() => setHoveredCommentId((current) => (current === commentId ? null : current)), 1500);\n}\n\n/**\n * The opt-in right-side comments panel (Notion/Google Docs-style) — every\n * thread in the document, unresolved first, each rendered via the same\n * CommentThreadCard the click-to-view CommentPopover uses (one reply/\n * resolve/delete implementation, two surfaces). Mount automatically via\n * `<NoteloomEditor showCommentsPanel commentAuthorId=\"...\">`, or render it\n * yourself anywhere under an `<EditorProvider>` for the granular API.\n *\n * Each card aligns vertically with its own anchored text (margin-comment\n * style), recomputed on scroll/resize and whenever the thread list changes\n * — a best-effort match against the current DOM (see findAnchorEl), not an\n * exact layout algorithm; closely-spaced comments can still overlap.\n *\n * `position: fixed` by default (see `.be-comments-panel` in style.css) so\n * it works with zero host layout changes; override that rule (or wrap it\n * in your own positioned container) for a different placement.\n */\nexport function CommentsPanel({ authorId }) {\n const store = useEditorStore();\n const comments = useComments();\n const [, setHoveredCommentId] = useHoveredComment();\n const listRef = useRef(null);\n const [positions, setPositions] = useState({});\n const sorted = [...comments].sort((a, b) => Number(a.resolved) - Number(b.resolved));\n\n useLayoutEffect(() => {\n function recompute() {\n const list = listRef.current;\n if (!list) return;\n const listTop = list.getBoundingClientRect().top;\n const next = {};\n // Starts at -Infinity (not 0) so a comment whose anchor has scrolled\n // above the panel moves right along with it (off the top, out of\n // view) instead of getting clamped there permanently -- Math.max\n // against a real previous-card position only kicks in to prevent\n // two comments landing on top of each other, never as a floor at 0.\n let cursor = -Infinity;\n for (const thread of sorted) {\n const el = findAnchorEl(store, thread);\n // Falls back to 0 (not `cursor + 90`) when an anchor can't be\n // found at all (e.g. its highlight was stripped by a later edit) --\n // otherwise a single missing anchor at the very start would leave\n // `cursor` at -Infinity forever, propagating through every\n // following card too.\n const natural = el ? el.getBoundingClientRect().top - listTop : Number.isFinite(cursor) ? cursor + 90 : 0;\n const top = Math.max(cursor, natural);\n next[thread.id] = top;\n cursor = top + 90; // rough per-card minimum before the next one can start, to avoid total overlap\n }\n setPositions(next);\n }\n recompute();\n window.addEventListener('scroll', recompute, true);\n window.addEventListener('resize', recompute);\n return () => {\n window.removeEventListener('scroll', recompute, true);\n window.removeEventListener('resize', recompute);\n };\n // `comments` (not the locally re-sorted `sorted`, a fresh array every\n // render) is the stable dependency -- useComments() only returns a new\n // reference when the underlying data actually changed.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [comments, store]);\n\n const totalHeight = Object.values(positions).reduce((max, v) => Math.max(max, v + 120), 0);\n\n if (sorted.length === 0) return null;\n\n return (\n <div className=\"be-comments-panel\" contentEditable={false}>\n <div ref={listRef} className=\"be-comments-panel-list\" style={{ height: totalHeight }}>\n {sorted.map((thread) => (\n <div key={thread.id} className=\"be-comments-panel-item\" style={{ top: positions[thread.id] ?? 0 }}>\n <CommentThreadCard\n store={store}\n thread={thread}\n authorId={authorId}\n onJumpToText={(id) => scrollToComment(store, id, setHoveredCommentId)}\n />\n </div>\n ))}\n </div>\n </div>\n );\n}\n","/**\r\n * Central registry of block types. Every consumer of a block's behavior\r\n * (the renderer, the slash-command menu, clipboard serialize/deserialize)\r\n * looks entries up here instead of switching on `block.type` itself — adding\r\n * a new block type is only ever \"call `register` once\".\r\n *\r\n * entry shape:\r\n * {\r\n * component, // React component, receives only { id }\r\n * isLeaf, // true if contentIds points at Runs, false if at child Blocks\r\n * defaultProps, // props for a freshly-inserted block of this type\r\n * toHTML(block, ctx), // ctx: { store, registry } -> html string\r\n * fromHTML(domNode, ctx), // -> constructed { block, runs } | null if this type doesn't claim the node\r\n * toPlainText(block, ctx), // -> plain text string\r\n * slashCommand: { label, icon, keywords, run(store, atBlockId) } | undefined,\r\n * slashCommands: [ { label, icon, keywords, run } ] | undefined // for a type offering more than one variant (e.g. listItem: bulleted/numbered/to-do)\r\n * }\r\n */\r\nexport class BlockRegistry {\r\n constructor() {\r\n this._types = new Map();\r\n }\r\n\r\n register(type, entry) {\r\n this._types.set(type, entry);\r\n }\r\n\r\n get(type) {\r\n return this._types.get(type);\r\n }\r\n\r\n isLeaf(type) {\r\n return Boolean(this._types.get(type)?.isLeaf);\r\n }\r\n\r\n listSlashCommands() {\r\n const commands = [];\r\n for (const entry of this._types.values()) {\r\n if (entry.slashCommand) commands.push(entry.slashCommand);\r\n if (entry.slashCommands) commands.push(...entry.slashCommands);\r\n }\r\n return commands;\r\n }\r\n\r\n listHtmlMatchers() {\r\n return [...this._types.values()].filter((entry) => entry.fromHTML);\r\n }\r\n}\r\n\r\nexport function createBlockRegistry() {\r\n return new BlockRegistry();\r\n}\r\n","/**\r\n * Registry of inline run types beyond plain text — e.g. a `select` chip, a\r\n * `date` chip, mixed directly into a paragraph's running text alongside\r\n * ordinary text runs. Parallel to BlockRegistry: `RunNode` (the per-run\r\n * renderer) looks entries up here instead of switching on `run.type`\r\n * itself, so adding a new inline type is only ever \"call `register` once\".\r\n *\r\n * entry shape:\r\n * {\r\n * component, // React component, receives only { id } (like BlockRenderer's contract)\r\n * isAtomic: true, // always true today: every registered inline type renders as a single\r\n * // contentEditable=false island (see RunNode) — the browser then handles\r\n * // arrow-key skip-over and single-backspace-delete for it natively.\r\n * toHTML(run, ctx), // ctx: { store, registry, inlineRegistry } -> html string\r\n * fromHTML(domNode, ctx), // -> constructed Run | null if this type doesn't claim the node\r\n * toPlainText(run, ctx), // -> plain text string\r\n * slashCommand: { label, icon, keywords, run(store, {blockId, runId}) } | undefined,\r\n * slashCommands: [ { label, icon, keywords, run } ] | undefined // for a type offering several commands\r\n * // at once (e.g. emoji: one entry per emoji, all sharing an \"emoji\" keyword)\r\n * // — mirrors BlockRegistry's own singular/plural split.\r\n * atCommand / atCommands, // same shape as slashCommand/slashCommands, listed under useAtMenuTrigger's\r\n * // \"@\" trigger instead of (or in addition to) \"/\" — e.g. createSelectFieldType's\r\n * // `triggers` option decides which of these two lists a given field type joins.\r\n * // A command object itself doesn't care which character triggered it (`run`\r\n * // only consumes {blockId, runId, sliceStart, sliceEnd}), so the very same\r\n * // object can be — and typically is — assigned to both slashCommand and atCommand.\r\n * }\r\n *\r\n * A plain `type: 'text'` run is handled directly by RunNode and never goes\r\n * through this registry — there's nothing to register for it.\r\n */\r\nexport class InlineRegistry {\r\n constructor() {\r\n this._types = new Map();\r\n }\r\n\r\n register(type, entry) {\r\n this._types.set(type, entry);\r\n }\r\n\r\n /** Drops a registered type — e.g. deleting a user-created custom field type. */\r\n unregister(type) {\r\n this._types.delete(type);\r\n }\r\n\r\n get(type) {\r\n return this._types.get(type);\r\n }\r\n\r\n listHtmlMatchers() {\r\n return [...this._types.values()].filter((entry) => entry.fromHTML);\r\n }\r\n\r\n listSlashCommands() {\r\n const commands = [];\r\n for (const entry of this._types.values()) {\r\n if (entry.slashCommand) commands.push(entry.slashCommand);\r\n if (entry.slashCommands) commands.push(...entry.slashCommands);\r\n }\r\n return commands;\r\n }\r\n\r\n /** Same shape as listSlashCommands, sourced from atCommand/atCommands instead — see useAtMenuTrigger. */\r\n listAtCommands() {\r\n const commands = [];\r\n for (const entry of this._types.values()) {\r\n if (entry.atCommand) commands.push(entry.atCommand);\r\n if (entry.atCommands) commands.push(...entry.atCommands);\r\n }\r\n return commands;\r\n }\r\n}\r\n\r\nexport function createInlineRegistry() {\r\n return new InlineRegistry();\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useEditorStore } from './EditorProvider.jsx';\r\n\r\n/**\r\n * Subscribes to exactly one block by id. `store.getBlock(id)` is guaranteed\r\n * by EditorStore's mutation discipline to return the same reference across\r\n * renders unless that exact block changed, which is what makes this safe\r\n * with useSyncExternalStore (no infinite-loop / \"getSnapshot should be\r\n * cached\" warning). Never derive a new object from the snapshot here — do\r\n * that in the calling component with useMemo instead.\r\n */\r\nexport function useBlock(id) {\r\n const store = useEditorStore();\r\n const subscribe = useCallback((onStoreChange) => store.subscribe(id, onStoreChange), [store, id]);\r\n const getSnapshot = useCallback(() => store.getBlock(id), [store, id]);\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n\r\n/** Same contract as useBlock, for inline Run leaves. */\r\nexport function useRun(id) {\r\n const store = useEditorStore();\r\n const subscribe = useCallback((onStoreChange) => store.subscribe(id, onStoreChange), [store, id]);\r\n const getSnapshot = useCallback(() => store.getRun(id), [store, id]);\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { genId } from '../utils/idGen.js';\r\n\r\n/**\r\n * A completely empty `<span></span>` (no text node at all) is not a valid\r\n * caret anchor in many browsers' contentEditable implementation: clicking\r\n * into it places the caret at the *container* level instead, and typing\r\n * then inserts a brand-new text node as a *sibling* of the empty span\r\n * rather than inside it. That stray node is never one React created, so it\r\n * becomes invisible to React's reconciliation from that point on — every\r\n * subsequent keystroke reads a DOM that's drifted further from what React\r\n * thinks it rendered, which is what produced runaway duplicated/shrinking\r\n * text. The fix (the same one Slate/Lexical use) is to never render a\r\n * truly empty text node: an empty run gets this zero-width-space\r\n * placeholder instead, giving the browser a real anchor, and it's stripped\r\n * back out whenever DOM text is read back into a run's logical value.\r\n */\r\nexport const EMPTY_RUN_PLACEHOLDER = '​';\r\n\r\nconst ZERO_WIDTH_SPACE_RE = /​/g;\r\n\r\n/** Strips the placeholder out of a string, however many times it appears. */\r\nexport function stripEmptyRunPlaceholder(text) {\r\n return (text ?? '').replace(ZERO_WIDTH_SPACE_RE, '');\r\n}\r\n\r\nfunction readRunText(node) {\r\n return stripEmptyRunPlaceholder(node.textContent);\r\n}\r\n\r\n/**\r\n * Reconciles a contentEditable container's *actual current* child nodes\r\n * back against the run list it was last rendered with. This is what makes\r\n * one shared contentEditable region per block work: React renders each run\r\n * as a child (a plain `<span data-run-id>` for text, an atomic\r\n * `contentEditable={false}` island for a non-text inline type), the browser\r\n * mutates that DOM natively as the user types/deletes/pastes, and this\r\n * function reads the result back into run objects on the container's\r\n * `input` event.\r\n *\r\n * Fast path (`onlyValueChanges: true`): every child still has the same\r\n * data-run-id, in the same order, and only text values differ — the\r\n * common case for ordinary typing, since the browser's native text edit\r\n * stays inside the existing span whose data-run-id attribute survives\r\n * untouched. Callers should apply per-run `updateRun` ops in this case, to\r\n * preserve History's per-run undo coalescing.\r\n *\r\n * Slow path (`onlyValueChanges: false`): node(s) appeared/disappeared/\r\n * reordered — e.g. paste, IME composition boundaries, or an atomic inline\r\n * chip being deleted as a whole unit. Callers should apply one\r\n * `setBlockRuns` op (see operations.js) as a single coarser undo step.\r\n *\r\n * Atomic (non-text) runs are matched by id only and never have their value\r\n * re-derived from DOM text content — they render their own UI, not plain\r\n * text, so `textContent` isn't a meaningful \"value\" for them.\r\n */\r\nexport function reconcileDomToRuns(containerEl, currentRuns) {\r\n const byId = new Map(currentRuns.map((run) => [run.id, run]));\r\n const seen = new Set();\r\n const nextRuns = [];\r\n let sameIdentityAndOrder = true;\r\n\r\n for (const node of containerEl.childNodes) {\r\n const runId = node.nodeType === 1 ? node.dataset?.runId : undefined;\r\n\r\n if (runId && byId.has(runId)) {\r\n seen.add(runId);\r\n const existing = byId.get(runId);\r\n\r\n if (existing.type !== 'text') {\r\n nextRuns.push(existing); // atomic: identity-only, never re-derive from DOM\r\n continue;\r\n }\r\n\r\n const newValue = readRunText(node);\r\n nextRuns.push(newValue === existing.value ? existing : { ...existing, value: newValue });\r\n continue;\r\n }\r\n\r\n // No existing run matches this DOM node at all: a structural change\r\n // (new text node from typing at a boundary, paste, IME, etc.).\r\n sameIdentityAndOrder = false;\r\n const text = readRunText(node);\r\n if (text) nextRuns.push({ id: genId(), type: 'text', value: text, marks: {} });\r\n }\r\n\r\n if (currentRuns.some((run) => !seen.has(run.id))) sameIdentityAndOrder = false; // a run's node vanished\r\n if (nextRuns.length !== currentRuns.length) sameIdentityAndOrder = false;\r\n if (sameIdentityAndOrder) {\r\n for (let i = 0; i < nextRuns.length; i += 1) {\r\n if (nextRuns[i].id !== currentRuns[i].id) {\r\n sameIdentityAndOrder = false;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n const changed = !sameIdentityAndOrder || nextRuns.some((run, i) => run !== currentRuns[i]);\r\n\r\n return { runs: nextRuns, changed, onlyValueChanges: sameIdentityAndOrder };\r\n}\r\n","/**\r\n * True when `run` contributes no real content: absent, or a text run whose\r\n * value is ''. An atomic (non-text) run — a date/select/checkbox/custom-field\r\n * chip — is never blank even without a \"value\", since there's a real chip\r\n * sitting there for the user to see/interact with.\r\n */\r\nexport function isRunBlank(run) {\r\n if (!run) return true;\r\n if (run.type !== 'text') return false;\r\n return (run.value ?? '') === '';\r\n}\r\n\r\n/**\r\n * True when every run in `runIds` is blank — used to decide whether to show\r\n * a placeholder hint (e.g. \"Type '/' for commands\") for a block that has\r\n * nothing in it yet. Same semantics as isCurrentBlockEmpty in\r\n * react/selectAllCommand.js (which needs a live caret to find the block\r\n * first); this version just takes run ids directly, since callers here\r\n * already have the block in hand from useBlock.\r\n */\r\nexport function isRunsEmpty(store, runIds) {\r\n if (!runIds || runIds.length === 0) return true;\r\n return runIds.every((id) => isRunBlank(store.getRun(id)));\r\n}\r\n","/** True for a block with nothing to merge/focus into (e.g. a divider): no run-bearing contentIds and no titleRunIds. */\r\nexport function isContentlessBlock(store, block) {\r\n if (!block) return false;\r\n const hasRuns = block.contentIds.length > 0;\r\n const hasTitleRuns = (block.props?.titleRunIds?.length ?? 0) > 0;\r\n return !hasRuns && !hasTitleRuns;\r\n}\r\n","function setCaretAtOffsetNow(runId, offset) {\n const el = document.querySelector(`[data-run-id=\"${runId}\"]`);\n if (!el) return;\n el.focus();\n const textNode = el.firstChild;\n const range = document.createRange();\n if (textNode && textNode.nodeType === 3) {\n const clamped = Math.max(0, Math.min(offset, textNode.length));\n range.setStart(textNode, clamped);\n range.setEnd(textNode, clamped);\n } else {\n range.selectNodeContents(el);\n range.collapse(offset <= 0);\n }\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n}\n\nfunction focusRunAt(runId, atStart) {\n requestAnimationFrame(() => {\n const el = document.querySelector(`[data-run-id=\"${runId}\"]`);\n if (!el) return;\n el.focus();\n const range = document.createRange();\n range.selectNodeContents(el);\n range.collapse(atStart);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n });\n}\n\n/** Best-effort: move DOM focus + caret to the end of the given run's editable element. */\nexport function focusRunEnd(runId) {\n focusRunAt(runId, false);\n}\n\n/** Best-effort: move DOM focus + caret to the start of the given run's editable element. */\nexport function focusRunStart(runId) {\n focusRunAt(runId, true);\n}\n\n/**\n * Best-effort: move DOM focus + caret to a specific character offset within\n * the given (text) run — deferred to the next animation frame, since most\n * callers use this right after a structural change (a new block/run that\n * may not exist in the DOM yet on this exact tick).\n */\nexport function focusRunAtOffset(runId, offset) {\n requestAnimationFrame(() => setCaretAtOffsetNow(runId, offset));\n}\n\n/**\n * Synchronous (no requestAnimationFrame) variant of focusRunAtOffset —\n * for the one call site (voice dictation's live interim-text hot path,\n * see useVoiceTyping.js) where the target run's DOM node is already\n * known to exist and has *already* been synchronously rewritten by the\n * time this is called. Deferring here would leave a window where a\n * rapid-fire next event reads the selection before it's been fixed,\n * which is exactly the caret-corruption bug this exists to avoid — every\n * other call site should keep using the rAF-deferred focusRunAtOffset\n * above.\n */\nexport function setCaretSync(runId, offset) {\n setCaretAtOffsetNow(runId, offset);\n}\n","import { useEffect, useRef } from 'react';\n\nconst FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\n/**\n * Minimal, dependency-free modal dialog: a fixed backdrop + centered panel.\n * Closes on Escape or a click directly on the backdrop (not bubbled up from\n * inside the panel, which is why the backdrop's onMouseDown checks\n * `event.target === event.currentTarget`). No focus trap — the whole\n * editor package is deliberately zero-dependency, and dialogs here are\n * short, single-purpose forms, not deep navigable UI.\n *\n * Does move focus IN (to the first focusable element inside the panel, or\n * the panel itself as a fallback) on open, and OUT (back to whatever had\n * focus right before the modal opened — typically the button that opened\n * it) on close — distinct from a focus trap: it's a one-time move each\n * way, not a loop that prevents Tab from ever leaving the panel.\n */\nexport function Modal({ isOpen, onClose, title, size = 'default', variant = 'dialog', children }) {\n const panelRef = useRef(null);\n const previouslyFocusedRef = useRef(null);\n\n useEffect(() => {\n if (!isOpen) return undefined;\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, onClose]);\n\n useEffect(() => {\n if (isOpen) {\n previouslyFocusedRef.current = document.activeElement;\n const panel = panelRef.current;\n const focusable = panel?.querySelector(FOCUSABLE_SELECTOR);\n (focusable ?? panel)?.focus();\n return undefined;\n }\n previouslyFocusedRef.current?.focus?.();\n previouslyFocusedRef.current = null;\n return undefined;\n }, [isOpen]);\n\n if (!isOpen) return null;\n const isSheet = variant === 'sheet';\n\n return (\n <div\n className={`be-modal-overlay${isSheet ? ' be-modal-overlay-sheet' : ''}`}\n onMouseDown={(event) => {\n if (event.target === event.currentTarget) onClose();\n }}\n >\n <div\n ref={panelRef}\n className={`be-modal${size === 'large' ? ' be-modal-large' : ''}${isSheet ? ' be-modal-sheet' : ''}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n tabIndex={-1}\n >\n {title && <div className=\"be-modal-title\">{title}</div>}\n {children}\n </div>\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { Modal } from './Modal.jsx';\n\n/**\n * URL + \"open in\" form shown for both creating a link (FloatingToolbar's\n * Link button, over a fresh selection) and editing one (LinkHoverCard's\n * pencil icon, over an existing link mark) — one shared modal so both\n * flows look and behave identically, rather than the hover card growing\n * its own smaller inline editor that drifts out of sync with this one.\n */\nexport function LinkEditModal({ isOpen, initialHref, initialTarget, hasExistingLink, onSave, onRemove, onClose }) {\n const [href, setHref] = useState('');\n const [target, setTarget] = useState('_self');\n\n useEffect(() => {\n if (!isOpen) return;\n setHref(initialHref);\n setTarget(initialTarget);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n const trimmedHref = href.trim();\n\n const handleSubmit = useCallback(\n (event) => {\n event.preventDefault();\n if (!trimmedHref) return;\n onSave(trimmedHref, target);\n },\n [trimmedHref, target, onSave],\n );\n\n return (\n <Modal isOpen={isOpen} onClose={onClose} title={hasExistingLink ? 'Edit link' : 'Add link'}>\n <form onSubmit={handleSubmit}>\n <label className=\"be-modal-field\">\n <span>URL</span>\n <input\n type=\"text\"\n value={href}\n onChange={(event) => setHref(event.target.value)}\n placeholder=\"https://example.com\"\n autoFocus\n />\n </label>\n <label className=\"be-modal-field\">\n <span>Open in</span>\n <select value={target} onChange={(event) => setTarget(event.target.value)}>\n <option value=\"_self\">Same tab</option>\n <option value=\"_blank\">New tab</option>\n </select>\n </label>\n <div className=\"be-modal-actions\">\n {hasExistingLink && (\n <button type=\"button\" className=\"be-modal-delete\" onClick={onRemove}>\n Remove link\n </button>\n )}\n <button type=\"button\" className=\"be-modal-cancel\" onClick={onClose}>\n Cancel\n </button>\n <button type=\"submit\" className=\"be-modal-save\" disabled={!trimmedHref}>\n Save\n </button>\n </div>\n </form>\n </Modal>\n );\n}\n","const MARGIN = 8;\n\n/**\n * Shifts `left`/`top` back inside the viewport (never past the opposite\n * edge either) for a box of the given size — the \"shift\" strategy antd's\n * `autoAdjustOverflow` uses, not a side-flip. Shared by every popover-\n * positioning hook in this file so the margin/clamp math lives in exactly\n * one place.\n */\nexport function clampLeftToViewport(left, width) {\n const maxLeft = Math.max(MARGIN, window.innerWidth - width - MARGIN);\n return Math.min(Math.max(left, MARGIN), maxLeft);\n}\n\nexport function clampTopToViewport(top, height) {\n const maxTop = Math.max(MARGIN, window.innerHeight - height - MARGIN);\n return Math.min(Math.max(top, MARGIN), maxTop);\n}\n","import { useLayoutEffect, useState } from 'react';\nimport { clampLeftToViewport, clampTopToViewport } from './popoverPosition.js';\n\n/**\n * Takes a `{ top, left }` position computed off a trigger's own\n * getBoundingClientRect() (as every portaled top-left-anchored menu here\n * already does) and, once the portaled element has actually mounted at\n * `menuRef`, measures its real size and shifts it back inside the viewport\n * if it would otherwise overflow — same \"shift\" behavior as antd's\n * `autoAdjustOverflow`, not a side-flip. Without this, a menu anchored near\n * the right/bottom edge (e.g. TurnIntoSubmenu opening to the right of its\n * trigger) can render partly or entirely off-screen, making its items\n * unreachable.\n *\n * `top`/`left` are taken as plain numbers (not a `{top,left}` object) so a\n * caller re-rendering every frame doesn't retrigger the adjustment via a\n * fresh object identity — only an actual numeric change re-anchors.\n *\n * Two-phase by design: the first effect snaps to the raw, unadjusted\n * position (matching the trigger) so the menu doesn't visibly jump on open;\n * the second effect then measures and clamps once real layout exists. Since\n * clamping the already-clamped position is a no-op, this settles after at\n * most one extra render — never loops. Both effects are `useLayoutEffect`s,\n * so React flushes the whole chain before the browser paints; nothing\n * visibly flashes at the raw position first.\n *\n * Only fits a plain top-left anchor (box grows right/down, no CSS\n * transform) — see popoverPosition.js's other hooks for centered\n * (translateX(-50%)) or right-anchored (translateX(-100%)) popovers, which\n * need the clamp math applied differently.\n */\nexport function useAutoAdjustedPosition(menuRef, isOpen, top, left) {\n const [position, setPosition] = useState(null);\n\n useLayoutEffect(() => {\n if (top == null || left == null) {\n setPosition(null);\n return;\n }\n setPosition({ top, left });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [top, left]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || !position) return;\n const rect = menuRef.current.getBoundingClientRect();\n const clampedLeft = clampLeftToViewport(position.left, rect.width);\n const clampedTop = clampTopToViewport(position.top, rect.height);\n if (clampedLeft !== position.left || clampedTop !== position.top) {\n setPosition({ top: clampedTop, left: clampedLeft });\n }\n }, [isOpen, menuRef, position]);\n\n return position;\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { updateRun } from '../store/operations.js';\nimport { LinkEditModal } from './LinkEditModal.jsx';\nimport { useAutoAdjustedPosition } from './useAutoAdjustedPosition.js';\nimport { PencilIcon, XIcon } from './icons.jsx';\n\n/**\n * Hover card for editing/removing an existing link mark — the counterpart\n * to FloatingToolbar's Link button (which only handles *creating* a link\n * over a selection). A plain click on link text just places the caret (see\n * EditableBlockContent's marksToStyle/onclick comment — navigation is\n * Ctrl/Cmd+click only, since the text is still editable), so there needs\n * to be some other way to discover \"this is a link\" and get back into it\n * without re-selecting the exact same text again. Hovering is that\n * discovery path, the same link-tooltip pattern most rich text editors use.\n *\n * The pencil button opens the exact same LinkEditModal FloatingToolbar's\n * Link button uses (pre-filled), rather than a second, smaller inline\n * editor — one link-editing UI, not two that could drift apart.\n *\n * Mutates the run directly via updateRun(runId, {marks}) rather than going\n * through the selection-based markCommands primitives — there's no live\n * text selection here at all, just \"this one run, whichever block it's\n * in\", so addressing it by run id directly is both simpler and correct\n * (no need to resolve/reconstruct a blockId+selection just to describe\n * \"the whole of this one run\").\n */\nexport function LinkHoverCard({ containerRef, store }) {\n const [hovered, setHovered] = useState(null); // { runId, rect } | null\n const [isModalOpen, setIsModalOpen] = useState(false);\n const hideTimerRef = useRef(null);\n const cardRef = useRef(null);\n\n const clearHideTimer = useCallback(() => {\n if (hideTimerRef.current) {\n clearTimeout(hideTimerRef.current);\n hideTimerRef.current = null;\n }\n }, []);\n\n const scheduleHide = useCallback(() => {\n clearHideTimer();\n hideTimerRef.current = setTimeout(() => {\n // A modal-open edit shouldn't vanish just because the mouse left the\n // hover card that launched it — only actually dismiss the underlying\n // hover state once the modal itself is closed (see the Save/Cancel\n // handlers below, which clear `hovered` themselves).\n setHovered((prev) => (isModalOpen ? prev : null));\n }, 250);\n }, [clearHideTimer, isModalOpen]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return undefined;\n\n const handleMouseOver = (event) => {\n const runEl = event.target.closest?.('[data-run-id]');\n if (!runEl || !container.contains(runEl)) return;\n const runId = runEl.dataset.runId;\n const run = store.getRun(runId);\n if (!run?.marks?.link) return;\n clearHideTimer();\n setHovered((prev) => (prev?.runId === runId ? prev : { runId, rect: runEl.getBoundingClientRect() }));\n };\n const handleMouseOut = () => scheduleHide();\n\n container.addEventListener('mouseover', handleMouseOver);\n container.addEventListener('mouseout', handleMouseOut);\n return () => {\n container.removeEventListener('mouseover', handleMouseOver);\n container.removeEventListener('mouseout', handleMouseOut);\n };\n }, [containerRef, store, clearHideTimer, scheduleHide]);\n\n useEffect(() => () => clearHideTimer(), [clearHideTimer]);\n\n const openModal = useCallback(() => setIsModalOpen(true), []);\n const closeModal = useCallback(() => {\n setIsModalOpen(false);\n setHovered(null);\n }, []);\n\n const saveLink = useCallback(\n (href, target) => {\n if (!hovered) return;\n const run = store.getRun(hovered.runId);\n if (!run) return;\n store.applyOperation(updateRun(hovered.runId, { marks: { ...run.marks, link: { href, target } } }));\n closeModal();\n },\n [hovered, store, closeModal],\n );\n\n const removeLink = useCallback(() => {\n if (!hovered) return;\n const run = store.getRun(hovered.runId);\n if (!run) return;\n const nextMarks = { ...run.marks };\n delete nextMarks.link;\n store.applyOperation(updateRun(hovered.runId, { marks: nextMarks }));\n closeModal();\n }, [hovered, store, closeModal]);\n\n const run = hovered && store.getRun(hovered.runId);\n const link = run?.marks?.link;\n const isCardOpen = Boolean(hovered && link && !isModalOpen);\n const position = useAutoAdjustedPosition(\n cardRef,\n isCardOpen,\n hovered ? hovered.rect.bottom + 6 : null,\n hovered ? hovered.rect.left : null,\n );\n\n return (\n <>\n {isCardOpen && position\n ? createPortal(\n <div\n ref={cardRef}\n className=\"be-link-hover-card\"\n contentEditable={false}\n style={{ position: 'fixed', top: position.top, left: position.left }}\n onMouseEnter={clearHideTimer}\n onMouseLeave={scheduleHide}\n >\n <a\n className=\"be-link-hover-card-url\"\n href={link.href}\n target={link.target === '_blank' ? '_blank' : '_self'}\n rel=\"noopener noreferrer\"\n >\n {link.href}\n </a>\n <button type=\"button\" className=\"be-link-hover-card-btn\" onClick={openModal} aria-label=\"Edit link\" title=\"Edit link\">\n <PencilIcon size={13} />\n </button>\n <button\n type=\"button\"\n className=\"be-link-hover-card-btn\"\n onClick={removeLink}\n aria-label=\"Remove link\"\n title=\"Remove link\"\n >\n <XIcon size={13} />\n </button>\n </div>,\n document.body,\n )\n : null}\n <LinkEditModal\n isOpen={isModalOpen}\n initialHref={link?.href ?? ''}\n initialTarget={link?.target ?? '_self'}\n hasExistingLink={Boolean(link)}\n onSave={saveLink}\n onRemove={removeLink}\n onClose={closeModal}\n />\n </>\n );\n}\n","import { XIcon } from './icons.jsx';\n\n/** Shared title + close-button row for both CommentPopover (viewing existing threads) and FloatingToolbar's standalone \"Add comment\" composer -- one small header, not duplicated markup in each. */\nexport function CommentPopoverHeader({ title, onClose }) {\n return (\n <div className=\"be-comment-popover-header\">\n <span className=\"be-comment-popover-title\">{title}</span>\n <button type=\"button\" className=\"be-comment-popover-close\" onClick={onClose} aria-label=\"Close\">\n <XIcon size={14} />\n </button>\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useAutoAdjustedPosition } from './useAutoAdjustedPosition.js';\nimport { CommentThreadCard } from './CommentThreadCard.jsx';\nimport { CommentPopoverHeader } from './CommentPopoverHeader.jsx';\nimport { useHoveredComment } from './EditorProvider.jsx';\n\n/**\n * The click-or-hover popover for VIEWING/replying to/resolving/deleting an\n * EXISTING comment thread over highlighted text (`.be-comment-highlight`,\n * see commentMarks.js) — the read/react counterpart to FloatingToolbar's\n * Comment button, which only handles *creating* a new comment over a fresh\n * selection. Mirrors LinkHoverCard's exact hover-card mechanism (same\n * container-level mouseover/mouseout listening, same hide-timer dance,\n * mounted the same way in EditableBlockContent.jsx) but additionally opens\n * (and stays open, \"pinned\") on a plain click, since a comment is more often\n * something you deliberately open than glance at in passing.\n *\n * A run can carry more than one `commentIds` entry (overlapping comments) —\n * every thread attached to the clicked/hovered run is shown, stacked,\n * inside one popover.\n */\nexport function CommentPopover({ containerRef, store, authorId }) {\n const [target, setTarget] = useState(null); // { rect, commentIds } | null\n const [pinned, setPinned] = useState(false);\n const hideTimerRef = useRef(null);\n const popoverRef = useRef(null);\n const [, setHoveredCommentId] = useHoveredComment();\n\n const clearHideTimer = useCallback(() => {\n if (hideTimerRef.current) {\n clearTimeout(hideTimerRef.current);\n hideTimerRef.current = null;\n }\n }, []);\n\n const scheduleHide = useCallback(() => {\n clearHideTimer();\n hideTimerRef.current = setTimeout(() => {\n setTarget((prev) => (pinned ? prev : null));\n }, 250);\n }, [clearHideTimer, pinned]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return undefined;\n\n const findCommentRun = (el) => {\n const runEl = el?.closest?.('[data-run-id]');\n if (!runEl || !container.contains(runEl)) return null;\n const commentIds = store.getRun(runEl.dataset.runId)?.marks?.commentIds;\n if (!commentIds?.length) return null;\n return { runEl, commentIds };\n };\n\n const handleMouseOver = (event) => {\n const found = findCommentRun(event.target);\n if (!found) return;\n clearHideTimer();\n setTarget((prev) =>\n prev && prev.runEl === found.runEl ? prev : { rect: found.runEl.getBoundingClientRect(), commentIds: found.commentIds, runEl: found.runEl },\n );\n };\n const handleMouseOut = () => scheduleHide();\n\n const handleClick = (event) => {\n const found = findCommentRun(event.target);\n if (!found) {\n setPinned(false);\n setTarget(null);\n return;\n }\n clearHideTimer();\n setPinned(true);\n setTarget({ rect: found.runEl.getBoundingClientRect(), commentIds: found.commentIds, runEl: found.runEl });\n };\n\n container.addEventListener('mouseover', handleMouseOver);\n container.addEventListener('mouseout', handleMouseOut);\n container.addEventListener('click', handleClick);\n return () => {\n container.removeEventListener('mouseover', handleMouseOver);\n container.removeEventListener('mouseout', handleMouseOut);\n container.removeEventListener('click', handleClick);\n };\n }, [containerRef, store, clearHideTimer, scheduleHide]);\n\n // Outside-click / Escape closes a pinned (click-opened) popover -- a\n // click landing inside the popover itself (portaled to document.body, so\n // outside `container`) doesn't count as \"outside\".\n useEffect(() => {\n if (!target) return undefined;\n const handlePointerDown = (event) => {\n if (popoverRef.current?.contains(event.target)) return;\n if (containerRef.current?.contains(event.target)) return; // handled by handleClick above\n setPinned(false);\n setTarget(null);\n };\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') {\n setPinned(false);\n setTarget(null);\n }\n };\n document.addEventListener('mousedown', handlePointerDown);\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('mousedown', handlePointerDown);\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [target, containerRef]);\n\n useEffect(() => () => clearHideTimer(), [clearHideTimer]);\n\n // Echoes onto the matching thread card in the panel, if one's rendered --\n // see useHoveredComment.\n useEffect(() => {\n setHoveredCommentId(target?.commentIds?.[0] ?? null);\n }, [target, setHoveredCommentId]);\n\n const closePopover = useCallback(() => {\n setPinned(false);\n setTarget(null);\n }, []);\n\n const isOpen = Boolean(target);\n const position = useAutoAdjustedPosition(popoverRef, isOpen, target ? target.rect.bottom + 6 : null, target ? target.rect.left : null);\n\n if (!isOpen || !position) return null;\n\n const threads = target.commentIds.map((id) => store.getComment(id)).filter(Boolean);\n if (threads.length === 0) return null;\n\n return createPortal(\n <div\n ref={popoverRef}\n className=\"be-comment-popover\"\n contentEditable={false}\n style={{ position: 'fixed', top: position.top, left: position.left }}\n onMouseEnter={clearHideTimer}\n onMouseLeave={scheduleHide}\n >\n <CommentPopoverHeader title={`Comments (${threads.length})`} onClose={closePopover} />\n {threads.map((thread) => (\n <CommentThreadCard key={thread.id} store={store} thread={thread} authorId={authorId} />\n ))}\n </div>,\n document.body,\n );\n}\n","import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { useEditorStore, useInlineRegistry, useSelectedBlock, useCommentAuthorId, useHoveredComment } from './EditorProvider.jsx';\r\nimport { useRun } from './useBlock.js';\r\nimport { updateRun, setBlockRuns, removeBlock } from '../store/operations.js';\r\nimport { reconcileDomToRuns, EMPTY_RUN_PLACEHOLDER, stripEmptyRunPlaceholder } from './domRunSync.js';\r\nimport { isRunBlank, isRunsEmpty } from '../blocks/shared/blockEmpty.js';\r\nimport { isContentlessBlock } from '../blocks/shared/contentless.js';\r\nimport { genId } from '../utils/idGen.js';\r\nimport { focusRunEnd, focusRunStart } from './focusRun.js';\r\nimport { LinkHoverCard } from './LinkHoverCard.jsx';\r\nimport { CommentPopover } from './CommentPopover.jsx';\r\n\r\n/**\r\n * Keeps the block wrapper's data-empty attribute (see the be-*[data-empty]\r\n * placeholder CSS) in sync on every keystroke — not just on structural\r\n * changes. Ordinary typing goes through the \"onlyValueChanges\" fast path in\r\n * handleInput below, which applies a plain updateRun op that only notifies\r\n * that *run's* own subscribers (see EditorStore's UPDATE_RUN case) — the\r\n * block itself never re-renders, by design, so it can't recompute this\r\n * itself from a React render the way its *initial* data-empty value is set.\r\n * Written directly onto containerRef.current.parentElement — always the block's\r\n * own wrapper element (the div/h-tag every ParagraphBlock/HeadingBlock/\r\n * ListItemBlock renders EditableBlockContent directly inside of) — gated on\r\n * data-placeholder so this is a no-op for block types (table cells) that\r\n * don't opt into the placeholder hint at all.\r\n */\r\nfunction syncEmptyAttr(container, runs) {\r\n const wrapper = container?.parentElement;\r\n if (!wrapper || !wrapper.hasAttribute('data-placeholder')) return;\r\n const isEmpty = runs.length === 0 || runs.every(isRunBlank);\r\n if (isEmpty) wrapper.setAttribute('data-empty', '');\r\n else wrapper.removeAttribute('data-empty');\r\n}\r\n\r\nfunction marksToStyle(marks = {}) {\r\n return {\r\n fontWeight: marks.bold ? 'bold' : undefined,\r\n fontStyle: marks.italic ? 'italic' : undefined,\r\n textDecoration:\r\n [(marks.underline || marks.link) && 'underline', marks.strike && 'line-through'].filter(Boolean).join(' ') || undefined,\r\n verticalAlign: marks.subscript ? 'sub' : marks.superscript ? 'super' : undefined,\r\n fontSize: marks.subscript || marks.superscript ? 'smaller' : undefined,\r\n color: marks.color || (marks.link ? 'var(--noteloom-accent)' : undefined),\r\n backgroundColor: marks.highlight || undefined,\r\n cursor: marks.link ? 'pointer' : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Syncs one text run's value/marks onto a `host` DOM element that\r\n * `EditableBlockContent` created and owns imperatively (see hostsRef/\r\n * getOrCreateHost below) — this component renders no DOM of its own\r\n * (`return null`); it only ever writes into `host` via a layout effect,\r\n * the same \"only touch the DOM if it actually differs\" discipline the old\r\n * EditableRun used.\r\n *\r\n * Subscribes to its own run via useRun (not a prop pre-resolved by the\r\n * parent) so an *external* value change — undo/redo, a future\r\n * collaborator's edit — still triggers a re-render and gets synced to the\r\n * DOM. Local typing bypasses this entirely: the browser mutates the text\r\n * node directly, `EditableBlockContent`'s input handler writes the same\r\n * value back into the store, and this sync then sees the DOM (once the\r\n * placeholder is stripped) already matches and does nothing.\r\n *\r\n * Critical: the comparison below is against the *stripped* DOM text, not\r\n * the raw text. `host.textContent = ...` always destroys and recreates the\r\n * underlying Text node, which resets/collapses the browser's active\r\n * Selection — comparing raw text (including the placeholder) meant every\r\n * empty-to-non-empty transition triggered a \"cleanup\" write that looked\r\n * harmless but silently reset the caret to the start of the run right\r\n * after the very first keystroke. Comparing stripped text means ordinary\r\n * typing — where the DOM already holds the right characters plus a leftover\r\n * placeholder byte — is a true no-op, so the caret is never touched.\r\n *\r\n * The rewrite itself (`setHostText` below) still has to happen on the\r\n * *opposite* transition — real content backspaced down to nothing — since a\r\n * host with zero children isn't a valid caret anchor either. But that write\r\n * mutates the existing Text node's own `.nodeValue` in place instead of\r\n * going through `host.textContent = ...` whenever a reusable node is\r\n * already there: a Range/Selection stays anchored to a Text node across a\r\n * `.nodeValue` change (same node, new data), but `textContent =` always\r\n * discards the old node and creates a new one, silently collapsing any\r\n * Selection that pointed into it. Continuously holding Backspace across a\r\n * whole run hits exactly this transition once, right as the run empties\r\n * out — on desktop a collapsed Selection is barely noticeable, but a mobile\r\n * on-screen keyboard treats the same momentary loss as \"the field lost\r\n * focus\" and dismisses itself, which is what this specifically fixes.\r\n */\r\nfunction setHostText(host, displayValue) {\r\n const onlyChild = host.childNodes.length === 1 ? host.firstChild : null;\r\n if (onlyChild && onlyChild.nodeType === 3) {\r\n if (onlyChild.nodeValue !== displayValue) onlyChild.nodeValue = displayValue;\r\n } else {\r\n host.textContent = displayValue;\r\n }\r\n}\r\n\r\nfunction TextRunSpan({ id, host, onValueSynced }) {\r\n const run = useRun(id);\r\n const [hoveredCommentId] = useHoveredComment();\r\n\r\n useLayoutEffect(() => {\r\n if (!host || !run) return;\r\n const value = run.value ?? '';\r\n const currentLogicalText = stripEmptyRunPlaceholder(host.textContent);\r\n const needsRewrite = currentLogicalText !== value || (value === '' && host.textContent === '');\r\n if (needsRewrite) {\r\n setHostText(host, value === '' ? EMPTY_RUN_PLACEHOLDER : value);\r\n }\r\n\r\n const style = marksToStyle(run.marks);\r\n host.style.fontWeight = style.fontWeight ?? '';\r\n host.style.fontStyle = style.fontStyle ?? '';\r\n host.style.textDecoration = style.textDecoration ?? '';\r\n host.style.verticalAlign = style.verticalAlign ?? '';\r\n host.style.fontSize = style.fontSize ?? '';\r\n host.style.color = style.color ?? '';\r\n host.style.backgroundColor = style.backgroundColor ?? '';\r\n host.style.cursor = style.cursor ?? '';\r\n\r\n // Comment-highlight is a plain CSS class (not an inline style, unlike\r\n // every mark above) since it's a presence/absence toggle with no\r\n // per-comment value to compute -- see src/comments/commentMarks.js for\r\n // how `marks.commentIds` gets populated.\r\n host.classList.toggle('be-comment-highlight', (run.marks?.commentIds?.length ?? 0) > 0);\r\n // Echoes a hover from the comment panel/popover back onto the text --\r\n // see useHoveredComment.\r\n host.classList.toggle('be-comment-highlight-active', Boolean(hoveredCommentId) && Boolean(run.marks?.commentIds?.includes(hoveredCommentId)));\r\n\r\n // A link mark is a *style*, not a real <a> — the host is always a plain\r\n // <span> (created once, before any run's marks are known; see\r\n // getOrCreateHost), so navigation is opt-in via Ctrl/Cmd+click rather\r\n // than a native anchor, matching most rich text editors: a plain click\r\n // still just places the caret for editing.\r\n const link = run.marks?.link;\r\n host.title = link?.href ? `${link.href} — Ctrl+Click to open` : '';\r\n host.onclick = link?.href\r\n ? (event) => {\r\n if (!event.ctrlKey && !event.metaKey) return;\r\n event.preventDefault();\r\n window.open(link.href, link.target === '_blank' ? '_blank' : '_self', 'noopener,noreferrer');\r\n }\r\n : null;\r\n\r\n // Covers value changes this component didn't cause itself — undo/redo,\r\n // a future collaborator's edit — which only notify this *run's* own\r\n // subscribers (see EditorStore's UPDATE_RUN case), never the block's.\r\n // Ordinary typing is already covered by handleInput's own call to\r\n // syncEmptyAttr; this makes every other path to a run's value changing\r\n // keep the placeholder hint in sync too.\r\n onValueSynced?.();\r\n }, [host, run, onValueSynced, hoveredCommentId]);\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * When the collapsed caret sits right at the boundary between a text run\r\n * and an atomic (contentEditable={false}) inline chip, native Backspace/\r\n * Delete would have the *browser* rip that chip's DOM node out on its own —\r\n * before React ever finds out. React's fiber tree still expects that node\r\n * to be there, so the next commit's `removeChild` throws\r\n * (\"NotFoundError: ... not a child of this node\"). The fix is to never let\r\n * the browser touch an atomic node's DOM directly: detect the adjacency\r\n * here, `preventDefault`, and delete the run purely through the store so\r\n * React's own reconciliation is the only thing that ever removes that DOM\r\n * node.\r\n *\r\n * Deliberately does NOT use `previousElementSibling`/`nextElementSibling` to\r\n * decide whether the neighbor is atomic — holding Backspace/Delete down\r\n * fires keydowns faster than React necessarily commits the previous\r\n * removal's DOM update, so a chip that's already gone from the *logical*\r\n * run list can still be physically sitting in the DOM for one more event.\r\n * Trusting that lingering DOM node re-triggered a second delete of an\r\n * already-deleted run and reproduced the same crash intermittently. `runIds`\r\n * (the block's current prop, always in sync with the store) and `getRun`\r\n * are the source of truth for \"what's adjacent and is it atomic\"; the DOM\r\n * is only used to find which run the caret currently sits in.\r\n */\r\nfunction findAdjacentAtomicRunId(containerEl, runIds, getRun, backward) {\r\n const selection = window.getSelection?.();\r\n if (!selection || !selection.isCollapsed || selection.rangeCount === 0) return null;\r\n const { anchorNode, anchorOffset } = selection;\r\n if (!anchorNode || !containerEl.contains(anchorNode)) return null;\r\n\r\n const neighborAtomicId = (caretRunId) => {\r\n const idx = runIds.indexOf(caretRunId);\r\n if (idx === -1) return null; // caret's run already isn't in the current logical model\r\n const neighborId = backward ? runIds[idx - 1] : runIds[idx + 1];\r\n if (!neighborId) return null;\r\n const neighborRun = getRun(neighborId);\r\n return neighborRun && neighborRun.type !== 'text' ? neighborId : null;\r\n };\r\n\r\n // Some browsers select an atomic island as a whole unit, anchoring the\r\n // caret on the container itself with a child-index offset rather than\r\n // inside an adjacent text node.\r\n if (anchorNode === containerEl) {\r\n const idx = backward ? anchorOffset - 1 : anchorOffset;\r\n const child = containerEl.childNodes[idx];\r\n const runId = child?.nodeType === 1 ? child.dataset?.runId : undefined;\r\n if (!runId || runIds.indexOf(runId) === -1) return null;\r\n const run = getRun(runId);\r\n return run && run.type !== 'text' ? runId : null;\r\n }\r\n\r\n const el = anchorNode.nodeType === 1 ? anchorNode : anchorNode.parentElement;\r\n const runEl = el?.closest?.('[data-run-id]');\r\n if (!runEl || !containerEl.contains(runEl)) return null;\r\n\r\n const atBoundary = backward ? anchorOffset === 0 : anchorOffset === (anchorNode.textContent ?? '').length;\r\n if (!atBoundary) return null;\r\n\r\n return neighborAtomicId(runEl.getAttribute('data-run-id'));\r\n}\r\n\r\n/**\r\n * Real browsers frequently turn arrow-key navigation past an atomic\r\n * `contentEditable={false}` island into a *non-collapsed* \"select this one\r\n * node as a unit\" selection (the same way an `<img>` gets selected as a\r\n * whole), rather than leaving a collapsed caret beside it — this is common\r\n * on ArrowLeft/ArrowRight approach and on click. `findAdjacentAtomicRunId`\r\n * only handles the collapsed-caret case; without this check, Backspace/\r\n * Delete on a whole-node selection falls through to native deletion and\r\n * reproduces the exact same removeChild crash it was meant to prevent.\r\n *\r\n * Same rapid-repeat-keydown caution as findAdjacentAtomicRunId: confirm the\r\n * selected node's run id is still in `runIds` before trusting it.\r\n */\r\nfunction findWhollySelectedAtomicRunId(containerEl, runIds, getRun) {\r\n const selection = window.getSelection?.();\r\n if (!selection || selection.isCollapsed || selection.rangeCount === 0) return null;\r\n const range = selection.getRangeAt(0);\r\n if (range.startContainer !== range.endContainer) return null;\r\n if (!containerEl.contains(range.startContainer)) return null;\r\n if (range.endOffset !== range.startOffset + 1) return null;\r\n\r\n const child = range.startContainer.childNodes[range.startOffset];\r\n const runId = child?.nodeType === 1 ? child.dataset?.runId : undefined;\r\n if (!runId || runIds.indexOf(runId) === -1) return null;\r\n const run = getRun(runId);\r\n return run && run.type !== 'text' ? runId : null;\r\n}\r\n\r\n/**\r\n * Resolves a Range/StaticRange boundary point to \"which child of\r\n * containerEl does it fall in, and at what character offset\" — the common\r\n * currency computeRunsAfterRangeDeletion needs for both boundaries,\r\n * regardless of whether the point addresses a run's text node directly or\r\n * the container itself (the same child-index addressing style seen in\r\n * findAdjacentAtomicRunId/findWhollySelectedAtomicRunId for whole-node\r\n * selections). Returns null if the point isn't inside any known run.\r\n */\r\nfunction resolveRangeBoundary(containerEl, node, offset) {\r\n if (node === containerEl) return { childIndex: offset, charOffset: null };\r\n const el = node.nodeType === 1 ? node : node.parentElement;\r\n const runEl = el?.closest?.('[data-run-id]');\r\n if (!runEl || !containerEl.contains(runEl)) return null;\r\n const childIndex = Array.prototype.indexOf.call(containerEl.childNodes, runEl);\r\n const charOffset = node === runEl ? (offset === 0 ? 0 : (runEl.textContent ?? '').length) : offset;\r\n return { childIndex, charOffset };\r\n}\r\n\r\n/**\r\n * Typing a replacement character (or composing, or a word/line/cut\r\n * deletion) over a selection that spans or fully covers an atomic chip\r\n * goes through `beforeinput`, not a Backspace/Delete keydown — so it's a\r\n * completely different native-DOM-mutation path than the one\r\n * findAdjacentAtomicRunId/findWhollySelectedAtomicRunId guard, and hits the\r\n * exact same removeChild crash if left to native handling. This computes\r\n * the resulting run list ourselves for any range that touches at least one\r\n * atomic run, so the caller can preventDefault and apply it through the\r\n * store instead. Returns null when the range doesn't touch any atomic run\r\n * at all, so ordinary text edits are completely unaffected — no change in\r\n * behavior, no new failure mode, for the common case.\r\n */\r\nfunction computeRunsAfterRangeDeletion(containerEl, runIds, getRun, range) {\r\n const start = resolveRangeBoundary(containerEl, range.startContainer, range.startOffset);\r\n const end = resolveRangeBoundary(containerEl, range.endContainer, range.endOffset);\r\n if (!start || !end) return null;\r\n\r\n const children = Array.from(containerEl.childNodes).filter(\r\n (n) => n.nodeType === 1 && n.dataset?.runId && runIds.indexOf(n.dataset.runId) !== -1,\r\n );\r\n\r\n let touchesAtomic = false;\r\n const nextRuns = [];\r\n let insertionIndex = null;\r\n\r\n children.forEach((child, i) => {\r\n const runId = child.dataset.runId;\r\n const run = getRun(runId);\r\n if (!run) return;\r\n\r\n const beforeStart = i < start.childIndex;\r\n const afterEnd = end.charOffset === null ? i >= end.childIndex : i > end.childIndex;\r\n\r\n if (beforeStart || afterEnd) {\r\n nextRuns.push(run);\r\n return;\r\n }\r\n\r\n const isStartChild = start.charOffset !== null && i === start.childIndex;\r\n const isEndChild = end.charOffset !== null && i === end.childIndex;\r\n\r\n if (run.type !== 'text') {\r\n touchesAtomic = true;\r\n if (insertionIndex === null) insertionIndex = nextRuns.length;\r\n return; // atomic run fully consumed by the range: dropped\r\n }\r\n\r\n const value = run.value ?? '';\r\n if (isStartChild && isEndChild) {\r\n const survivor = value.slice(0, start.charOffset) + value.slice(end.charOffset);\r\n if (survivor) nextRuns.push({ ...run, value: survivor });\r\n insertionIndex = nextRuns.length;\r\n } else if (isStartChild) {\r\n const prefix = value.slice(0, start.charOffset);\r\n if (prefix) nextRuns.push({ ...run, value: prefix });\r\n if (insertionIndex === null) insertionIndex = nextRuns.length;\r\n } else if (isEndChild) {\r\n const suffix = value.slice(end.charOffset);\r\n if (suffix) nextRuns.push({ id: genId(), type: 'text', value: suffix, marks: run.marks });\r\n }\r\n // else: fully inside the range, dropped entirely\r\n });\r\n\r\n if (!touchesAtomic) return null;\r\n return { nextRuns, insertionIndex: insertionIndex ?? nextRuns.length };\r\n}\r\n\r\n/** Caret is collapsed and sits at the very first text position of the container's first child. */\r\nfunction isCaretAtContainerStart(containerEl) {\r\n const selection = window.getSelection?.();\r\n if (!selection || !selection.isCollapsed) return false;\r\n const firstChild = containerEl.firstChild;\r\n if (!firstChild) return true;\r\n\r\n if (selection.anchorNode === containerEl) return selection.anchorOffset === 0;\r\n\r\n let probe = firstChild;\r\n while (probe && probe.firstChild) probe = probe.firstChild;\r\n if (selection.anchorNode !== probe && selection.anchorNode !== firstChild) return false;\r\n\r\n // A first run that's still just the placeholder has no real content yet,\r\n // so any caret position within it (offset 0 or 1) counts as \"at start\".\r\n const maxStartOffset = probe.nodeType === 3 && probe.textContent === EMPTY_RUN_PLACEHOLDER ? 1 : 0;\r\n return selection.anchorOffset <= maxStartOffset;\r\n}\r\n\r\n/** Symmetric to isCaretAtContainerStart: caret is collapsed at the very last text position of the container's last child. */\r\nfunction isCaretAtContainerEnd(containerEl) {\r\n const selection = window.getSelection?.();\r\n if (!selection || !selection.isCollapsed) return false;\r\n const lastChild = containerEl.lastChild;\r\n if (!lastChild) return true;\r\n\r\n if (selection.anchorNode === containerEl) return selection.anchorOffset >= containerEl.childNodes.length;\r\n\r\n let probe = lastChild;\r\n while (probe && probe.lastChild) probe = probe.lastChild;\r\n if (selection.anchorNode !== probe && selection.anchorNode !== lastChild) return false;\r\n\r\n const textLength = probe.nodeType === 3 ? (probe.textContent ?? '').length : 0;\r\n return selection.anchorOffset >= textLength;\r\n}\r\n\r\n/**\r\n * Resolves the sibling of `blockId` in `direction` ('backward' | 'forward')\r\n * only if it's a non-editable/contentless block (image/video/audio/file\r\n * embed, divider, ...) — a real leaf/container with actual content returns\r\n * null here, since Backspace/Delete into *that* is ordinary merge/no-op\r\n * territory (handled by onBackspaceAtStart), not this select-then-delete\r\n * flow.\r\n */\r\nfunction findAdjacentContentlessSiblingId(store, blockId, direction) {\r\n const block = store.getBlock(blockId);\r\n const parent = store.getBlock(block?.parentId);\r\n if (!parent) return null;\r\n const index = parent.contentIds.indexOf(blockId);\r\n const adjacentIndex = direction === 'backward' ? index - 1 : index + 1;\r\n if (adjacentIndex < 0 || adjacentIndex >= parent.contentIds.length) return null;\r\n const adjacentId = parent.contentIds[adjacentIndex];\r\n return isContentlessBlock(store, store.getBlock(adjacentId)) ? adjacentId : null;\r\n}\r\n\r\n/**\r\n * Dispatches one run's id to the right renderer: TextRunSpan for text, the\r\n * inline registry's component otherwise. Also passes `blockId` (the\r\n * containing leaf block — a paragraph, or a table cell) down to atomic\r\n * components — runs themselves have no parent back-reference in the store,\r\n * so this is the only place that can hand it to them. Most inline types\r\n * ignore it (select/date/custom field types are self-contained); it exists for types\r\n * like a table's select column that need to resolve their own containing\r\n * cell/row/table to read shared, column-level state.\r\n */\r\nfunction RunNode({ id, blockId, host, inlineRegistry, onValueSynced }) {\r\n const run = useRun(id);\r\n if (!run) return null;\r\n if (run.type === 'text') return <TextRunSpan id={id} host={host} onValueSynced={onValueSynced} />;\r\n\r\n const entry = inlineRegistry?.get(run.type);\r\n if (!entry) {\r\n if (process.env.NODE_ENV !== 'production') {\r\n // eslint-disable-next-line no-console\r\n console.warn(`[block-editor] No inline type registered for \"${run.type}\" (run: ${id})`);\r\n }\r\n return null;\r\n }\r\n const Component = entry.component;\r\n return <Component id={id} blockId={blockId} />;\r\n}\r\n\r\n/**\r\n * Creates (once) or reuses the persistent DOM element that hosts one run's\r\n * content — `data-run-id`, and for atomic (non-text) runs `contentEditable=\r\n * \"false\"`, live on this element, not on anything React renders into it.\r\n * The host is looked up directly from the store (not the `useRun` hook)\r\n * because this only needs to run once per id, at creation time — a run's\r\n * type never changes after creation (a semantic change always creates a\r\n * new run with a new id elsewhere in this codebase), so there's nothing to\r\n * keep reactive here.\r\n */\r\nfunction getOrCreateHost(hostsMap, store, id) {\r\n let host = hostsMap.get(id);\r\n if (!host) {\r\n host = document.createElement('span');\r\n host.dataset.runId = id;\r\n const run = store.getRun(id);\r\n if (run && run.type !== 'text') host.setAttribute('contenteditable', 'false');\r\n hostsMap.set(id, host);\r\n }\r\n return host;\r\n}\r\n\r\n/**\r\n * Renders every run of a leaf block (paragraph/heading/tableCell's own\r\n * contentIds, or a listItem's props.titleRunIds) inside ONE shared\r\n * contentEditable region — replacing the old one-contentEditable-per-run\r\n * model. This is what lets the browser's native selection/typing/cursor\r\n * movement work across formatting boundaries and atomic inline elements\r\n * (a select/date chip), instead of each run being its own disconnected\r\n * editable island.\r\n *\r\n * Every run — text or atomic — gets a persistent \"host\" DOM element that\r\n * *this component creates, positions, and removes imperatively* (see\r\n * hostsRef/getOrCreateHost and the layout effect below); React only ever\r\n * renders each run's *content* into its host via `createPortal`. React's\r\n * own fiber tree therefore never owns the operation of inserting or\r\n * removing a run's DOM node relative to its siblings — that's the same\r\n * technique Lexical uses for its \"decorator\" nodes. It's what closes the\r\n * \"NotFoundError: removeChild ... not a child of this node\" crash for\r\n * good: that error was always React's commit phase trying to remove a\r\n * host node the *browser* had already ripped out natively (via Backspace/\r\n * Delete, typing over a selection, word-delete, autocorrect, IME, drag —\r\n * there is no finite list of native paths that can do this). Since React\r\n * no longer has a fiber responsible for that removal at all, no native\r\n * mutation of a run's DOM node can ever race against — or be duplicated\r\n * by — a React-driven one.\r\n *\r\n * `runIds` must come from the caller's own `useBlock` subscription\r\n * (block.contentIds for paragraph/heading/tableCell, or\r\n * block.props.titleRunIds for a listItem) — that's what keeps this\r\n * component reactive to *structural* changes (e.g. a mark-toggle split),\r\n * while each individual run's *value* reactivity is owned by RunNode/\r\n * TextRunSpan subscribing to that one run id themselves.\r\n */\r\nexport function EditableBlockContent({\r\n blockId,\r\n runIds,\r\n dir = 'auto',\r\n onEnter,\r\n onBackspaceAtStart,\r\n onDeleteAtEnd,\r\n onArrowUp,\r\n onArrowDown,\r\n onTab,\r\n onShiftTab,\r\n onAutoformat,\r\n}) {\r\n const store = useEditorStore();\r\n const inlineRegistry = useInlineRegistry();\r\n const commentAuthorId = useCommentAuthorId();\r\n const { getSelectedBlockId, setSelectedBlockId } = useSelectedBlock();\r\n const containerRef = useRef(null);\r\n // IME composition (CJK/Korean/etc.) produces a sequence of transient,\r\n // uncommitted `input` events while the user is still choosing characters.\r\n // Reconciling — and possibly rewriting DOM text — mid-composition would\r\n // fight the browser/OS IME UI and can cut a composition session short.\r\n // Defer reconciliation until compositionend commits the final text.\r\n const isComposingRef = useRef(false);\r\n const hostsRef = useRef(new Map()); // runId -> persistent host DOM element (see getOrCreateHost)\r\n\r\n // Keeps containerRef's *actual* DOM children (the hosts) in the same\r\n // membership/order as runIds — the only place any run's DOM node is ever\r\n // inserted or removed. Runs on every runIds change (structural edits:\r\n // insert/remove/reorder/split); ordinary text edits don't change runIds\r\n // at all, so this doesn't run on every keystroke.\r\n useLayoutEffect(() => {\r\n const container = containerRef.current;\r\n if (!container) return;\r\n\r\n const liveIds = new Set(runIds);\r\n for (const [id, host] of hostsRef.current) {\r\n if (!liveIds.has(id)) {\r\n host.remove();\r\n hostsRef.current.delete(id);\r\n }\r\n }\r\n\r\n let previous = null;\r\n for (const id of runIds) {\r\n const host = hostsRef.current.get(id);\r\n if (!host) continue; // created synchronously during render, in the map already\r\n const expectedNext = previous ? previous.nextSibling : container.firstChild;\r\n if (expectedNext !== host) container.insertBefore(host, expectedNext);\r\n previous = host;\r\n }\r\n }, [runIds]);\r\n\r\n const handleInput = useCallback(() => {\r\n if (isComposingRef.current) return;\r\n const container = containerRef.current;\r\n if (!container) return;\r\n const currentRuns = runIds.map((id) => store.getRun(id)).filter(Boolean);\r\n const { runs: nextRuns, changed, onlyValueChanges } = reconcileDomToRuns(container, currentRuns);\r\n if (!changed) return;\r\n\r\n if (onlyValueChanges) {\r\n nextRuns.forEach((run, i) => {\r\n if (run !== currentRuns[i]) store.applyOperation(updateRun(run.id, { value: run.value }));\r\n });\r\n // A markdown shortcut (e.g. \"1. \" -> ordered list) always types into a\r\n // single existing run, never a structural DOM change, so it only ever\r\n // applies on this branch. On a match, blockId's block was just\r\n // replaced by a different type — the container/wrapper this callback\r\n // is running inside of is about to unmount, so there's nothing left\r\n // here to sync.\r\n if (onAutoformat?.(nextRuns)) return;\r\n } else {\r\n // Same \"never zero runs\" guard as removeRun — belt-and-suspenders,\r\n // since reconcileDomToRuns normally never drops a matched run.\r\n store.applyOperation(\r\n setBlockRuns(blockId, nextRuns.length ? nextRuns : [{ id: genId(), type: 'text', value: '', marks: {} }]),\r\n );\r\n }\r\n syncEmptyAttr(container, nextRuns);\r\n }, [store, blockId, runIds, onAutoformat]);\r\n\r\n const syncEmptyFromStore = useCallback(() => {\r\n syncEmptyAttr(\r\n containerRef.current,\r\n runIds.map((id) => store.getRun(id)).filter(Boolean),\r\n );\r\n }, [store, runIds]);\r\n\r\n const handleCompositionStart = useCallback(() => {\r\n isComposingRef.current = true;\r\n }, []);\r\n\r\n const handleCompositionEnd = useCallback(() => {\r\n isComposingRef.current = false;\r\n handleInput(); // reconcile now that the composed text has been committed\r\n }, [handleInput]);\r\n\r\n const removeRun = useCallback(\r\n (runId) => {\r\n const currentRuns = runIds.map((id) => store.getRun(id)).filter(Boolean);\r\n const nextRuns = currentRuns.filter((run) => run.id !== runId);\r\n // Never leave the block with zero runs: an empty contentEditable\r\n // region (no children at all) isn't a valid caret anchor in most\r\n // browsers, so the very next keystroke lands on the *container*\r\n // instead of any run, producing a stray untracked text node that\r\n // reconcileDomToRuns can't ever match back to an existing run —\r\n // every keystroke after that mints a brand new run+host instead of\r\n // updating one in place (the \"characters double\" bug).\r\n store.applyOperation(\r\n setBlockRuns(blockId, nextRuns.length ? nextRuns : [{ id: genId(), type: 'text', value: '', marks: {} }]),\r\n );\r\n },\r\n [store, blockId, runIds],\r\n );\r\n\r\n /**\r\n * The common convention for a non-editable neighbor (image/video/\r\n * audio/file embed, divider): the first Backspace/Delete that reaches it\r\n * only selects/highlights it (see the be-block-selected class toggled by\r\n * setSelectedBlockId); a second press while it's already selected is\r\n * what actually removes it. Neither press ever touches or refocuses\r\n * *this* block — the caret never moves, since only the neighbor is\r\n * selected or removed, not anything in the block the user is actually\r\n * typing in.\r\n */\r\n const selectOrDeleteContentlessNeighbor = useCallback(\r\n (neighborId) => {\r\n if (getSelectedBlockId() === neighborId) {\r\n store.applyOperation(removeBlock(neighborId));\r\n setSelectedBlockId(null);\r\n } else {\r\n setSelectedBlockId(neighborId);\r\n }\r\n },\r\n [store, getSelectedBlockId, setSelectedBlockId],\r\n );\r\n\r\n /**\r\n * Catches every native content-editable mutation that can rip an atomic\r\n * run's DOM node out directly — not just Backspace/Delete, but typing a\r\n * replacement character over a selection that spans a chip, Ctrl/Cmd+\r\n * Backspace word/line delete, and cut — all of which fire `beforeinput`\r\n * with the exact range about to be affected (`getTargetRanges()`, falling\r\n * back to the live selection where unsupported). When that range touches\r\n * an atomic run, this computes the resulting content itself and applies\r\n * it through the store, so the browser never gets to mutate that node.\r\n * Ordinary text-only edits are untouched: computeRunsAfterRangeDeletion\r\n * returns null for them and this handler is a no-op, leaving the existing\r\n * fast-path onInput reconciliation to handle typing exactly as before.\r\n */\r\n const handleBeforeInput = useCallback(\r\n (event) => {\r\n if (isComposingRef.current) return;\r\n\r\n // A native `beforeinput` (or `input`, elsewhere) fired by a real form\r\n // control nested inside an atomic run's own host (the checkbox\r\n // label's <input>, a date chip's <input type=\"date\">, ...) still\r\n // bubbles up through this contenteditable=true container, even\r\n // though that host is contenteditable=\"false\" and typing into it has\r\n // nothing to do with the surrounding text flow. Left unguarded, the\r\n // fallback to window.getSelection() below can pick up a *stale*\r\n // range still pointing at that atomic run's position from before\r\n // focus moved into its nested control, get misread as \"this range\r\n // touches an atomic run,\" and rewrite it clean out of the block —\r\n // the exact \"typing in the checkbox's label deletes the checkbox\"\r\n // bug this guard closes. That nested control owns its own value via\r\n // its own onChange; this container-level pipeline must stay out of\r\n // it entirely.\r\n if (event.target instanceof Node) {\r\n const el = event.target.nodeType === 1 ? event.target : event.target.parentElement;\r\n if (el?.closest?.('[contenteditable=\"false\"]')) return;\r\n }\r\n\r\n const inputType = event.inputType ?? '';\r\n const isDelete = inputType.startsWith('delete');\r\n const isReplaceTyped = inputType === 'insertText' || inputType === 'insertReplacementText';\r\n if (!isDelete && !isReplaceTyped) return;\r\n\r\n const container = containerRef.current;\r\n if (!container) return;\r\n\r\n const targetRanges = event.getTargetRanges?.();\r\n const selection = window.getSelection?.();\r\n const range = targetRanges?.[0] ?? (selection?.rangeCount ? selection.getRangeAt(0) : null);\r\n if (!range) return;\r\n if (!container.contains(range.startContainer) || !container.contains(range.endContainer)) return;\r\n\r\n const result = computeRunsAfterRangeDeletion(container, runIds, (id) => store.getRun(id), range);\r\n if (!result) return; // no atomic run in range: let native/existing handling proceed unchanged\r\n\r\n event.preventDefault();\r\n let { nextRuns, insertionIndex } = result;\r\n\r\n let focusRunId = null;\r\n let focusAtStart = false;\r\n\r\n if (isReplaceTyped && event.data) {\r\n const typedRun = { id: genId(), type: 'text', value: event.data, marks: {} };\r\n nextRuns = [...nextRuns.slice(0, insertionIndex), typedRun, ...nextRuns.slice(insertionIndex)];\r\n focusRunId = typedRun.id;\r\n focusAtStart = false;\r\n } else if (insertionIndex > 0) {\r\n focusRunId = nextRuns[insertionIndex - 1]?.id;\r\n focusAtStart = false;\r\n } else if (nextRuns.length > 0) {\r\n focusRunId = nextRuns[0].id;\r\n focusAtStart = true;\r\n }\r\n\r\n const finalRuns = nextRuns.length ? nextRuns : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n store.applyOperation(setBlockRuns(blockId, finalRuns));\r\n\r\n const landingRunId = focusRunId ?? finalRuns[0].id;\r\n if (focusAtStart) focusRunStart(landingRunId);\r\n else focusRunEnd(landingRunId);\r\n },\r\n [store, blockId, runIds],\r\n );\r\n\r\n // React's `onBeforeInput` JSX prop does NOT correspond to the native\r\n // `beforeinput` event — it's a legacy pre-InputEvent-spec polyfill\r\n // synthesized from keypress/textInput/composition events, so it never\r\n // fires for Backspace/Delete/word-delete and carries no `inputType` or\r\n // `getTargetRanges()`. Attaching a real native listener directly (same\r\n // pattern useEditorKeyboardShortcuts uses for its own native handling)\r\n // is the only way to actually observe and cancel these before the\r\n // browser mutates an atomic run's DOM node itself.\r\n useEffect(() => {\r\n const container = containerRef.current;\r\n if (!container) return undefined;\r\n container.addEventListener('beforeinput', handleBeforeInput);\r\n return () => container.removeEventListener('beforeinput', handleBeforeInput);\r\n }, [handleBeforeInput]);\r\n\r\n const handleKeyDown = useCallback(\r\n (event) => {\r\n // While composing, Enter/Backspace/arrows are the IME's own candidate-\r\n // selection UI (confirming a suggestion, moving between candidates) —\r\n // must not also trigger this block's own Enter/merge/navigation.\r\n if (isComposingRef.current) return;\r\n\r\n if (event.key === 'Enter' && onEnter) {\r\n event.preventDefault();\r\n onEnter(event);\r\n return;\r\n }\r\n if (event.key === 'Backspace') {\r\n const container = containerRef.current;\r\n const wholeId = container && findWhollySelectedAtomicRunId(container, runIds, store.getRun.bind(store));\r\n if (wholeId) {\r\n event.preventDefault();\r\n removeRun(wholeId);\r\n return;\r\n }\r\n const atomicId = container && findAdjacentAtomicRunId(container, runIds, store.getRun.bind(store), true);\r\n if (atomicId) {\r\n event.preventDefault();\r\n removeRun(atomicId);\r\n return;\r\n }\r\n if (container && isCaretAtContainerStart(container)) {\r\n // Only offer the select-then-delete flow for a non-editable\r\n // neighbor when THIS block still has real content of its own —\r\n // an empty current block (e.g. a trailing blank paragraph right\r\n // after an image) must disappear on its own first, exactly like\r\n // Backspace on any other empty block, before the neighbor is\r\n // offered at all. Otherwise the very first Backspace on an empty\r\n // paragraph would highlight the image instead of removing the\r\n // paragraph, which is backwards. onBackspaceAtStart (the normal\r\n // merge/delete path) handles the empty case, and itself lands on\r\n // selecting the neighbor via focusAfterMerge once there's\r\n // nothing left of the current block to focus back into.\r\n const isCurrentEmpty = isRunsEmpty(store, runIds);\r\n if (!isCurrentEmpty) {\r\n const neighborId = findAdjacentContentlessSiblingId(store, blockId, 'backward');\r\n if (neighborId) {\r\n event.preventDefault();\r\n selectOrDeleteContentlessNeighbor(neighborId);\r\n return;\r\n }\r\n }\r\n // Always claim this keypress once we know it's Backspace-at-\r\n // absolute-start being handled here (native backspace has nothing\r\n // to do at this exact position anyway, so this is a no-op for the\r\n // browser) — this is what lets the global handler in\r\n // useEditorKeyboardShortcuts distinguish \"a neighbor was *just*\r\n // selected as part of *this* keypress\" (defaultPrevented is now\r\n // true, so it must NOT also delete that neighbor on this same\r\n // press) from \"a neighbor was already selected from a *previous*\r\n // keypress\" (a fresh event, defaultPrevented starts false again,\r\n // so the global handler correctly deletes it then).\r\n event.preventDefault();\r\n if (onBackspaceAtStart) onBackspaceAtStart(event);\r\n }\r\n return;\r\n }\r\n if (event.key === 'Delete') {\r\n const container = containerRef.current;\r\n const wholeId = container && findWhollySelectedAtomicRunId(container, runIds, store.getRun.bind(store));\r\n if (wholeId) {\r\n event.preventDefault();\r\n removeRun(wholeId);\r\n return;\r\n }\r\n const atomicId = container && findAdjacentAtomicRunId(container, runIds, store.getRun.bind(store), false);\r\n if (atomicId) {\r\n event.preventDefault();\r\n removeRun(atomicId);\r\n return;\r\n }\r\n if (container && isCaretAtContainerEnd(container)) {\r\n const neighborId = findAdjacentContentlessSiblingId(store, blockId, 'forward');\r\n if (neighborId) {\r\n event.preventDefault();\r\n selectOrDeleteContentlessNeighbor(neighborId);\r\n return;\r\n }\r\n if (onDeleteAtEnd) onDeleteAtEnd(event);\r\n }\r\n return;\r\n }\r\n if (event.key === 'ArrowUp' && onArrowUp) {\r\n event.preventDefault();\r\n onArrowUp(event);\r\n return;\r\n }\r\n if (event.key === 'ArrowDown' && onArrowDown) {\r\n event.preventDefault();\r\n onArrowDown(event);\r\n return;\r\n }\r\n if (event.key === 'Tab') {\r\n if (event.shiftKey && onShiftTab) {\r\n event.preventDefault();\r\n onShiftTab(event);\r\n } else if (!event.shiftKey && onTab) {\r\n event.preventDefault();\r\n onTab(event);\r\n }\r\n }\r\n },\r\n [\r\n onEnter,\r\n onBackspaceAtStart,\r\n onDeleteAtEnd,\r\n onArrowUp,\r\n onArrowDown,\r\n onTab,\r\n onShiftTab,\r\n removeRun,\r\n selectOrDeleteContentlessNeighbor,\r\n runIds,\r\n blockId,\r\n store,\r\n ],\r\n );\r\n\r\n return (\r\n <>\r\n <span\r\n ref={containerRef}\r\n className=\"be-editable\"\r\n dir={dir}\r\n contentEditable\r\n suppressContentEditableWarning\r\n onInput={handleInput}\r\n onCompositionStart={handleCompositionStart}\r\n onCompositionEnd={handleCompositionEnd}\r\n onKeyDown={handleKeyDown}\r\n >\r\n {runIds.map((id) => {\r\n const host = getOrCreateHost(hostsRef.current, store, id);\r\n return createPortal(\r\n <RunNode\r\n key={id}\r\n id={id}\r\n blockId={blockId}\r\n host={host}\r\n inlineRegistry={inlineRegistry}\r\n onValueSynced={syncEmptyFromStore}\r\n />,\r\n host,\r\n );\r\n })}\r\n </span>\r\n <LinkHoverCard containerRef={containerRef} store={store} />\r\n <CommentPopover containerRef={containerRef} store={store} authorId={commentAuthorId} />\r\n </>\r\n );\r\n}\r\n","import { focusRunEnd } from '../../react/focusRun.js';\r\n\r\nfunction adjacentSiblingId(store, blockId, direction) {\r\n const block = store.getBlock(blockId);\r\n const parent = block && store.getBlock(block.parentId);\r\n if (!parent) return null;\r\n const index = parent.contentIds.indexOf(blockId);\r\n const adjacentIndex = direction === 'up' ? index - 1 : index + 1;\r\n if (adjacentIndex < 0 || adjacentIndex >= parent.contentIds.length) return null;\r\n return parent.contentIds[adjacentIndex];\r\n}\r\n\r\n/**\r\n * Resolves which run id should receive focus when moving from `blockId` in\r\n * `direction` ('up' | 'down') — pure logic, no DOM, so it's directly\r\n * testable. When the adjacent sibling is a container with actual content\r\n * (a table with rows, a layout with columns holding blocks), this *enters*\r\n * it — landing in its first cell/child when moving down, or its last when\r\n * moving up — via resolveBlockFirstRun/resolveBlockLastRun. Only a sibling\r\n * with truly nothing focusable at all (a divider, or an empty table with\r\n * zero rows) gets skipped over entirely, continuing the search to the next\r\n * sibling after it.\r\n */\r\nexport function resolveAdjacentFocusTarget(store, blockId, direction) {\r\n let currentId = blockId;\r\n while (true) {\r\n const adjacentId = adjacentSiblingId(store, currentId, direction);\r\n if (!adjacentId) return null;\r\n const runId = direction === 'up' ? resolveBlockLastRun(store, adjacentId) : resolveBlockFirstRun(store, adjacentId);\r\n if (runId) return runId;\r\n currentId = adjacentId; // truly empty (no rows/children at all): keep walking past it\r\n }\r\n}\r\n\r\n/** Moves focus to the nearest focusable sibling block's text in `direction` (see resolveAdjacentFocusTarget). */\r\nexport function focusAdjacentBlock(store, blockId, direction) {\r\n const targetRunId = resolveAdjacentFocusTarget(store, blockId, direction);\r\n if (targetRunId) focusRunEnd(targetRunId);\r\n}\r\n\r\n/**\r\n * Resolves the first directly-focusable run inside `blockId`, descending\r\n * into containers as needed — a leaf's own contentIds/titleRunIds are\r\n * already run ids, but a table's contentIds are row *block* ids (recurse\r\n * into the first row, then its first cell, then that cell's runs), and\r\n * likewise for a layout's columns. Used to focus into a block right after\r\n * it's created (Enter, a slash command), so the caret always lands\r\n * somewhere typeable instead of staying on the block that triggered it.\r\n */\r\nexport function resolveBlockFirstRun(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n if (!block) return null;\r\n const runIds = block.props?.titleRunIds ?? block.contentIds;\r\n if (!runIds || runIds.length === 0) return null;\r\n const firstId = runIds[0];\r\n if (store.getRun(firstId)) return firstId; // a leaf's ids are runs directly\r\n return resolveBlockFirstRun(store, firstId); // a container's ids are child blocks: recurse\r\n}\r\n\r\n/** Moves focus to the first typeable position inside `blockId` (see resolveBlockFirstRun). */\r\nexport function focusBlockStart(store, blockId) {\r\n const runId = resolveBlockFirstRun(store, blockId);\r\n if (runId) focusRunEnd(runId);\r\n}\r\n\r\n/** Symmetric to resolveBlockFirstRun: the last directly-focusable run inside `blockId`, descending into containers' last child. */\r\nexport function resolveBlockLastRun(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n if (!block) return null;\r\n const runIds = block.props?.titleRunIds ?? block.contentIds;\r\n if (!runIds || runIds.length === 0) return null;\r\n const lastId = runIds[runIds.length - 1];\r\n if (store.getRun(lastId)) return lastId;\r\n return resolveBlockLastRun(store, lastId);\r\n}\r\n\r\n/** Moves focus to the last typeable position inside `blockId` (see resolveBlockLastRun). */\r\nexport function focusBlockEnd(store, blockId) {\r\n const runId = resolveBlockLastRun(store, blockId);\r\n if (runId) focusRunEnd(runId);\r\n}\r\n","import { stripEmptyRunPlaceholder } from './domRunSync.js';\r\n\r\n/**\r\n * v1 scope: resolves the native selection only when it's a non-collapsed\r\n * range entirely within one run's single text node — matches the same\r\n * single-run limitation as toggleMarkOnRunRange and the clipboard range\r\n * resolution. Returns null for collapsed selections or ranges spanning\r\n * multiple runs/blocks.\r\n */\r\nexport function resolveRunSelection() {\r\n const selection = window.getSelection?.();\r\n if (!selection || selection.rangeCount === 0) return null;\r\n const range = selection.getRangeAt(0);\r\n if (range.collapsed || range.startContainer !== range.endContainer) return null;\r\n\r\n const container = range.startContainer;\r\n const el = container.nodeType === 1 ? container : container.parentElement;\r\n const runEl = el?.closest?.('[data-run-id]');\r\n if (!runEl) return null;\r\n const blockEl = runEl.closest('[data-block-id]');\r\n if (!blockEl) return null;\r\n\r\n const rawText = container.textContent ?? '';\r\n return {\r\n runId: runEl.getAttribute('data-run-id'),\r\n blockId: blockEl.getAttribute('data-block-id'),\r\n startOffset: stripEmptyRunPlaceholder(rawText.slice(0, range.startOffset)).length,\r\n endOffset: stripEmptyRunPlaceholder(rawText.slice(0, range.endOffset)).length,\r\n };\r\n}\r\n\r\n/**\r\n * Native selection gestures that don't drill into a specific run's text\r\n * node — Ctrl+A \"select all\" within one contentEditable region is the main\r\n * one — anchor directly on the shared contentEditable container instead,\r\n * addressing by child-index rather than character offset. Without this,\r\n * detecting \"the whole current block is already selected\" (the trigger for\r\n * promoting a second Ctrl+A to a whole-document selection) silently fails\r\n * for exactly the selection shape native select-all actually produces.\r\n */\r\nfunction resolveContainerLevelSelection(node, offset) {\r\n if (node?.nodeType !== 1 || node.getAttribute?.('contenteditable') !== 'true') return null;\r\n const children = node.childNodes;\r\n if (children.length === 0) return null;\r\n\r\n const atEnd = offset >= children.length;\r\n const child = children[atEnd ? children.length - 1 : Math.max(0, offset)];\r\n const runId = child?.nodeType === 1 ? child.dataset?.runId : undefined;\r\n if (!runId) return null;\r\n const blockEl = child.closest('[data-block-id]');\r\n if (!blockEl) return null;\r\n\r\n return {\r\n runId,\r\n blockId: blockEl.getAttribute('data-block-id'),\r\n // Raw DOM length, not the logical (placeholder-stripped) length: a run\r\n // that started empty and was later typed into keeps a leftover\r\n // zero-width-space byte in its actual text node forever (see\r\n // TextRunSpan in EditableBlockContent.jsx — never rewritten, to avoid\r\n // resetting the caret on every keystroke), even though run.value itself\r\n // is clean. Using the raw length here would put native select-all's\r\n // offset one character ahead of run.value.length for exactly those\r\n // blocks, which is exactly what silently broke \"is the whole block\r\n // selected\" detection for any block typed into after being created\r\n // empty (slash-menu-created blocks, Enter-split blocks, etc.).\r\n offset: atEnd ? stripEmptyRunPlaceholder(child.textContent ?? '').length : 0,\r\n };\r\n}\r\n\r\nfunction resolveRunAndOffset(node, offset) {\r\n const containerLevel = resolveContainerLevelSelection(node, offset);\r\n if (containerLevel) return containerLevel;\r\n\r\n let el = node?.nodeType === 1 ? node : node?.parentElement;\r\n const runEl = el?.closest?.('[data-run-id]');\r\n if (!runEl) return null;\r\n const blockEl = runEl.closest('[data-block-id]');\r\n if (!blockEl) return null;\r\n\r\n // `offset` is a raw DOM char index when node is the run's own text node;\r\n // when the selection anchors on the run element itself (e.g. an empty/\r\n // atomic island), it's a child-node index instead — convert to a char\r\n // count. Either way, strip any leftover placeholder byte so the result\r\n // lines up with run.value.length (see the matching comment in\r\n // resolveContainerLevelSelection above — same underlying cause).\r\n let charOffset = stripEmptyRunPlaceholder((node.textContent ?? '').slice(0, offset)).length;\r\n if (node === runEl) {\r\n charOffset = 0;\r\n for (let i = 0; i < offset && i < runEl.childNodes.length; i += 1) {\r\n charOffset += stripEmptyRunPlaceholder(runEl.childNodes[i].textContent ?? '').length;\r\n }\r\n }\r\n\r\n return {\r\n runId: runEl.getAttribute('data-run-id'),\r\n blockId: blockEl.getAttribute('data-block-id'),\r\n offset: charOffset,\r\n };\r\n}\r\n\r\n/**\r\n * Resolves a *collapsed* caret to the run+char-offset it sits at — used by\r\n * Enter-to-split so the new block gets exactly the text after the caret,\r\n * instead of always starting blank. Returns null for a non-collapsed\r\n * selection or a caret that isn't inside any run at all.\r\n */\r\nexport function resolveCollapsedCaret() {\r\n const selection = window.getSelection?.();\r\n if (!selection || selection.rangeCount === 0 || !selection.isCollapsed) return null;\r\n return resolveRunAndOffset(selection.anchorNode, selection.anchorOffset);\r\n}\r\n\r\n/**\r\n * Resolves a non-collapsed selection that may span *multiple runs within\r\n * the same block* (e.g. selecting text that crosses a bold boundary) —\r\n * generalizes resolveRunSelection's single-run limitation. Returns null if\r\n * the selection spans multiple blocks (use resolveCrossBlockSelection for\r\n * that) or if either end isn't inside a run at all.\r\n */\r\nexport function resolveMultiRunSelection() {\r\n const selection = window.getSelection?.();\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return null;\r\n\r\n const anchor = resolveRunAndOffset(selection.anchorNode, selection.anchorOffset);\r\n const focus = resolveRunAndOffset(selection.focusNode, selection.focusOffset);\r\n if (!anchor || !focus) return null;\r\n if (anchor.blockId !== focus.blockId) return null; // cross-block: use resolveCrossBlockSelection\r\n\r\n return {\r\n blockId: anchor.blockId,\r\n startRunId: anchor.runId,\r\n startOffset: anchor.offset,\r\n endRunId: focus.runId,\r\n endOffset: focus.offset,\r\n };\r\n}\r\n\r\n/**\r\n * Resolves a non-collapsed selection spanning *multiple sibling blocks*\r\n * under a shared parent (e.g. from the middle of one paragraph through the\r\n * middle of another a few blocks down) — for toggleMarkOverBlockRange.\r\n * Needs `store` (unlike the other resolvers here) to walk the parent's\r\n * contentIds and slice out the sibling range. Returns null when the\r\n * selection is actually within one block (use resolveMultiRunSelection\r\n * instead), or when the two blocks aren't siblings under the same parent\r\n * (nested at different depths — not supported in v1).\r\n */\r\nexport function resolveCrossBlockSelection(store) {\r\n const selection = window.getSelection?.();\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return null;\r\n\r\n const anchor = resolveRunAndOffset(selection.anchorNode, selection.anchorOffset);\r\n const focus = resolveRunAndOffset(selection.focusNode, selection.focusOffset);\r\n if (!anchor || !focus) return null;\r\n if (anchor.blockId === focus.blockId) return null; // same block: use resolveMultiRunSelection\r\n\r\n const startBlock = store.getBlock(anchor.blockId);\r\n const parent = startBlock && store.getBlock(startBlock.parentId);\r\n if (!parent) return null;\r\n\r\n const ids = parent.contentIds;\r\n const i1 = ids.indexOf(anchor.blockId);\r\n const i2 = ids.indexOf(focus.blockId);\r\n if (i1 === -1 || i2 === -1) return null; // not siblings under the same parent\r\n\r\n const [from, to] = i1 <= i2 ? [i1, i2] : [i2, i1];\r\n\r\n return {\r\n blockIds: ids.slice(from, to + 1),\r\n startBlockId: anchor.blockId,\r\n startRunId: anchor.runId,\r\n startOffset: anchor.offset,\r\n endBlockId: focus.blockId,\r\n endRunId: focus.runId,\r\n endOffset: focus.offset,\r\n };\r\n}\r\n","import { insertBlock, updateRun, setBlockRuns, removeBlock } from '../../store/operations.js';\r\nimport { focusBlockStart } from './navigationCommands.js';\r\nimport { resolveCollapsedCaret } from '../../react/selectionResolve.js';\r\nimport { genId } from '../../utils/idGen.js';\r\n\r\n/**\r\n * Inserts a new block immediately after `currentBlockId`, as a sibling under\r\n * the same parent. `factory(parentId)` must return `{ block, runs, subtreeBlocks }`\r\n * — `runs` may be empty for non-leaf types, and `subtreeBlocks` (default [])\r\n * holds any additional descendant blocks for multi-level inserts (e.g. a\r\n * table's rows/cells alongside its own root block). Shared by every block\r\n * type's slash command so \"where do I insert relative to the current block\"\r\n * is written once.\r\n */\r\nexport function insertSiblingAfter(store, currentBlockId, factory) {\r\n const current = store.getBlock(currentBlockId);\r\n const parentId = current.parentId;\r\n const parent = store.getBlock(parentId);\r\n const index = parent.contentIds.indexOf(currentBlockId) + 1;\r\n const { block, runs = [], subtreeBlocks = [] } = factory(parentId);\r\n store.applyOperation(insertBlock(block, parentId, index, { blocks: [block, ...subtreeBlocks], runs }));\r\n return block.id;\r\n}\r\n\r\n/**\r\n * Same as insertSiblingAfter, but also moves focus into the new block —\r\n * every editor does this (Enter, or picking a block from the slash menu,\r\n * always lands the caret in the thing you just created, never leaves it on\r\n * the block you triggered it from). Descends into containers (table,\r\n * layout) to find the first actually-typeable position.\r\n */\r\nexport function insertSiblingAfterAndFocus(store, currentBlockId, factory) {\r\n const newBlockId = insertSiblingAfter(store, currentBlockId, factory);\r\n focusBlockStart(store, newBlockId);\r\n return newBlockId;\r\n}\r\n\r\n/**\r\n * Inserts a new block as the *first child* of `parentBlockId` and focuses\r\n * it. Used when a container block (a list item with nested items beneath\r\n * it) needs the new block to appear visually right after the parent's own\r\n * content but before its existing children — since children render\r\n * *inside* the parent's own DOM subtree, a \"sibling in the grandparent's\r\n * array\" would only ever land after that whole subtree, not between the\r\n * parent's title and its first child.\r\n */\r\nexport function insertFirstChildAndFocus(store, parentBlockId, factory) {\r\n const { block, runs = [], subtreeBlocks = [] } = factory(parentBlockId);\r\n store.applyOperation(insertBlock(block, parentBlockId, 0, { blocks: [block, ...subtreeBlocks], runs }));\r\n focusBlockStart(store, block.id);\r\n return block.id;\r\n}\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') {\r\n store.performBatch(ops);\r\n } else {\r\n for (const op of ops) store.applyOperation(op);\r\n }\r\n}\r\n\r\n/**\r\n * Pure: splits an ordered list of Run objects at `caretRunId`/`caretOffset`\r\n * into \"everything before the caret\" and \"everything at/after it\",\r\n * splitting the caret's own run in two when it's a text run with content on\r\n * both sides. Identity is preserved wherever possible (a run that doesn't\r\n * actually get cut keeps its id) so only a genuine mid-run split spends a\r\n * new id. Neither side is ever left with zero runs — a block needs at least\r\n * one run to render/anchor a caret in, so an empty side gets a fresh blank\r\n * text run.\r\n */\r\nexport function splitRunsAtCaret(runs, caretRunId, caretOffset) {\r\n const idx = runs.findIndex((r) => r.id === caretRunId);\r\n if (idx === -1) return null;\r\n\r\n const caretRun = runs[idx];\r\n const before = runs.slice(0, idx);\r\n const after = runs.slice(idx + 1);\r\n\r\n if (caretRun.type === 'text') {\r\n const value = caretRun.value ?? '';\r\n const leftValue = value.slice(0, caretOffset);\r\n const rightValue = value.slice(caretOffset);\r\n if (leftValue && rightValue) {\r\n before.push({ ...caretRun, value: leftValue });\r\n after.unshift({ ...caretRun, id: genId(), value: rightValue });\r\n } else if (rightValue) {\r\n after.unshift(caretRun); // caret at the run's start: whole run moves right, unchanged\r\n } else {\r\n before.push(caretRun); // caret at the run's end (or run already empty): stays left, unchanged\r\n }\r\n } else if (caretOffset > 0) {\r\n before.push(caretRun); // atomic run: never split inside it, only before/after\r\n } else {\r\n after.unshift(caretRun);\r\n }\r\n\r\n const leftRuns = before.length ? before : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n const rightRuns = after.length ? after : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n return { leftRuns, rightRuns };\r\n}\r\n\r\n/**\r\n * Enter-to-split: every real editor splits the block's content at the\r\n * caret (text before stays, text after moves into the new sibling) rather\r\n * than always creating a blank sibling and leaving all the text behind.\r\n * Falls back to the old \"just append an empty sibling\" behavior when there\r\n * is no resolvable live caret in this exact block (no DOM selection at all,\r\n * as in most non-interactive tests, or a caret that landed somewhere else).\r\n *\r\n * `currentRunIds` must be the block's own run ids (contentIds for a plain\r\n * leaf, props.titleRunIds for a listItem) — same convention as\r\n * EditableBlockContent's `runIds` prop. `factory(parentId, initialRuns?)`\r\n * must accept the optional pre-built run list (see createTextLeafBlock/\r\n * createListItemBlock).\r\n */\r\nexport function insertSiblingSplitAtCaretAndFocus(store, blockId, currentRunIds, factory) {\r\n const current = store.getBlock(blockId);\r\n const parent = store.getBlock(current.parentId);\r\n const index = parent.contentIds.indexOf(blockId) + 1;\r\n return splitAndInsertAtCaret(store, blockId, currentRunIds, factory, {\r\n insertParentId: parent.id,\r\n insertIndex: index,\r\n fallback: () => insertSiblingAfterAndFocus(store, blockId, factory),\r\n });\r\n}\r\n\r\n/**\r\n * Same idea as insertSiblingSplitAtCaretAndFocus, but for the \"this item has\r\n * nested children\" case (see insertFirstChildAndFocus): the new block's\r\n * content is the split-off right-hand runs, and it lands as the first child\r\n * of `blockId` itself (whose own title runs get truncated to the left half)\r\n * rather than as its sibling.\r\n */\r\nexport function insertFirstChildSplitAtCaretAndFocus(store, blockId, currentRunIds, factory) {\r\n return splitAndInsertAtCaret(store, blockId, currentRunIds, factory, {\r\n insertParentId: blockId,\r\n insertIndex: 0,\r\n fallback: () => insertFirstChildAndFocus(store, blockId, factory),\r\n });\r\n}\r\n\r\nfunction splitAndInsertAtCaret(store, blockId, currentRunIds, factory, { insertParentId, insertIndex, fallback }) {\r\n const caret = resolveCollapsedCaret();\r\n if (!caret || caret.blockId !== blockId) return fallback();\r\n\r\n const currentRuns = currentRunIds.map((id) => store.getRun(id)).filter(Boolean);\r\n const split = splitRunsAtCaret(currentRuns, caret.runId, caret.offset);\r\n if (!split) return fallback();\r\n\r\n const { leftRuns, rightRuns } = split;\r\n const { block, runs = rightRuns, subtreeBlocks = [] } = factory(insertParentId, rightRuns);\r\n\r\n // Enter at the very start of a block's content leaves nothing before the\r\n // caret, so leftRuns comes back empty — but the block staying behind\r\n // must never end up with zero runs: an empty contentEditable region isn't\r\n // a valid caret anchor in most browsers, so the next time someone types\r\n // into it, every keystroke mints a brand-new run instead of updating one\r\n // in place (the same \"characters double\" bug this exact guard fixes for\r\n // removeRun/handleInput in EditableBlockContent).\r\n const survivingLeftRuns = leftRuns.length ? leftRuns : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n\r\n applyOps(store, [\r\n setBlockRuns(blockId, survivingLeftRuns),\r\n insertBlock(block, insertParentId, insertIndex, { blocks: [block, ...subtreeBlocks], runs }),\r\n ]);\r\n focusBlockStart(store, block.id);\r\n return block.id;\r\n}\r\n\r\nfunction getOwnRunIds(block) {\r\n return block?.props?.titleRunIds ?? block?.contentIds ?? [];\r\n}\r\n\r\n// A listItem's own text lives in props.titleRunIds while contentIds holds\r\n// its nested child *blocks* — so for it (and any other block shaped that\r\n// way), contentIds having entries means it has children, not extra runs.\r\nfunction hasNestedChildren(block) {\r\n return Boolean(block?.props?.titleRunIds) && (block.contentIds?.length ?? 0) > 0;\r\n}\r\n\r\n/**\r\n * Converts an empty block in place to a different type, instead of leaving\r\n * the old empty block behind with a new sibling after it — e.g. picking\r\n * \"Heading\" from the slash menu on a still-empty paragraph turns that same\r\n * paragraph into the heading, rather than inserting a heading after an\r\n * orphaned blank paragraph. Removes the old block and inserts the new one\r\n * at the same index as one atomic step, so undo/redo treats it as a single\r\n * operation.\r\n */\r\nfunction replaceBlockInPlace(store, blockId, factory) {\r\n const current = store.getBlock(blockId);\r\n const parentId = current.parentId;\r\n const parent = store.getBlock(parentId);\r\n const index = parent.contentIds.indexOf(blockId);\r\n const { block, runs = [], subtreeBlocks = [] } = factory(parentId);\r\n\r\n applyOps(store, [\r\n removeBlock(blockId),\r\n insertBlock(block, parentId, index, { blocks: [block, ...subtreeBlocks], runs }),\r\n ]);\r\n focusBlockStart(store, block.id);\r\n return block.id;\r\n}\r\n\r\n/**\r\n * Slash-command entry point for block-level commands: removes the\r\n * \"/query\" span from the triggering run (merging whatever was before and\r\n * after it — a block command doesn't need to preserve a split point the\r\n * way an inline command does, since it's creating an entirely separate\r\n * sibling block, not splicing into this one).\r\n *\r\n * If trimming the query leaves the block completely empty — it was the\r\n * block's only run and the block has no nested children — the block is\r\n * converted in place (replaceBlockInPlace) rather than inserted after,\r\n * which would otherwise leave a pointless empty block sitting above the\r\n * one the user actually meant to create. Otherwise, behaves as before:\r\n * trims the query and inserts+focuses the new block after the current one.\r\n */\r\nexport function trimSlashQueryAndInsertAfter(store, { blockId, runId, sliceStart, sliceEnd }, factory) {\r\n const run = store.getRun(runId);\r\n const value = run?.value ?? '';\r\n const newValue = value.slice(0, sliceStart) + value.slice(sliceEnd);\r\n\r\n const block = store.getBlock(blockId);\r\n const ownRunIds = getOwnRunIds(block);\r\n const isOnlyRun = ownRunIds.length === 1 && ownRunIds[0] === runId;\r\n const wouldBeEmpty = isOnlyRun && newValue === '' && !hasNestedChildren(block);\r\n\r\n if (wouldBeEmpty) {\r\n return replaceBlockInPlace(store, blockId, factory);\r\n }\r\n\r\n store.applyOperation(updateRun(runId, { value: newValue }));\r\n return insertSiblingAfterAndFocus(store, blockId, factory);\r\n}\r\n","import { genId } from '../../utils/idGen.js';\r\n\r\n/**\r\n * Builds a factory(parentId, initialRuns?) -> {block, runs} for a text leaf\r\n * block. Most callers (slash commands) omit `initialRuns` and get a single\r\n * blank run; Enter-to-split passes the runs that landed after the caret so\r\n * the new block starts with that text instead of empty.\r\n */\r\nexport function createTextLeafBlock(type, props = {}) {\r\n return function factory(parentId, initialRuns) {\r\n const blockId = genId();\r\n const runs = initialRuns?.length ? initialRuns : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n return {\r\n block: { id: blockId, type, parentId, contentIds: runs.map((r) => r.id), props },\r\n runs,\r\n };\r\n };\r\n}\r\n","import { insertBlock } from '../../store/operations.js';\r\nimport { createTextLeafBlock } from './leafBlockFactory.js';\r\n\r\n/**\r\n * Call after any operation that might have deleted the *last* block under\r\n * the document root. Every real editor keeps at least one empty paragraph\r\n * rather than allowing a genuinely blank document — a page with zero\r\n * children isn't just a UX dead end (nothing to click into), it also\r\n * breaks caret placement entirely, since there's no contentEditable region\r\n * left anywhere for the browser to anchor a click or keystroke in.\r\n *\r\n * No-op (returns null) if the root already has content. `store` may be a\r\n * plain EditorStore or a History wrapper — either way this issues its own\r\n * `applyOperation` call, so call it *after* whatever batch removed the\r\n * block, not folded into that same batch (the fallback should only ever\r\n * fire if the removal actually emptied the root, which isn't knowable\r\n * until after it's applied).\r\n */\r\nexport function ensureRootNonEmpty(store) {\r\n const rootId = store.getRootId();\r\n const root = store.getBlock(rootId);\r\n if (!root || root.contentIds.length > 0) return null;\r\n\r\n const { block, runs } = createTextLeafBlock('paragraph')(rootId);\r\n store.applyOperation(insertBlock(block, rootId, 0, { blocks: [block], runs }));\r\n return block.id;\r\n}\r\n","import { removeBlock, setBlockContentIds, insertBlock } from '../../store/operations.js';\r\nimport { isContentlessBlock } from './contentless.js';\r\nimport { createTextLeafBlock } from './leafBlockFactory.js';\r\nimport { ensureRootNonEmpty } from './ensureRootNonEmpty.js';\r\n\r\n// Container types that should vanish entirely once their one-and-only\r\n// content block is emptied out, rather than leaving an empty box behind —\r\n// e.g. an empty callout with nothing typed into it. Deliberately does NOT\r\n// include layoutColumn: removing one column would break an N-column\r\n// layout's symmetry, which isn't the same situation as a callout with\r\n// nothing left to say.\r\nconst UNWRAP_WHEN_SOLE_CHILD_EMPTIED = new Set(['callout']);\r\n\r\n// Block types whose contentIds are always run ids (never child blocks) and\r\n// whose only real difference is presentational (heading level, or a quote's\r\n// left border, vs plain paragraph) — merging across these keeps the\r\n// surviving (previous) block's own type/props untouched, so merging a\r\n// paragraph up into a heading stays a heading, backspacing into a quote\r\n// keeps it a quote, and vice versa. Deliberately does NOT include\r\n// tableCell/listItem: those have distinct structural roles (a cell belongs\r\n// to a row; a list item carries indentation/marker state) where \"just\r\n// concatenate the text and keep whichever type was already there\" isn't\r\n// the right semantics.\r\nexport const MERGEABLE_TEXT_TYPES = new Set(['paragraph', 'heading', 'blockquote']);\r\n\r\nexport function canMergeTypes(prevType, blockType) {\r\n return prevType === blockType || (MERGEABLE_TEXT_TYPES.has(prevType) && MERGEABLE_TEXT_TYPES.has(blockType));\r\n}\r\n\r\n/**\r\n * Backspace-at-start-of-block behavior:\r\n * 1. If the previous sibling is contentless (e.g. a divider), delete *it*\r\n * first and stay put — matches the familiar \"backspace clears the\r\n * nearest obstacle\" convention, and means a second\r\n * backspace then merges into whatever's before the divider.\r\n * 2. Else if this block is empty, delete it.\r\n * 3. Else merge its inline content onto the end of the previous sibling —\r\n * same type, or both are in MERGEABLE_TEXT_TYPES (paragraph/heading, in\r\n * either direction) — and delete the now-empty shell. Any other type\r\n * pairing (a table, a list item, ...) is left alone; merging into those\r\n * doesn't have well-defined semantics in v1.\r\n *\r\n * 4. Special case when there's *nothing before this block at all* (it's\r\n * first in its container, so there's no \"merge into\" target): a block\r\n * with real content still does nothing (matches every other editor —\r\n * Backspace at the absolute start of the first line is a no-op when\r\n * there's something to preserve). But an *empty* leading block should\r\n * still go away — removed outright if something follows it, or, if\r\n * it's the only block left, replaced with a blank paragraph (same\r\n * \"never leave nothing to click into\" fallback as\r\n * exitListItemToParagraph / ensureRootNonEmpty). Without this, an empty\r\n * heading/paragraph that happens to be first (very often *the only\r\n * block left* after deleting everything else) could never be removed\r\n * at all.\r\n *\r\n * All of this is one atomic undo step: if `store` is a History instance\r\n * (has performBatch), the ops are grouped; a plain EditorStore just applies\r\n * them in sequence (no undo tracking to group).\r\n *\r\n * Returns the id of the block that should receive focus afterward, or null\r\n * if there was nothing to do.\r\n */\r\nexport function mergeWithPreviousOrDelete(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n if (!block) return null;\r\n\r\n const parent = store.getBlock(block.parentId);\r\n const index = parent.contentIds.indexOf(blockId);\r\n const isEmpty = block.contentIds.length === 0 || (block.contentIds.length === 1 && isBlankRun(store, block.contentIds[0]));\r\n\r\n if (index <= 0) {\r\n if (!isEmpty) return null; // real content, nothing before it: no-op, as every other editor does\r\n\r\n if (parent.contentIds.length > 1) {\r\n applyOps(store, [removeBlock(blockId)]);\r\n return store.getBlock(parent.id).contentIds[0]; // whatever's now first\r\n }\r\n\r\n // The sole (now-empty) child of a container that should disappear once\r\n // there's nothing left in it (e.g. a callout) — remove the CONTAINER\r\n // itself, not just this child, instead of leaving an empty box behind.\r\n if (UNWRAP_WHEN_SOLE_CHILD_EMPTIED.has(parent.type)) {\r\n return unwrapEmptyContainer(store, parent);\r\n }\r\n\r\n if (block.type === 'paragraph') return null; // already the fallback shape; nothing to do\r\n\r\n const { block: fallbackBlock, runs } = createTextLeafBlock('paragraph')(parent.id);\r\n applyOps(store, [\r\n insertBlock(fallbackBlock, parent.id, index, { blocks: [fallbackBlock], runs }),\r\n removeBlock(blockId),\r\n ]);\r\n return fallbackBlock.id;\r\n }\r\n\r\n const prevId = parent.contentIds[index - 1];\r\n const prev = store.getBlock(prevId);\r\n\r\n // An empty CURRENT block always goes first, even when the previous\r\n // sibling is a non-editable block (divider/embed) — Backspace on a\r\n // trailing empty paragraph should make the empty paragraph disappear\r\n // (ordinary empty-block behavior) before anything about the\r\n // non-editable neighbor is offered at all. Checking isContentlessBlock\r\n // first here would instead delete the neighbor immediately, one\r\n // Backspace too early. (In the normal keyboard path this is actually\r\n // decided one layer up, in EditableBlockContent, which only offers the\r\n // neighbor select-then-delete flow once the current block has real\r\n // content left — this ordering just keeps the pure function's own\r\n // behavior consistent for direct callers.)\r\n if (isEmpty) {\r\n applyOps(store, [removeBlock(blockId)]);\r\n return prevId;\r\n }\r\n\r\n if (isContentlessBlock(store, prev)) {\r\n applyOps(store, [removeBlock(prevId)]);\r\n return blockId; // stay put; the obstacle is gone, no DOM remount needed\r\n }\r\n\r\n if (!prev || !canMergeTypes(prev.type, block.type)) return null;\r\n\r\n const mergedContentIds = [...prev.contentIds, ...block.contentIds];\r\n applyOps(store, [\r\n setBlockContentIds(prevId, mergedContentIds),\r\n setBlockContentIds(blockId, []), // detach moved runs before deleting the shell\r\n removeBlock(blockId),\r\n ]);\r\n return prevId;\r\n}\r\n\r\nfunction isBlankRun(store, runId) {\r\n const run = store.getRun(runId);\r\n return !run || (run.value ?? '') === '';\r\n}\r\n\r\n/**\r\n * Removes `container` itself (e.g. a callout whose only child was just\r\n * emptied out), focusing whatever now sits where it used to — its previous\r\n * sibling, or else its next sibling, or else (the container was the only\r\n * thing under the document root) whatever ensureRootNonEmpty falls back\r\n * to, so there's always still somewhere to land the caret.\r\n */\r\nfunction unwrapEmptyContainer(store, container) {\r\n const grandParent = store.getBlock(container.parentId);\r\n if (!grandParent) return null;\r\n const idx = grandParent.contentIds.indexOf(container.id);\r\n const prevId = idx > 0 ? grandParent.contentIds[idx - 1] : null;\r\n const nextId = idx !== -1 && idx < grandParent.contentIds.length - 1 ? grandParent.contentIds[idx + 1] : null;\r\n\r\n applyOps(store, [removeBlock(container.id)]);\r\n const fallbackId = ensureRootNonEmpty(store);\r\n return prevId ?? nextId ?? fallbackId;\r\n}\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') {\r\n store.performBatch(ops);\r\n } else {\r\n for (const op of ops) store.applyOperation(op);\r\n }\r\n}\r\n","import { focusRunEnd } from '../../react/focusRun.js';\r\nimport { resolveBlockLastRun } from './navigationCommands.js';\r\n\r\n/**\r\n * Resolves what to do with focus after a merge/delete operation returns\r\n * `focusBlockId` — normally focus the end of its last *focusable* run, but\r\n * if there's truly nothing to put a caret in (e.g. the current block's own\r\n * empty content was just deleted, landing \"focus\" on a divider/embed\r\n * sibling), select/highlight it instead, via the exact same select-then-\r\n * delete flow as backspacing straight into a non-editable neighbor (see\r\n * EditableBlockContent's selectOrDeleteContentlessNeighbor) — this is what\r\n * makes that flow reachable at all for \"empty paragraph right after an\r\n * image\": the empty paragraph is deleted first (ordinary empty-block\r\n * Backspace), *then* the image becomes selected, rather than the image\r\n * jumping straight to selected before the empty paragraph itself ever\r\n * goes away.\r\n *\r\n * Uses resolveBlockLastRun (not focusBlockId's own contentIds directly) so\r\n * this also does the right thing when focusBlockId is a *container* — e.g.\r\n * backspacing away the block right after a callout should land the caret\r\n * at the end of the callout's own last child, not fail silently because a\r\n * container's contentIds are child block ids, not run ids.\r\n */\r\nexport function focusAfterMerge(store, focusBlockId, currentBlockId, setSelectedBlockId) {\r\n if (!focusBlockId || focusBlockId === currentBlockId) return;\r\n const lastRunId = resolveBlockLastRun(store, focusBlockId);\r\n if (lastRunId) {\r\n focusRunEnd(lastRunId);\r\n return;\r\n }\r\n setSelectedBlockId(focusBlockId);\r\n // The current block (whose empty content just got deleted) is gone from\r\n // the DOM entirely, so — unlike EditableBlockContent's own select-then-\r\n // delete flow, which deliberately never steals focus away from a block\r\n // that's still there — nothing else has focus here. Move it onto the\r\n // now-selected non-editable block directly (divider/embed both set\r\n // tabIndex={-1} for exactly this) so the surface's own keydown listener\r\n // keeps capturing the next Backspace/Delete.\r\n requestAnimationFrame(() => {\r\n document.querySelector(`[data-block-id=\"${focusBlockId}\"]`)?.focus();\r\n });\r\n}\r\n","/**\n * Resolves the `dir` attribute a block's editable region/wrapper should\n * render with: the block's own `props.dir` override, else the document\n * root's `props.dir` (a document-wide default), else `'auto'`.\n *\n * `'auto'` is the actual workhorse for multi-language support, not just a\n * fallback: it lets the browser's own Unicode bidi algorithm detect\n * direction per block from its first strong character, which is exactly\n * what a document mixing LTR and RTL blocks (e.g. an English heading over\n * an Arabic paragraph) needs with zero configuration. The explicit\n * override exists for what `auto` can't infer on its own — most commonly\n * an empty block with no text yet to detect a direction from.\n */\nexport function resolveBlockDir(store, block) {\n if (!block) return 'auto';\n if (block.props?.dir) return block.props.dir;\n const root = store.getBlock(store.getRootId());\n return root?.props?.dir ?? 'auto';\n}\n","import { changeBlockType, moveBlock, setBlockContentIds, updateBlockProps } from '../../store/operations.js';\n\n/**\n * Builds the ops that convert `blockId` to a different type IN PLACE — same\n * id, same parentId, same position among siblings — carrying over `runIds`\n * (reusing the existing Run objects — never recreated) rather than creating\n * new ones, so any marks/text already typed survive the conversion. `props`\n * may include `titleRunIds` (for a listItem-shaped target) — `runIds` is\n * threaded into whichever of contentIds/props.titleRunIds the target type\n * actually uses (and whichever the *source* type used, when detaching).\n *\n * Keeping the same id (rather than deleting the old block and inserting a\n * new one) matters beyond just simplicity: it's what lets a future\n * multi-peer merge treat two concurrent conversions of the same block as\n * one field-level conflict on that id (last-write-wins) instead of two\n * unrelated structural edits that would otherwise leave both resulting\n * blocks sitting side by side after merging.\n *\n * `registry` is optional and additive — this function's two original\n * callers (markdownShortcuts.js, applyVoiceAction.js) never pass one, and\n * only ever call this on a fresh, childless, single-run paragraph, so their\n * behavior is completely unaffected by anything below. When `registry` IS\n * supplied (the \"Turn into\" feature), the *source* block's own nested\n * children — real child blocks in `contentIds`, distinct from a leaf's own\n * runs, true for `listItem`/`toggleHeading`/`callout` (`!registry.isLeaf`)\n * — are handled instead of being silently orphaned:\n * - If the *target* type can also hold children (`!registry.isLeaf(type)`,\n * e.g. listItem -> toggleHeading), the children simply stay parented to\n * this same block id — nothing needs to move.\n * - If the target is a pure leaf (e.g. toggleHeading -> heading) and can't\n * hold them, they're promoted to sibling blocks inserted immediately\n * after this block instead — content is never silently dropped.\n *\n * Returns `{ ops, newBlockId }` rather than applying anything itself —\n * `newBlockId` is always `blockId` (kept for backward compatibility with\n * callers written when this returned a freshly generated id). The caller\n * folds `ops` into its own batch (e.g. alongside an `updateRun` that strips\n * a matched markdown-shortcut prefix from the first run), so the whole\n * thing is one atomic undo step.\n */\nexport function convertBlockType(store, blockId, type, props, runIds, registry) {\n const block = store.getBlock(blockId);\n const parent = store.getBlock(block.parentId);\n const index = parent.contentIds.indexOf(blockId);\n const targetUsesTitleRunIds = 'titleRunIds' in props;\n const sourceUsesTitleRunIds = 'titleRunIds' in (block.props ?? {});\n const sourceHasChildren = registry ? !registry.isLeaf(block.type) && block.contentIds.length > 0 : false;\n const targetCanHoldChildren = registry ? !registry.isLeaf(type) : false;\n\n const ops = [];\n\n // Children only need to move when the target can't hold them (promoted\n // to siblings). When the target can also hold children, they're already\n // correctly parented to this same block id — nothing to do.\n if (sourceHasChildren && !targetCanHoldChildren) {\n block.contentIds.forEach((childId, i) => ops.push(moveBlock(childId, block.parentId, index + 1 + i)));\n }\n\n ops.push(changeBlockType(blockId, type, props));\n\n if (targetUsesTitleRunIds) {\n ops.push(updateBlockProps(blockId, { titleRunIds: runIds }));\n // A leaf source's old contentIds held its own runs, now superseded by\n // titleRunIds — clear it so those ids aren't misread as child blocks.\n // A container source that already used titleRunIds (or had its\n // children promoted to siblings above) already has the right\n // contentIds and needs no clearing.\n if (!sourceUsesTitleRunIds && !sourceHasChildren) {\n ops.push(setBlockContentIds(blockId, []));\n }\n } else {\n // Target keeps its own runs directly in contentIds. Any children still\n // sitting in contentIds at this point are ones the target can also\n // hold (handled above) and must be kept alongside the transferred\n // runIds, not replaced by them.\n const keepChildren = sourceHasChildren && targetCanHoldChildren ? block.contentIds : [];\n ops.push(setBlockContentIds(blockId, [...keepChildren, ...runIds]));\n }\n\n return { newBlockId: blockId, ops };\n}\n","import { updateRun } from '../../store/operations.js';\r\nimport { convertBlockType } from '../shared/convertBlockType.js';\r\nimport { focusRunStart } from '../../react/focusRun.js';\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n// Markdown shortcuts: a recognized prefix, typed at the\r\n// very start of an otherwise-plain paragraph, converts the block once the\r\n// pattern is complete — most need a trailing trigger space (\"# \", \"- \",\r\n// \"1. \", \"> \", \"[] \"), matching every other editor's convention that the\r\n// space itself commits the conversion (so \"#\" alone, mid-typing, doesn't\r\n// convert early); \"```\" has no trailing space since there's nothing after\r\n// the third backtick to wait for.\r\n//\r\n// The trigger character class is `[  ]`, not a literal \" \" — browsers\r\n// commonly insert a *non-breaking* space (U+00A0) instead of an ordinary\r\n// one for a trailing space in a contentEditable region (so it doesn't get\r\n// collapsed away by normal HTML whitespace rules), and every one of these\r\n// shortcuts' trigger is exactly that: the last character in the region at\r\n// the moment it's typed. Matching only a literal \" \" meant none of these\r\n// ever fired against real typed input, only against text set up directly\r\n// in a test — jsdom doesn't reproduce this browser quirk, which is why it\r\n// wasn't caught there.\r\nconst RULES = [\r\n { re: /^(#{1,3})[  ]$/, type: 'heading', props: (m) => ({ level: m[1].length }) },\r\n { re: /^[-*][  ]$/, type: 'listItem', props: () => ({ ordered: false, titleRunIds: [] }) },\r\n { re: /^\\d+\\.[  ]$/, type: 'listItem', props: () => ({ ordered: true, titleRunIds: [] }) },\r\n { re: /^\\[\\][  ]$/, type: 'listItem', props: () => ({ ordered: false, checked: false, titleRunIds: [] }) },\r\n { re: /^>[  ]$/, type: 'blockquote', props: () => ({}) },\r\n { re: /^```$/, type: 'code', props: () => ({ language: 'plaintext' }) },\r\n];\r\n\r\n/**\r\n * Checks the block's current run list against every rule above and, on a\r\n * match, converts it: strips the matched prefix from the first run's text\r\n * and swaps the block for the matching type via convertBlockType, carrying\r\n * over the (now-stripped) run so any text/marks typed after the prefix\r\n * survive — all as one atomic undo step. Only fires when the block's\r\n * ENTIRE content is a single plain text run (no marks/atomic runs mixed in\r\n * yet); typing the same characters mid-sentence, or spanning multiple\r\n * runs, never triggers it — scoped to a fresh, still-plain line.\r\n *\r\n * `runs` is the block's just-committed run list (see EditableBlockContent's\r\n * handleInput, onlyValueChanges path — a markdown shortcut is always typed\r\n * into a single existing run, never a structural DOM change). Returns\r\n * `true` if a conversion happened (the caller should treat blockId as gone\r\n * — a new block now occupies its place).\r\n */\r\nexport function applyMarkdownShortcut(store, blockId, runs) {\r\n if (runs.length !== 1 || runs[0].type !== 'text') return false;\r\n const value = runs[0].value ?? '';\r\n\r\n for (const rule of RULES) {\r\n const match = rule.re.exec(value);\r\n if (!match) continue;\r\n\r\n const strippedValue = value.slice(match[0].length);\r\n const { ops } = convertBlockType(store, blockId, rule.type, rule.props(match), [runs[0].id]);\r\n applyOps(store, [updateRun(runs[0].id, { value: strippedValue }), ...ops]);\r\n focusRunStart(runs[0].id);\r\n return true;\r\n }\r\n return false;\r\n}\r\n","import { useCallback } from 'react';\r\nimport { EditableBlockContent } from '../../react/EditableBlockContent.jsx';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useSelectedBlock, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { insertSiblingSplitAtCaretAndFocus, insertSiblingAfterAndFocus } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { mergeWithPreviousOrDelete } from '../shared/mergeCommands.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { focusAfterMerge } from '../shared/focusAfterMerge.js';\r\nimport { focusRunEnd } from '../../react/focusRun.js';\r\nimport { focusAdjacentBlock } from '../shared/navigationCommands.js';\r\nimport { resolveBlockDir } from '../shared/resolveBlockDir.js';\r\nimport { applyMarkdownShortcut } from './markdownShortcuts.js';\r\n\r\n// Container types a nested paragraph can \"exit\" out of on an empty last\r\n// line — pressing Enter on a blank final paragraph inside one of these\r\n// creates the new paragraph as a SIBLING OF THE CONTAINER ITSELF (back out\r\n// at the outer level), instead of yet another paragraph nested inside it.\r\n// This is how you get out of a callout/toggle heading's body to keep\r\n// writing in the main document — there's no other affordance for it, so\r\n// without this an empty trailing line is a dead end.\r\nconst EXITABLE_PARENT_TYPES = new Set(['callout', 'toggleHeading']);\r\n\r\nexport function ParagraphBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n const { setSelectedBlockId } = useSelectedBlock();\r\n\r\n const handleEnter = useCallback(() => {\r\n const parent = store.getBlock(block?.parentId);\r\n const isEmpty = isRunsEmpty(store, block?.contentIds ?? []);\r\n const isLastChild = Boolean(parent) && parent.contentIds[parent.contentIds.length - 1] === id;\r\n\r\n if (isEmpty && isLastChild && EXITABLE_PARENT_TYPES.has(parent?.type)) {\r\n insertSiblingAfterAndFocus(store, parent.id, createTextLeafBlock('paragraph'));\r\n return;\r\n }\r\n\r\n insertSiblingSplitAtCaretAndFocus(store, id, block?.contentIds ?? [], createTextLeafBlock('paragraph'));\r\n }, [store, id, block]);\r\n\r\n const handleBackspaceAtStart = useCallback(() => {\r\n const parent = store.getBlock(block?.parentId);\r\n const isEmpty = isRunsEmpty(store, block?.contentIds ?? []);\r\n const isSoleChild = parent?.contentIds?.length === 1 && parent.contentIds[0] === id;\r\n\r\n if (isEmpty && isSoleChild && parent?.type === 'toggleHeading') {\r\n // Pop back out to the toggle heading's own title instead of deleting\r\n // anything here — mirrors how a nested list item's empty Backspace\r\n // pops out one level at a time. Backspacing *again* from the title\r\n // (now that focus is there) is what actually removes an entirely\r\n // blank toggle heading, via mergeToggleHeadingOrNoop — this is the\r\n // first of those two steps, not a dead end.\r\n const titleRunIds = parent.props?.titleRunIds ?? [];\r\n const lastTitleRunId = titleRunIds[titleRunIds.length - 1];\r\n if (lastTitleRunId) focusRunEnd(lastTitleRunId);\r\n return;\r\n }\r\n\r\n const focusBlockId = mergeWithPreviousOrDelete(store, id);\r\n focusAfterMerge(store, focusBlockId, id, setSelectedBlockId);\r\n }, [store, id, block, setSelectedBlockId]);\r\n\r\n const handleArrowUp = useCallback(() => focusAdjacentBlock(store, id, 'up'), [store, id]);\r\n const handleArrowDown = useCallback(() => focusAdjacentBlock(store, id, 'down'), [store, id]);\r\n\r\n const handleAutoformat = useCallback((runs) => applyMarkdownShortcut(store, id, runs), [store, id]);\r\n const className = useBlockClassName('be-paragraph', block);\r\n\r\n if (!block) return null;\r\n const isEmpty = isRunsEmpty(store, block.contentIds);\r\n const dir = resolveBlockDir(store, block);\r\n\r\n return (\r\n <div\r\n className={className}\r\n data-block-id={id}\r\n data-empty={isEmpty ? '' : undefined}\r\n data-placeholder=\"Type '/' for commands\"\r\n dir={dir}\r\n >\r\n <EditableBlockContent\r\n blockId={id}\r\n runIds={block.contentIds}\r\n dir={dir}\r\n onEnter={handleEnter}\r\n onBackspaceAtStart={handleBackspaceAtStart}\r\n onArrowUp={handleArrowUp}\r\n onArrowDown={handleArrowDown}\r\n onAutoformat={handleAutoformat}\r\n />\r\n </div>\r\n );\r\n}\r\n","/**\r\n * Serialization for a single inline Run. Shared by every leaf block type\r\n * (paragraph, heading, list item title, table cell) so formatting logic is\r\n * written exactly once instead of once per block type.\r\n *\r\n * `ctx.inlineRegistry` is optional — callers that don't mix in any\r\n * non-text inline types (or are serializing a run known to be plain text)\r\n * can omit it; a non-text run with no registry available just falls back\r\n * to its raw `value` rather than throwing.\r\n */\r\n\r\nexport function escapeHTML(str) {\r\n return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\r\n}\r\n\r\nexport function escapeAttr(str) {\r\n return escapeHTML(str).replace(/\"/g, '&quot;');\r\n}\r\n\r\nexport function runToHTML(run, ctx) {\r\n if (!run) return '';\r\n\r\n if (run.type !== 'text') {\r\n const entry = ctx?.inlineRegistry?.get(run.type);\r\n return entry ? entry.toHTML(run, ctx) : escapeHTML(run.value ?? '');\r\n }\r\n\r\n const marks = run.marks ?? {};\r\n let html = escapeHTML(run.value ?? '');\r\n if (marks.code) html = `<code>${html}</code>`;\r\n if (marks.bold) html = `<strong>${html}</strong>`;\r\n if (marks.italic) html = `<em>${html}</em>`;\r\n if (marks.underline) html = `<u>${html}</u>`;\r\n if (marks.strike) html = `<s>${html}</s>`;\r\n if (marks.subscript) html = `<sub>${html}</sub>`;\r\n if (marks.superscript) html = `<sup>${html}</sup>`;\r\n if (marks.color) html = `<span style=\"color:${escapeAttr(marks.color)}\">${html}</span>`;\r\n if (marks.highlight) html = `<span style=\"background-color:${escapeAttr(marks.highlight)}\">${html}</span>`;\r\n if (marks.link?.href) {\r\n const targetAttrs = marks.link.target === '_blank' ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : '';\r\n html = `<a href=\"${escapeAttr(marks.link.href)}\"${targetAttrs}>${html}</a>`;\r\n }\r\n return html;\r\n}\r\n\r\n/** Serializes a whole ordered run list to one HTML string — every leaf block's own toHTML already inlines exactly this. */\r\nexport function runsToHTML(runs, ctx) {\r\n return (runs ?? []).map((run) => runToHTML(run, ctx)).join('');\r\n}\r\n\r\nexport function runToPlainText(run, ctx) {\r\n if (!run) return '';\r\n if (run.type !== 'text') {\r\n const entry = ctx?.inlineRegistry?.get(run.type);\r\n return entry ? entry.toPlainText(run, ctx) : (run.value ?? '');\r\n }\r\n return run.value ?? '';\r\n}\r\n","import { genId } from '../utils/idGen.js';\r\n\r\nconst TAG_TO_MARK = {\r\n STRONG: 'bold',\r\n B: 'bold',\r\n EM: 'italic',\r\n I: 'italic',\r\n U: 'underline',\r\n S: 'strike',\r\n STRIKE: 'strike',\r\n DEL: 'strike',\r\n CODE: 'code',\r\n SUB: 'subscript',\r\n SUP: 'superscript',\r\n};\r\n\r\n/**\r\n * Walks a DOM node's inline children (text + <strong>/<em>/<a>/etc., plus\r\n * any registered non-text inline type like a select chip) and produces an\r\n * array of Run objects carrying the accumulated marks. Reused by every leaf\r\n * block type's fromHTML matcher so paste-formatting logic is written once,\r\n * not duplicated per block type.\r\n *\r\n * `ctx.inlineRegistry` is optional — omit it if the caller never mixes in\r\n * non-text inline types (matched elements just fall through to their own\r\n * text content instead).\r\n */\r\nexport function domInlineToRuns(node, ctx, activeMarks = {}) {\r\n const runs = [];\r\n\r\n const walk = (n, marks) => {\r\n if (n.nodeType === 3 /* TEXT_NODE */) {\r\n const value = n.textContent;\r\n if (value) runs.push({ id: genId(), type: 'text', value, marks: { ...marks } });\r\n return;\r\n }\r\n if (n.nodeType !== 1 /* ELEMENT_NODE */) return;\r\n\r\n if (ctx?.inlineRegistry) {\r\n for (const entry of ctx.inlineRegistry.listHtmlMatchers()) {\r\n const run = entry.fromHTML(n, ctx);\r\n if (run) {\r\n runs.push(run);\r\n return; // atomic: don't also walk its children as plain text\r\n }\r\n }\r\n }\r\n\r\n let nextMarks = marks;\r\n const markName = TAG_TO_MARK[n.tagName];\r\n if (markName) nextMarks = { ...nextMarks, [markName]: true };\r\n if (n.tagName === 'A' && n.getAttribute('href')) {\r\n nextMarks = { ...nextMarks, link: { href: n.getAttribute('href'), target: n.getAttribute('target') === '_blank' ? '_blank' : '_self' } };\r\n }\r\n // Color/highlight round-trip via inline style (see marks.js's runToHTML)\r\n // rather than a fixed tag — style.color/backgroundColor are only ever\r\n // set by us in that exact shape, so reading them back is unambiguous\r\n // for our own copy/paste; arbitrary third-party HTML with these styles\r\n // picks up the same treatment, which is a reasonable default.\r\n if (n.style?.color) nextMarks = { ...nextMarks, color: n.style.color };\r\n if (n.style?.backgroundColor) nextMarks = { ...nextMarks, highlight: n.style.backgroundColor };\r\n\r\n for (const child of n.childNodes) walk(child, nextMarks);\r\n };\r\n\r\n walk(node, activeMarks);\r\n return runs.length ? runs : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n}\r\n","import { ParagraphBlock } from './ParagraphBlock.jsx';\r\nimport { runToHTML, runToPlainText } from '../../inline/marks.js';\r\nimport { domInlineToRuns } from '../../inline/runOps.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { TextIcon } from '../../react/icons.jsx';\r\n\r\nfunction toHTML(block, ctx) {\r\n const runs = block.contentIds.map((runId) => ctx.store.getRun(runId));\r\n return `<p>${runs.map((r) => runToHTML(r, ctx)).join('')}</p>`;\r\n}\r\n\r\nfunction toPlainText(block, ctx) {\r\n return block.contentIds.map((runId) => runToPlainText(ctx.store.getRun(runId), ctx)).join('');\r\n}\r\n\r\nfunction fromHTML(node, ctx) {\r\n if (node.tagName !== 'P') return null;\r\n const runs = domInlineToRuns(node, ctx);\r\n const block = { id: genId(), type: 'paragraph', parentId: null, contentIds: runs.map((r) => r.id), props: {} };\r\n return { block, runs };\r\n}\r\n\r\nexport const paragraphBlockType = {\r\n component: ParagraphBlock,\r\n isLeaf: true,\r\n defaultProps: {},\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: {\r\n label: 'Text',\r\n icon: TextIcon,\r\n keywords: ['paragraph', 'text', 'p'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createTextLeafBlock('paragraph')),\r\n },\r\n};\r\n","import { useCallback } from 'react';\r\nimport { EditableBlockContent } from '../../react/EditableBlockContent.jsx';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useSelectedBlock, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { insertSiblingSplitAtCaretAndFocus } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { mergeWithPreviousOrDelete } from '../shared/mergeCommands.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { focusAfterMerge } from '../shared/focusAfterMerge.js';\r\nimport { focusAdjacentBlock } from '../shared/navigationCommands.js';\r\nimport { resolveBlockDir } from '../shared/resolveBlockDir.js';\r\n\r\nexport function HeadingBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n const { setSelectedBlockId } = useSelectedBlock();\r\n\r\n const handleEnter = useCallback(() => {\r\n insertSiblingSplitAtCaretAndFocus(store, id, block?.contentIds ?? [], createTextLeafBlock('paragraph'));\r\n }, [store, id, block]);\r\n\r\n const handleBackspaceAtStart = useCallback(() => {\r\n const focusBlockId = mergeWithPreviousOrDelete(store, id);\r\n focusAfterMerge(store, focusBlockId, id, setSelectedBlockId);\r\n }, [store, id, setSelectedBlockId]);\r\n\r\n const handleArrowUp = useCallback(() => focusAdjacentBlock(store, id, 'up'), [store, id]);\r\n const handleArrowDown = useCallback(() => focusAdjacentBlock(store, id, 'down'), [store, id]);\r\n\r\n // A level-specific class (be-heading-1/2/3) alongside the shared\r\n // be-heading one — lets a host style/override each heading level\r\n // independently (font-size, etc.) via a real class instead of having to\r\n // rely on h1/h2/h3 tag-selector specificity tricks, and gives\r\n // getBlockClassName's own extra string a distinct per-level hook too.\r\n const level = block?.props?.level ?? 3;\r\n const className = useBlockClassName(`be-heading be-heading-${level}`, block);\r\n\r\n if (!block) return null;\r\n const Tag = `h${level}`;\r\n const isEmpty = isRunsEmpty(store, block.contentIds);\r\n const dir = resolveBlockDir(store, block);\r\n\r\n return (\r\n <Tag\r\n className={className}\r\n data-block-id={id}\r\n data-empty={isEmpty ? '' : undefined}\r\n data-placeholder={`Heading ${level}`}\r\n dir={dir}\r\n >\r\n <EditableBlockContent\r\n blockId={id}\r\n runIds={block.contentIds}\r\n dir={dir}\r\n onEnter={handleEnter}\r\n onBackspaceAtStart={handleBackspaceAtStart}\r\n onArrowUp={handleArrowUp}\r\n onArrowDown={handleArrowDown}\r\n />\r\n </Tag>\r\n );\r\n}\r\n","import { HeadingBlock } from './HeadingBlock.jsx';\r\nimport { runToHTML, runToPlainText } from '../../inline/marks.js';\r\nimport { domInlineToRuns } from '../../inline/runOps.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { Heading1Icon, Heading2Icon, Heading3Icon } from '../../react/icons.jsx';\r\n\r\nconst HEADING_ICONS = { 1: Heading1Icon, 2: Heading2Icon, 3: Heading3Icon };\r\n\r\nconst TAG_TO_LEVEL = { H1: 1, H2: 2, H3: 3 };\r\n\r\nfunction toHTML(block, ctx) {\r\n const level = block.props?.level ?? 3;\r\n const runs = block.contentIds.map((runId) => ctx.store.getRun(runId));\r\n return `<h${level}>${runs.map((r) => runToHTML(r, ctx)).join('')}</h${level}>`;\r\n}\r\n\r\nfunction toPlainText(block, ctx) {\r\n return block.contentIds.map((runId) => runToPlainText(ctx.store.getRun(runId), ctx)).join('');\r\n}\r\n\r\nfunction fromHTML(node, ctx) {\r\n const level = TAG_TO_LEVEL[node.tagName];\r\n if (!level) return null;\r\n const runs = domInlineToRuns(node, ctx);\r\n const block = {\r\n id: genId(),\r\n type: 'heading',\r\n parentId: null,\r\n contentIds: runs.map((r) => r.id),\r\n props: { level },\r\n };\r\n return { block, runs };\r\n}\r\n\r\nexport const headingBlockType = {\r\n component: HeadingBlock,\r\n isLeaf: true,\r\n defaultProps: { level: 3 },\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommands: [\r\n {\r\n label: 'Heading 1',\r\n icon: HEADING_ICONS[1],\r\n keywords: ['heading', 'h1', 'title'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createTextLeafBlock('heading', { level: 1 })),\r\n },\r\n {\r\n label: 'Heading 2',\r\n icon: HEADING_ICONS[2],\r\n keywords: ['heading', 'h2', 'subtitle'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createTextLeafBlock('heading', { level: 2 })),\r\n },\r\n {\r\n label: 'Heading 3',\r\n icon: HEADING_ICONS[3],\r\n keywords: ['heading', 'h3', 'title'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createTextLeafBlock('heading', { level: 3 })),\r\n },\r\n ],\r\n};\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useEditorStore } from './EditorProvider.jsx';\r\n\r\n// Stable empty-array reference so a not-yet-existing/childless block never\r\n// trips the useSyncExternalStore \"snapshot changed\" check by returning a\r\n// fresh [] every call.\r\nconst EMPTY_CONTENT_IDS = [];\r\n\r\n/**\r\n * Subscribes only to a block's `contentIds` array reference. EditorStore\r\n * only replaces that reference when membership/order actually changes\r\n * (insert/remove/move), never on a leaf edit inside one of the children —\r\n * so this hook (and the list-rendering component that calls it) does not\r\n * re-render on every keystroke inside a child, only on structural changes.\r\n */\r\nexport function useBlockChildren(parentId) {\r\n const store = useEditorStore();\r\n const subscribe = useCallback((onStoreChange) => store.subscribe(parentId, onStoreChange), [store, parentId]);\r\n const getSnapshot = useCallback(() => {\r\n const block = store.getBlock(parentId);\r\n return block ? block.contentIds : EMPTY_CONTENT_IDS;\r\n }, [store, parentId]);\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { Component, Fragment } from 'react';\r\n\r\n/**\r\n * Wraps a single block's rendered output so that a crash in one block (e.g.\r\n * a contentEditable/DOM desync throwing during React's commit phase) can't\r\n * take the whole document down with it — without this, an uncaught error\r\n * from any single block unmounts the entire root, blanking the page for a\r\n * problem that only ever affected one paragraph.\r\n *\r\n * Recovery is a full remount, not a permanent fallback message: the DOM\r\n * subtree that threw may be in a state React no longer trusts, so the only\r\n * sound way back is to throw it away and rebuild fresh from the current\r\n * store state, which is unaffected (the store is a separate source of\r\n * truth from the DOM). Bumping `nonce` and keying a Fragment on it forces\r\n * exactly that remount with zero extra DOM nodes. Recovery happens on the\r\n * next microtask so React finishes unwinding the failed commit first.\r\n */\r\nexport class BlockErrorBoundary extends Component {\r\n state = { hasError: false, nonce: 0 };\r\n\r\n static getDerivedStateFromError() {\r\n return { hasError: true };\r\n }\r\n\r\n componentDidCatch(error, info) {\r\n if (process.env.NODE_ENV !== 'production') {\r\n // eslint-disable-next-line no-console\r\n console.error('[block-editor] a block failed to render; recovering by remounting it:', error, info);\r\n }\r\n this.props.onError?.(error, info);\r\n queueMicrotask(() => this.setState((s) => ({ hasError: false, nonce: s.nonce + 1 })));\r\n }\r\n\r\n render() {\r\n if (this.state.hasError) return null; // one brief frame while recovery is queued\r\n return <Fragment key={this.state.nonce}>{this.props.children}</Fragment>;\r\n }\r\n}\r\n","import { memo } from 'react';\r\nimport { useBlock } from './useBlock.js';\r\nimport { useBlockRegistry } from './EditorProvider.jsx';\r\nimport { BlockErrorBoundary } from './BlockErrorBoundary.jsx';\r\n\r\n/**\r\n * Recursive entry point: given a block id, looks up its type in the\r\n * registry and renders that type's component. Every block component (leaf\r\n * or container) receives only `id` — never the whole document — and is\r\n * memoized here so unrelated blocks skip re-rendering when a sibling's\r\n * data changes elsewhere in the tree.\r\n */\r\nexport const BlockRenderer = memo(function BlockRenderer({ id }) {\r\n const block = useBlock(id);\r\n const registry = useBlockRegistry();\r\n\r\n if (!block) return null; // about to be removed this frame; render nothing\r\n\r\n const entry = registry.get(block.type);\r\n if (!entry) {\r\n if (process.env.NODE_ENV !== 'production') {\r\n // eslint-disable-next-line no-console\r\n console.warn(`[block-editor] No block type registered for \"${block.type}\" (id: ${id})`);\r\n }\r\n return null;\r\n }\r\n\r\n const Component = entry.component;\r\n return (\r\n <BlockErrorBoundary>\r\n <Component id={id} />\r\n </BlockErrorBoundary>\r\n );\r\n});\r\n","import { useEffect } from 'react';\r\n\r\n/**\r\n * Closes whatever `isOpen` gates when the user clicks outside every ref in\r\n * `refs`, or presses Escape — the same ~15-line pattern this codebase\r\n * previously copy-pasted independently in FloatingToolbar, TableHeaderRow's\r\n * column menu, and Modal. Extracted here so a new consumer (Select) doesn't\r\n * need a fourth copy; the existing three call sites are left as-is (their\r\n * own small variations — e.g. Modal's backdrop-click check — aren't worth\r\n * disturbing for this).\r\n *\r\n * `refs` accepts either a single ref or an array of refs — a consumer whose\r\n * popover is portaled somewhere else in the DOM (e.g. Select's popover,\r\n * portaled to document.body so it isn't nested inside a contentEditable\r\n * region) needs a second ref for that portaled element, since it's no\r\n * longer a DOM descendant of the trigger's own root.\r\n */\r\nexport function useOutsideClickAndEscape(refs, isOpen, onClose) {\r\n useEffect(() => {\r\n if (!isOpen) return undefined;\r\n const refList = Array.isArray(refs) ? refs : [refs];\r\n const handlePointerDown = (event) => {\r\n const inside = refList.some((ref) => ref.current && ref.current.contains(event.target));\r\n if (!inside) onClose();\r\n };\r\n const handleKeyDown = (event) => {\r\n if (event.key === 'Escape') onClose();\r\n };\r\n document.addEventListener('mousedown', handlePointerDown);\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => {\r\n document.removeEventListener('mousedown', handlePointerDown);\r\n document.removeEventListener('keydown', handleKeyDown);\r\n };\r\n }, [isOpen, onClose, refs]);\r\n}\r\n","import { useEffect, useRef } from 'react';\n\n/**\n * Makes a portaled `role=\"menu\"` popover keyboard-operable: on open, moves\n * real DOM focus onto its first `[role=\"menuitem\"]`; ArrowDown/ArrowUp move\n * focus between items (wrapping), Home/End jump to the first/last, and\n * Escape calls `onClose()` and returns focus to `triggerRef.current`.\n * Activating an item (Enter/Space) is already handled by each item being a\n * real `<button>` — no extra wiring needed for that part.\n *\n * Modeled on Select.jsx's own already-working real-focus-move pattern\n * (not SlashMenu's activedescendant one) — these are standalone action\n * menus, not inline-typeahead where staying in the surrounding text\n * matters, so moving real focus into the menu is the right (and simpler)\n * choice here. Needed because these menus are portaled to `document.body`\n * (escaping ancestor `overflow` clipping, same reason Select's popover is\n * portaled) — being disconnected from the trigger in DOM order means a\n * keyboard user tabbing forward from the trigger would never reach the\n * menu at all without this.\n *\n * Each caller keeps its own `useOutsideClickAndEscape` for outside-click\n * dismissal — this hook only owns the *keyboard* half (arrow nav + this\n * menu's own Escape-with-focus-restore), which outside-click handling\n * doesn't provide on its own.\n */\nexport function useMenuKeyboardNav(menuRef, isOpen, onClose, triggerRef) {\n const wasOpenRef = useRef(false);\n const didFocusRef = useRef(false);\n\n // Deliberately no dependency array: some menus (BlockRangeActionMenu, in\n // particular) compute their portal position via a separate effect that\n // runs *after* `isOpen` flips true, so `menuRef.current` is still null on\n // the render where `isOpen` first becomes true — the menu only mounts on\n // a follow-up render once that position state lands. Re-checking after\n // every render (instead of only when `isOpen` changes) means this hook\n // picks the menu up on that follow-up render too, without caring whether\n // the caller mounts the menu synchronously or a tick later. `didFocusRef`\n // keeps first-item focus a one-time-per-open-session thing rather than\n // re-stealing focus back to item 0 on every subsequent re-render while\n // still open (e.g. BlockRangeActionMenu's own rect recompute on scroll).\n useEffect(() => {\n if (!isOpen) {\n didFocusRef.current = false;\n if (wasOpenRef.current) {\n wasOpenRef.current = false;\n triggerRef?.current?.focus?.();\n }\n return undefined;\n }\n wasOpenRef.current = true;\n\n const menu = menuRef.current;\n if (!menu) return undefined;\n\n const items = () => Array.from(menu.querySelectorAll('[role=\"menuitem\"]'));\n\n const focusItem = (index) => {\n const list = items();\n if (list.length === 0) return;\n const clamped = ((index % list.length) + list.length) % list.length;\n list[clamped]?.focus();\n };\n\n if (!didFocusRef.current) {\n didFocusRef.current = true;\n focusItem(0);\n }\n\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n onClose();\n return;\n }\n\n // Some menus (the table column menu, in particular) mix real\n // menuitems with other interactive content (a type <Select>, a\n // rename <input>) — only hijack arrow/Home/End when focus is\n // actually ON one of the tracked menuitems, so typing in an input\n // or arrowing through a Select's own popover elsewhere in the same\n // menu is never interrupted.\n const list = items();\n const currentIndex = list.indexOf(document.activeElement);\n if (currentIndex === -1) return;\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n focusItem(currentIndex + 1);\n } else if (event.key === 'ArrowUp') {\n event.preventDefault();\n focusItem(currentIndex - 1);\n } else if (event.key === 'Home') {\n event.preventDefault();\n focusItem(0);\n } else if (event.key === 'End') {\n event.preventDefault();\n focusItem(list.length - 1);\n }\n };\n\n menu.addEventListener('keydown', handleKeyDown);\n return () => menu.removeEventListener('keydown', handleKeyDown);\n });\n}\n","const LIVE_REGION_ID = 'be-live-region';\n\n/**\n * Lazily creates (once — idempotent, same singleton pattern as\n * injectDefaultStyles.js) a visually-hidden `aria-live=\"polite\"` region\n * appended to `document.body`, so screen-reader users get an announcement\n * for structural actions that don't otherwise move focus anywhere\n * describable (duplicate/move/hide/delete a block or a block range) —\n * previously there was no `aria-live` region anywhere in this codebase at\n * all, so none of those actions were announced.\n */\nfunction getOrCreateLiveRegion() {\n if (typeof document === 'undefined') return null; // SSR guard\n let region = document.getElementById(LIVE_REGION_ID);\n if (region) return region;\n\n region = document.createElement('div');\n region.id = LIVE_REGION_ID;\n region.setAttribute('role', 'status');\n region.setAttribute('aria-live', 'polite');\n region.setAttribute('aria-atomic', 'true');\n // Visually hidden but still exposed to assistive tech (the standard\n // \"clip\" pattern — display:none/visibility:hidden would hide it from\n // screen readers too, defeating the point).\n Object.assign(region.style, {\n position: 'absolute',\n width: '1px',\n height: '1px',\n margin: '-1px',\n padding: '0',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: '0',\n });\n document.body.appendChild(region);\n return region;\n}\n\n/**\n * Announces `message` via the shared live region. Clears the region's\n * text first (on a microtask-length delay) before setting the new\n * message — most screen readers only announce an `aria-live` region when\n * its *text content changes*, so announcing the same message twice in a\n * row (e.g. \"Block deleted\" after two separate deletes) would otherwise\n * silently not fire the second time.\n */\nexport function announce(message) {\n const region = getOrCreateLiveRegion();\n if (!region) return;\n region.textContent = '';\n // setTimeout(0), not a microtask — needs to land in a separate paint/\n // AT-observation tick from the clear above for some screen readers to\n // register the change as new content rather than coalescing both writes\n // into one.\n setTimeout(() => {\n region.textContent = message;\n }, 0);\n}\n","import { genId } from '../../utils/idGen.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\n\r\nexport const DEFAULT_CALLOUT_ICON = '💡';\r\n\r\n/**\r\n * factory(parentId) -> {block, runs, subtreeBlocks} for a fresh callout —\r\n * a plain container (same contentIds-holds-child-block-ids shape as\r\n * layoutColumn/page) plus an `icon` prop, seeded with one empty paragraph\r\n * so there's somewhere to type immediately (same convention as\r\n * createLayoutBlock's columns).\r\n */\r\nexport const DEFAULT_CALLOUT_COLOR = 'gray';\r\n\r\nexport function createCalloutBlock({ icon = DEFAULT_CALLOUT_ICON, color = DEFAULT_CALLOUT_COLOR } = {}) {\r\n return function factory(parentId) {\r\n const calloutId = genId();\r\n const { block: paragraphBlock, runs } = createTextLeafBlock('paragraph')(calloutId);\r\n const block = { id: calloutId, type: 'callout', parentId, contentIds: [paragraphBlock.id], props: { icon, color } };\r\n return { block, runs, subtreeBlocks: [paragraphBlock] };\r\n };\r\n}\r\n","import { convertBlockType } from './convertBlockType.js';\nimport { updateRun } from '../../store/operations.js';\nimport { DEFAULT_CALLOUT_ICON } from '../callout/createCalloutBlock.js';\nimport {\n TextIcon,\n Heading1Icon,\n Heading2Icon,\n Heading3Icon,\n BulletedListIcon,\n NumberedListIcon,\n CheckboxIcon,\n ChevronRightIcon,\n QuoteIcon,\n CalloutIcon,\n CodeIcon,\n} from '../../react/icons.jsx';\n\n/**\n * The \"text family\" — every block type this codebase's own R&D pass (see\n * README/commit history) settled on as freely inter-convertible, matching\n * the same boundary most block editors independently draw:\n * blocks holding rich/plain text content. Deliberately excludes the\n * \"structural\" group (table, layout/layoutColumn, embed, divider, button)\n * — few block editors offer generic type-conversion for those\n * either; they keep their own dedicated creation/management UI instead.\n *\n * Each entry's `props` matches the exact shape that type's own slash\n * command already inserts with (see e.g. `markdownShortcuts.js`'s RULES,\n * or each block type's own `index.js` `slashCommand(s)`) — this is data,\n * not new conversion logic.\n */\nexport const TEXT_FAMILY_TARGETS = [\n { type: 'paragraph', props: {}, label: 'Text', icon: TextIcon },\n { type: 'heading', props: { level: 1 }, label: 'Heading 1', icon: Heading1Icon },\n { type: 'heading', props: { level: 2 }, label: 'Heading 2', icon: Heading2Icon },\n { type: 'heading', props: { level: 3 }, label: 'Heading 3', icon: Heading3Icon },\n { type: 'listItem', props: { ordered: false, titleRunIds: [] }, label: 'Bulleted list', icon: BulletedListIcon },\n { type: 'listItem', props: { ordered: true, titleRunIds: [] }, label: 'Numbered list', icon: NumberedListIcon },\n {\n type: 'listItem',\n props: { ordered: false, checked: false, titleRunIds: [] },\n label: 'To-do list',\n icon: CheckboxIcon,\n },\n {\n type: 'listItem',\n props: { ordered: false, collapsed: false, titleRunIds: [] },\n label: 'Toggle list',\n icon: ChevronRightIcon,\n },\n {\n type: 'toggleHeading',\n props: { level: 2, collapsed: false, titleRunIds: [] },\n label: 'Toggle heading',\n icon: ChevronRightIcon,\n },\n { type: 'blockquote', props: {}, label: 'Quote', icon: QuoteIcon },\n { type: 'callout', props: { icon: DEFAULT_CALLOUT_ICON }, label: 'Callout', icon: CalloutIcon },\n { type: 'code', props: { language: 'plaintext' }, label: 'Code', icon: CodeIcon },\n];\n\nconst TEXT_FAMILY_TYPES = new Set(TEXT_FAMILY_TARGETS.map((t) => t.type));\n\n/** Single source of truth for \"is this block type offered by Turn into at all\" — menu visibility and range-selection filtering both key off this. */\nexport function isTurnIntoEligible(type) {\n return TEXT_FAMILY_TYPES.has(type);\n}\n\n/**\n * A block's own inline text run ids -- `props.titleRunIds` for a container\n * that has them (listItem, toggleHeading), or `contentIds` for a leaf\n * (paragraph, heading, blockquote, code), since a leaf's contentIds *are*\n * its runs. A container WITHOUT titleRunIds (callout) owns no text runs of\n * its own at all -- its contentIds are child blocks (e.g. a nested\n * paragraph that holds the actual text), not runs -- so it must report no\n * own runIds rather than have its children's block ids misread as run ids.\n * Requires `registry` to tell \"leaf whose contentIds are runs\" apart from\n * \"container whose contentIds are children\"; without one, only a leaf\n * shape is assumed (matches this function's own two other callers, which\n * only ever operate on a fresh, childless, single-run paragraph).\n */\nfunction getOwnRunIds(block, registry) {\n if (block?.props && 'titleRunIds' in block.props) return block.props.titleRunIds;\n if (registry && !registry.isLeaf(block?.type)) return [];\n return block?.contentIds ?? [];\n}\n\n/**\n * Converts one block to `target` ({ type, props }), reusing\n * `convertBlockType` — this is the one shared place `getOwnRunIds` and the\n * \"strip marks when converting into code\" rule live, rather than\n * duplicating either per call site (gutter menu vs. range menu).\n *\n * Marks are stripped only when the target is `code` — code shouldn't carry\n * bold/italic/etc (its own `toHTML` never emits mark tags either) — via\n * plain `updateRun` ops folded into the same batch, so it's still one\n * atomic undo step. This is scoped entirely to this new call path; it\n * never touches `convertBlockType` itself or its two original callers.\n *\n * Returns `{ ops, newBlockId }`, same contract as `convertBlockType` — the\n * caller applies `ops` as one batch (directly, or concatenated with other\n * blocks' ops for a multi-block conversion).\n */\nexport function turnBlockInto(store, registry, blockId, target) {\n const block = store.getBlock(blockId);\n const runIds = getOwnRunIds(block, registry);\n\n const ops = [];\n if (target.type === 'code') {\n for (const runId of runIds) {\n const run = store.getRun(runId);\n if (run?.marks && Object.keys(run.marks).length > 0) ops.push(updateRun(runId, { marks: {} }));\n }\n }\n\n // Cloned, not passed by reference — TEXT_FAMILY_TARGETS entries are\n // shared module-level objects reused across every conversion; convertBlockType\n // hands `props` straight to the new block as-is, so a raw shared reference\n // here would mean every block converted via the same menu entry ends up\n // pointing at the exact same props object.\n const props = { ...target.props };\n const { ops: convertOps, newBlockId } = convertBlockType(store, blockId, target.type, props, runIds, registry);\n return { ops: [...ops, ...convertOps], newBlockId };\n}\n","import { useCallback, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useOutsideClickAndEscape } from './useOutsideClickAndEscape.js';\nimport { useMenuKeyboardNav } from './useMenuKeyboardNav.js';\nimport { useAutoAdjustedPosition } from './useAutoAdjustedPosition.js';\nimport { TEXT_FAMILY_TARGETS } from '../blocks/shared/turnInto.js';\nimport { ChevronRightIcon } from './icons.jsx';\n\n/**\n * A menu item that opens a second, nested `role=\"menu\"` listing every\n * `TEXT_FAMILY_TARGETS` entry — the one reusable \"submenu\" this codebase\n * has (see turnInto.js's plan doc comment: no prior submenu pattern\n * existed here). Modeled directly on BlockGutterRow's own portaled-menu\n * convention (own `rect` off the trigger's own `getBoundingClientRect()`,\n * own `menuRef` + `useMenuKeyboardNav` + `useOutsideClickAndEscape`) rather\n * than introducing a new one.\n *\n * `onSelect(target)` is called with the chosen `{ type, props, label, icon }`\n * entry; the caller (BlockGutterRow / BlockRangeActionMenu) owns actually\n * converting the block(s) and closing its own outer menu — this component\n * only owns picking a target and closing itself, via `onClose()`, which the\n * caller passes down (its Escape/outside-click here calls `onClose` only,\n * never the outer menu's).\n *\n * `containerRef` (optional) receives the submenu's own portaled DOM node —\n * the caller (BlockGutterRow/BlockRangeActionMenu) must fold it into its\n * OWN outer menu's outside-click ref list. Without this, a click on a\n * submenu item registers as \"outside\" the outer menu (the submenu portal is\n * a DOM sibling of the outer menu, not a descendant of it, even though it's\n * a React child of this component) — the outer menu's own\n * useOutsideClickAndEscape closes it on `mousedown`, unmounting this\n * component and its submenu *before* the follow-up `click` event that would\n * have actually fired `onSelect` ever reaches the browser, so selecting a\n * target silently did nothing.\n *\n * ArrowRight on the trigger opens the submenu (focusing its first item, via\n * useMenuKeyboardNav's own on-open behavior); ArrowLeft anywhere inside the\n * submenu closes it and returns focus to the trigger (via that same hook's\n * on-close behavior) — the standard nested-menu convention (most native OS\n * menus, and most block editors) alongside Escape/outside-click, which already worked.\n */\nexport function TurnIntoSubmenu({ onSelect, onClose, containerRef, menuClassName = 'be-block-gutter-menu', itemClassName = 'be-block-gutter-menu-item' }) {\n const [isOpen, setIsOpen] = useState(false);\n const [rect, setRect] = useState(null);\n const triggerRef = useRef(null);\n const menuRef = useRef(null);\n\n const setMenuRef = useCallback(\n (el) => {\n menuRef.current = el;\n if (containerRef) containerRef.current = el;\n },\n [containerRef],\n );\n\n const close = useCallback(() => {\n setIsOpen(false);\n onClose?.();\n }, [onClose]);\n\n useOutsideClickAndEscape([triggerRef, menuRef], isOpen, close);\n useMenuKeyboardNav(menuRef, isOpen, close, triggerRef);\n\n const position = useAutoAdjustedPosition(menuRef, isOpen, rect?.top, rect ? rect.right + 4 : null);\n\n const open = useCallback(() => {\n setRect(triggerRef.current?.getBoundingClientRect() ?? null);\n setIsOpen(true);\n }, []);\n\n const handleSelect = useCallback(\n (target) => {\n onSelect(target);\n close();\n },\n [onSelect, close],\n );\n\n const handleTriggerKeyDown = useCallback(\n (event) => {\n if (event.key === 'ArrowRight' && !isOpen) {\n event.preventDefault();\n open();\n }\n },\n [isOpen, open],\n );\n\n const handleSubmenuKeyDown = useCallback(\n (event) => {\n if (event.key === 'ArrowLeft') {\n event.preventDefault();\n close();\n }\n },\n [close],\n );\n\n return (\n <>\n <button\n ref={triggerRef}\n type=\"button\"\n role=\"menuitem\"\n className={itemClassName}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n onClick={() => (isOpen ? close() : open())}\n onKeyDown={handleTriggerKeyDown}\n >\n <ChevronRightIcon size={15} /> Turn into\n </button>\n {isOpen &&\n position &&\n createPortal(\n <div\n ref={setMenuRef}\n role=\"menu\"\n aria-label=\"Turn into\"\n className={menuClassName}\n style={{ position: 'fixed', top: position.top, left: position.left }}\n onKeyDown={handleSubmenuKeyDown}\n >\n {TEXT_FAMILY_TARGETS.map((target, i) => {\n const Icon = target.icon;\n return (\n <button\n key={`${target.type}-${i}`}\n type=\"button\"\n role=\"menuitem\"\n className={itemClassName}\n onClick={() => handleSelect(target)}\n >\n <Icon size={15} /> {target.label}\n </button>\n );\n })}\n </div>,\n document.body,\n )}\n </>\n );\n}\n","import { insertBlock, removeBlock, moveBlock } from '../../store/operations.js';\r\nimport { captureSubtree, remapSubtreeIds } from '../../clipboard/serialize.js';\r\nimport { focusBlockStart } from './navigationCommands.js';\r\nimport { ensureRootNonEmpty } from './ensureRootNonEmpty.js';\r\n\r\n/**\r\n * Clones `blockId`'s entire subtree (itself + every descendant + their\r\n * runs, all with fresh ids — see remapSubtreeIds) and inserts the copy\r\n * right after the original, then focuses the copy's own first typeable\r\n * position. Reuses the exact same subtree-capture/id-remap machinery the\r\n * same-editor clipboard JSON path already relies on (see serialize.js) —\r\n * \"duplicate\" is exactly \"copy, then paste right after itself.\"\r\n */\r\nexport function duplicateBlock(store, blockId) {\r\n const original = store.getBlock(blockId);\r\n if (!original) return null;\r\n const parent = store.getBlock(original.parentId);\r\n const index = parent.contentIds.indexOf(blockId);\r\n\r\n const subtree = captureSubtree(store, blockId);\r\n const { block, runs, subtreeBlocks } = remapSubtreeIds(subtree);\r\n\r\n store.applyOperation(insertBlock(block, parent.id, index + 1, { blocks: [block, ...subtreeBlocks], runs }));\r\n focusBlockStart(store, block.id);\r\n return block.id;\r\n}\r\n\r\n/**\r\n * Swaps `blockId` with its previous sibling under the same parent — a\r\n * no-op (returns false) if it's already first. `moveBlock`'s own `toIndex`\r\n * is interpreted against the array *after* the block has already been\r\n * removed from it (see EditorStore's MOVE_BLOCK case) — `index - 1` lands\r\n * it exactly one slot earlier in that already-shifted array, which is\r\n * what makes this a plain adjacent swap rather than needing any special\r\n * \"moving backward\" arithmetic.\r\n */\r\nexport function moveBlockUp(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n const parent = block && store.getBlock(block.parentId);\r\n if (!parent) return false;\r\n const index = parent.contentIds.indexOf(blockId);\r\n if (index <= 0) return false;\r\n store.applyOperation(moveBlock(blockId, parent.id, index - 1));\r\n return true;\r\n}\r\n\r\n/** Symmetric to moveBlockUp: swaps with the next sibling, a no-op if already last. */\r\nexport function moveBlockDown(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n const parent = block && store.getBlock(block.parentId);\r\n if (!parent) return false;\r\n const index = parent.contentIds.indexOf(blockId);\r\n if (index === -1 || index >= parent.contentIds.length - 1) return false;\r\n store.applyOperation(moveBlock(blockId, parent.id, index + 1));\r\n return true;\r\n}\r\n\r\n/**\r\n * Removes `blockId` (its whole subtree) and moves focus to whatever's now\r\n * in its old spot — the previous sibling, or else the next one, or else\r\n * (it was the only top-level block) whatever ensureRootNonEmpty falls back\r\n * to, so there's always still somewhere to land the caret. Same\r\n * prev-or-next-or-fallback convention as unwrapEmptyContainer/\r\n * removeTableAndFocusSibling elsewhere in this codebase.\r\n */\r\nexport function deleteBlockAndFocusSibling(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n if (!block) return null;\r\n const parent = store.getBlock(block.parentId);\r\n const index = parent.contentIds.indexOf(blockId);\r\n const prevId = index > 0 ? parent.contentIds[index - 1] : null;\r\n const nextId = index !== -1 && index < parent.contentIds.length - 1 ? parent.contentIds[index + 1] : null;\r\n\r\n store.applyOperation(removeBlock(blockId));\r\n const fallbackId = ensureRootNonEmpty(store);\r\n const targetId = prevId ?? nextId ?? fallbackId;\r\n if (targetId) focusBlockStart(store, targetId);\r\n return targetId ?? null;\r\n}\r\n","import { useCallback, useMemo, useRef, useState } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { useEditorStore, useBlockRegistry, useBlockRangeSelection } from './EditorProvider.jsx';\r\nimport { useBlock } from './useBlock.js';\r\nimport { useOutsideClickAndEscape } from './useOutsideClickAndEscape.js';\r\nimport { useMenuKeyboardNav } from './useMenuKeyboardNav.js';\r\nimport { useAutoAdjustedPosition } from './useAutoAdjustedPosition.js';\r\nimport { announce } from './liveAnnouncer.js';\r\nimport { BlockRenderer } from './BlockRenderer.jsx';\r\nimport { TurnIntoSubmenu } from './TurnIntoSubmenu.jsx';\r\nimport { insertSiblingAfterAndFocus } from '../blocks/shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../blocks/shared/leafBlockFactory.js';\r\nimport { duplicateBlock, moveBlockUp, moveBlockDown, deleteBlockAndFocusSibling } from '../blocks/shared/blockActions.js';\r\nimport { resolveBlockDir } from '../blocks/shared/resolveBlockDir.js';\r\nimport { isTurnIntoEligible, turnBlockInto } from '../blocks/shared/turnInto.js';\r\nimport { updateBlockProps } from '../store/operations.js';\r\nimport {\r\n PlusIcon,\r\n GripVerticalIcon,\r\n CopyIcon,\r\n ArrowUpIcon,\r\n ArrowDownIcon,\r\n TrashIcon,\r\n EyeIcon,\r\n EyeOffIcon,\r\n AlignLeftIcon,\r\n AlignRightIcon,\r\n} from './icons.jsx';\r\n\r\n/**\r\n * Wraps ONE top-level block with a hover-revealed left gutter — a \"+\" to\r\n * insert a new paragraph right after it, and a grip-handle trigger opening\r\n * a small menu (Duplicate / Move Up / Move Down / Hide-Show / Delete), the\r\n * same per-block affordance most block editors show. Only used for\r\n * TOP-LEVEL blocks (see BlockChildren's `isTopLevel` prop) — nested\r\n * content (list item children, table cells, layout columns) doesn't get\r\n * its own gutter, matching every one of those editors' own convention of\r\n * only offering this at the outermost level. Never rendered at all in\r\n * preview mode (see BlockChildren) — a preview isn't something you edit.\r\n *\r\n * Deliberately does not implement drag-and-drop reordering itself (a much\r\n * larger feature on its own) — the grip icon here is just the\r\n * conventional trigger for the menu; Move Up/Down cover reordering\r\n * instead. The menu is portaled to document.body (position:fixed off the\r\n * trigger's own rect), same convention as Select/SlashMenu/the table\r\n * header menu elsewhere in this codebase.\r\n *\r\n * \"Hide\"/\"Show\" toggles a generic `props.hidden` flag — works on any block\r\n * type since props is a free-form per-block object, no schema change\r\n * needed anywhere. In edit mode a hidden block still renders with full\r\n * functionality, just dimmed (see the be-block-row-hidden CSS) as a visual\r\n * reminder it won't appear once switched to preview mode, where\r\n * BlockChildren skips it entirely instead.\r\n *\r\n * `be-block-row-range-selected` (see useBlockRangeSelection) highlights\r\n * this row when it's part of a drag-selected block range — the actual\r\n * drag-start detection lives in useBlockRangeDrag, mounted once at the\r\n * surface level rather than here, since it needs to catch presses in the\r\n * blank page margin on either side of the content column too, not just\r\n * this row's own narrow gutter.\r\n */\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\nexport function BlockGutterRow({ id }) {\r\n const store = useEditorStore();\r\n const registry = useBlockRegistry();\r\n const block = useBlock(id);\r\n const [isMenuOpen, setIsMenuOpen] = useState(false);\r\n const [rect, setRect] = useState(null);\r\n const triggerRef = useRef(null);\r\n const menuRef = useRef(null);\r\n const turnIntoMenuRef = useRef(null);\r\n // The Turn into item's own submenu is a SEPARATE portal (a DOM sibling of\r\n // this menu, not a descendant, even though it's a React child of it) — it\r\n // must be included here or a click inside it reads as \"outside this menu\"\r\n // and closes (unmounts) everything before the submenu's own click handler\r\n // ever fires. See TurnIntoSubmenu's own doc comment for the full story.\r\n const outsideRefs = useMemo(() => [triggerRef, menuRef, turnIntoMenuRef], []);\r\n const [selectedBlockRange] = useBlockRangeSelection();\r\n const isRangeSelected = selectedBlockRange.includes(id);\r\n\r\n const closeMenu = useCallback(() => setIsMenuOpen(false), []);\r\n useOutsideClickAndEscape(outsideRefs, isMenuOpen, closeMenu);\r\n useMenuKeyboardNav(menuRef, isMenuOpen, closeMenu, triggerRef);\r\n\r\n const openMenu = useCallback(() => {\r\n setRect(triggerRef.current?.getBoundingClientRect() ?? null);\r\n setIsMenuOpen(true);\r\n }, []);\r\n\r\n const position = useAutoAdjustedPosition(menuRef, isMenuOpen, rect?.bottom != null ? rect.bottom + 4 : null, rect?.left);\r\n\r\n const handleAdd = useCallback(() => {\r\n insertSiblingAfterAndFocus(store, id, createTextLeafBlock('paragraph'));\r\n }, [store, id]);\r\n\r\n const handleDuplicate = useCallback(() => {\r\n duplicateBlock(store, id);\r\n announce('Block duplicated');\r\n closeMenu();\r\n }, [store, id, closeMenu]);\r\n\r\n const handleMoveUp = useCallback(() => {\r\n if (moveBlockUp(store, id)) announce('Block moved up');\r\n closeMenu();\r\n }, [store, id, closeMenu]);\r\n\r\n const handleMoveDown = useCallback(() => {\r\n if (moveBlockDown(store, id)) announce('Block moved down');\r\n closeMenu();\r\n }, [store, id, closeMenu]);\r\n\r\n const handleDelete = useCallback(() => {\r\n deleteBlockAndFocusSibling(store, id);\r\n announce('Block deleted');\r\n closeMenu();\r\n }, [store, id, closeMenu]);\r\n\r\n const isHidden = Boolean(block?.props?.hidden);\r\n const handleToggleHidden = useCallback(() => {\r\n store.applyOperation(updateBlockProps(id, { hidden: !isHidden }));\r\n announce(isHidden ? 'Block shown in preview' : 'Block hidden in preview');\r\n closeMenu();\r\n }, [store, id, isHidden, closeMenu]);\r\n\r\n // Explicitly overrides resolveBlockDir's own 'auto'/document-default\r\n // resolution for just this block — for the common case (a document\r\n // that's uniformly one direction) the document-level default this menu\r\n // doesn't touch is all that's needed; this exists for the block that's\r\n // the odd one out (e.g. a single quoted line in the other language).\r\n const isRtl = resolveBlockDir(store, block) === 'rtl';\r\n const handleToggleDir = useCallback(() => {\r\n store.applyOperation(updateBlockProps(id, { dir: isRtl ? 'ltr' : 'rtl' }));\r\n announce(isRtl ? 'Block set to left-to-right' : 'Block set to right-to-left');\r\n closeMenu();\r\n }, [store, id, isRtl, closeMenu]);\r\n\r\n const handleTurnInto = useCallback(\r\n (target) => {\r\n const { ops } = turnBlockInto(store, registry, id, target);\r\n applyOps(store, ops);\r\n announce(`Turned into ${target.label}`);\r\n closeMenu();\r\n },\r\n [store, registry, id, closeMenu],\r\n );\r\n\r\n if (!block) return null;\r\n\r\n return (\r\n <div\r\n className={`be-block-row${isHidden ? ' be-block-row-hidden' : ''}${isRangeSelected ? ' be-block-row-range-selected' : ''}`}\r\n data-block-row-id={id}\r\n dir={resolveBlockDir(store, block)}\r\n >\r\n <div className={`be-block-gutter${isMenuOpen ? ' be-block-gutter-active' : ''}`} contentEditable={false}>\r\n <button type=\"button\" className=\"be-block-gutter-btn\" onClick={handleAdd} aria-label=\"Add block below\">\r\n <PlusIcon size={16} />\r\n </button>\r\n <button\r\n ref={triggerRef}\r\n type=\"button\"\r\n className=\"be-block-gutter-btn\"\r\n aria-label=\"More options\"\r\n aria-haspopup=\"menu\"\r\n aria-expanded={isMenuOpen}\r\n onClick={() => (isMenuOpen ? closeMenu() : openMenu())}\r\n >\r\n <GripVerticalIcon size={16} />\r\n </button>\r\n </div>\r\n <div className=\"be-block-row-content\">\r\n <BlockRenderer id={id} />\r\n </div>\r\n {isMenuOpen &&\r\n position &&\r\n createPortal(\r\n <div\r\n ref={menuRef}\r\n role=\"menu\"\r\n aria-label=\"Block options\"\r\n className=\"be-block-gutter-menu\"\r\n style={{ position: 'fixed', top: position.top, left: position.left }}\r\n >\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-gutter-menu-item\" onClick={handleDuplicate}>\r\n <CopyIcon size={15} /> Duplicate\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-gutter-menu-item\" onClick={handleMoveUp}>\r\n <ArrowUpIcon size={15} /> Move up\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-gutter-menu-item\" onClick={handleMoveDown}>\r\n <ArrowDownIcon size={15} /> Move down\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-gutter-menu-item\" onClick={handleToggleHidden}>\r\n {isHidden ? <EyeIcon size={15} /> : <EyeOffIcon size={15} />}\r\n {isHidden ? 'Show in preview' : 'Hide in preview'}\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-gutter-menu-item\" onClick={handleToggleDir}>\r\n {isRtl ? <AlignLeftIcon size={15} /> : <AlignRightIcon size={15} />}\r\n {isRtl ? 'Switch to left-to-right' : 'Switch to right-to-left'}\r\n </button>\r\n {isTurnIntoEligible(block.type) && (\r\n <TurnIntoSubmenu onSelect={handleTurnInto} onClose={() => {}} containerRef={turnIntoMenuRef} />\r\n )}\r\n <button\r\n type=\"button\"\r\n role=\"menuitem\"\r\n className=\"be-block-gutter-menu-item be-block-gutter-menu-item-danger\"\r\n onClick={handleDelete}\r\n >\r\n <TrashIcon size={15} /> Delete\r\n </button>\r\n </div>,\r\n document.body,\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useBlockChildren } from './useBlockChildren.js';\r\nimport { useEditorStore, usePreviewMode } from './EditorProvider.jsx';\r\nimport { BlockRenderer } from './BlockRenderer.jsx';\r\nimport { BlockGutterRow } from './BlockGutterRow.jsx';\r\n\r\n/**\r\n * Renders the child blocks of any container block. This is the single piece\r\n * of tree-walking logic shared by every container type (page, list item,\r\n * table row, table cell-as-container, layout column) — none of them need\r\n * their own child-rendering loop.\r\n *\r\n * `isTopLevel` opts into wrapping each child with the per-block hover\r\n * gutter (+/duplicate/move/delete/hide — see BlockGutterRow) — pass it only\r\n * for the ONE call site rendering the document's actual top-level blocks\r\n * (the page root), never for a nested container's own children: most block\r\n * editors restrict this affordance to the outermost level only, and\r\n * showing it for a table cell's or list item's own content would\r\n * be visually cramped and semantically confusing (e.g. \"delete\" there\r\n * could read as deleting the cell/item itself or just its content).\r\n *\r\n * In preview mode (see usePreviewMode), the gutter never renders at all —\r\n * a preview isn't something you edit — and any block whose own\r\n * `props.hidden` is true is skipped entirely, at every level (not just\r\n * top-level), rather than rendered dimmed the way edit mode shows it: the\r\n * whole point of \"hidden\" is that it disappears from what a reader\r\n * eventually sees.\r\n */\r\nexport function BlockChildren({ parentId, isTopLevel = false }) {\r\n const contentIds = useBlockChildren(parentId);\r\n const store = useEditorStore();\r\n const [isPreviewMode] = usePreviewMode();\r\n\r\n const visibleIds = isPreviewMode ? contentIds.filter((childId) => !store.getBlock(childId)?.props?.hidden) : contentIds;\r\n\r\n if (isTopLevel && !isPreviewMode) {\r\n return visibleIds.map((childId) => <BlockGutterRow key={childId} id={childId} />);\r\n }\r\n return visibleIds.map((childId) => <BlockRenderer key={childId} id={childId} />);\r\n}\r\n","const ALPHA_START = 'a'.charCodeAt(0);\r\nconst ROMAN_TABLE = [\r\n [1000, 'm'],\r\n [900, 'cm'],\r\n [500, 'd'],\r\n [400, 'cd'],\r\n [100, 'c'],\r\n [90, 'xc'],\r\n [50, 'l'],\r\n [40, 'xl'],\r\n [10, 'x'],\r\n [9, 'ix'],\r\n [5, 'v'],\r\n [4, 'iv'],\r\n [1, 'i'],\r\n];\r\n\r\n/** 1 -> \"a\", 26 -> \"z\", 27 -> \"aa\", ... (spreadsheet-column style, no zero digit). */\r\nfunction toAlpha(n) {\r\n let out = '';\r\n while (n > 0) {\r\n n -= 1;\r\n out = String.fromCharCode(ALPHA_START + (n % 26)) + out;\r\n n = Math.floor(n / 26);\r\n }\r\n return out;\r\n}\r\n\r\nfunction toRoman(n) {\r\n let out = '';\r\n let rest = n;\r\n for (const [value, symbol] of ROMAN_TABLE) {\r\n while (rest >= value) {\r\n out += symbol;\r\n rest -= value;\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * A \"plain\" list item is one whose marker is a bullet/number (not a to-do\r\n * checkbox, not a toggle disclosure triangle) — only these participate in\r\n * numbering/bullet-style cycling at all.\r\n */\r\nfunction isPlainMarkerItem(block) {\r\n return block?.type === 'listItem' && block.props?.checked === undefined && block.props?.collapsed === undefined;\r\n}\r\n\r\n/**\r\n * How many listItem ancestors this block is nested under — 0 for a\r\n * top-level item, 1 for its first nested level, and so on. Cycles every 3\r\n * levels for marker style (a common numbered-list convention:\r\n * 1,2,3 -> a,b,c -> i,ii,iii -> 1,2,3 again as you keep nesting), applied\r\n * uniformly regardless of whether ancestors at those levels happen to be\r\n * ordered, bulleted, or a mix.\r\n */\r\nexport function listItemDepth(store, block) {\r\n let depth = 0;\r\n let current = block;\r\n while (current) {\r\n const parent = store.getBlock(current.parentId);\r\n if (!parent || parent.type !== 'listItem') break;\r\n depth += 1;\r\n current = parent;\r\n }\r\n return depth;\r\n}\r\n\r\n/**\r\n * This item's 1-based position within its *contiguous run* of ordered\r\n * sibling list items — counting backward from this item only while\r\n * immediately-preceding siblings are also plain ordered list items, so\r\n * numbering restarts at 1 after any interruption (a bullet item, a toggle,\r\n * a to-do, or a completely different block type) — a numbered list restarts\r\n * after a break rather than continuing a global counter across the whole\r\n * document.\r\n */\r\nexport function orderedItemIndex(store, block, siblingIds) {\r\n const pos = siblingIds.indexOf(block.id);\r\n let count = 1;\r\n for (let i = pos - 1; i >= 0; i -= 1) {\r\n const sibling = store.getBlock(siblingIds[i]);\r\n if (!isPlainMarkerItem(sibling) || !sibling.props.ordered) break;\r\n count += 1;\r\n }\r\n return count;\r\n}\r\n\r\n/** e.g. depth 0 -> \"1.\", depth 1 -> \"a.\", depth 2 -> \"i.\", depth 3 -> \"1.\" again. */\r\nexport function orderedMarkerText(depth, index) {\r\n const style = ((depth % 3) + 3) % 3;\r\n if (style === 0) return `${index}.`;\r\n if (style === 1) return `${toAlpha(index)}.`;\r\n return `${toRoman(index)}.`;\r\n}\r\n\r\nconst BULLET_GLYPHS = ['•', '◦', '▪'];\r\n\r\n/** e.g. depth 0 -> \"•\" (disc), depth 1 -> \"◦\" (circle), depth 2 -> \"▪\" (square), depth 3 -> \"•\" again. */\r\nexport function bulletMarkerText(depth) {\r\n const style = ((depth % 3) + 3) % 3;\r\n return BULLET_GLYPHS[style];\r\n}\r\n","import { genId } from '../../utils/idGen.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\n\r\n/**\r\n * factory(parentId, initialRuns?) -> {block, runs, subtreeBlocks} for a\r\n * list item. `checked` left undefined (default) renders a bullet/number\r\n * marker; passing a boolean turns it into a to-do item with a checkbox\r\n * marker. `collapsed` left undefined (default) is the same plain bullet/\r\n * number/todo marker; passing a boolean turns it into a \"toggle\" item\r\n * instead — a disclosure triangle marker whose nested children (contentIds)\r\n * render only while `collapsed` is false. `checked` and `collapsed` are\r\n * mutually exclusive markers in the UI (whichever is set decides which\r\n * marker renders; see ListItemBlock) — passing both is not a supported\r\n * combination — matches the common \"one marker style per item\" convention.\r\n * `initialRuns`, when given (Enter-to-split), seeds the title with the runs\r\n * that landed after the caret instead of a single blank run.\r\n *\r\n * A toggle is seeded with one empty paragraph child right away (same\r\n * convention as callout/toggleHeading) — without this, a toggle created\r\n * with no children at all has nothing to expand: its own disclosure\r\n * marker has nothing to reveal, and there was no other way to get content\r\n * into it (this was a real dead end for exactly this reason before the\r\n * seeding was added).\r\n */\r\nexport function createListItemBlock({ ordered = false, checked, collapsed } = {}) {\r\n return function factory(parentId, initialRuns) {\r\n const blockId = genId();\r\n const runs = initialRuns?.length ? initialRuns : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n const props = { ordered, titleRunIds: runs.map((r) => r.id) };\r\n if (checked !== undefined) props.checked = checked;\r\n\r\n let contentIds = [];\r\n let subtreeBlocks = [];\r\n let allRuns = runs;\r\n if (collapsed !== undefined) {\r\n props.collapsed = collapsed;\r\n const { block: childBlock, runs: childRuns } = createTextLeafBlock('paragraph')(blockId);\r\n contentIds = [childBlock.id];\r\n subtreeBlocks = [childBlock];\r\n allRuns = [...runs, ...childRuns];\r\n }\r\n\r\n return {\r\n block: { id: blockId, type: 'listItem', parentId, contentIds, props },\r\n runs: allRuns,\r\n subtreeBlocks,\r\n };\r\n };\r\n}\r\n","import { moveBlock } from '../../store/operations.js';\r\nimport { focusAdjacentBlock, focusBlockStart } from '../shared/navigationCommands.js';\r\n\r\n/**\r\n * Tab: makes this list item a child (nested one level deeper) of its\r\n * previous sibling — but only when that previous sibling is itself a\r\n * listItem. Nesting under a non-container block (a paragraph, heading,\r\n * etc.) would silently make this item invisible: only container block\r\n * types render `<BlockChildren>` for their contentIds, so a listItem\r\n * reparented under, say, a paragraph would still exist in the store but\r\n * never be rendered anywhere — this is what \"the whole list disappeared\"\r\n * turned out to be. When there's no previous sibling to nest under (this\r\n * is the first item, or no valid listItem precedes it), Tab moves focus to\r\n * the next block instead of doing nothing silently.\r\n *\r\n * moveBlock reparents the item — a different contentIds array now owns it,\r\n * so React remounts its subtree under the new parent and any DOM focus it\r\n * had is destroyed. Must explicitly refocus afterward, same as every other\r\n * reparenting path (outdent-on-Backspace, outdent-on-Enter) already does.\r\n */\r\nexport function indentListItem(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n const parent = store.getBlock(block.parentId);\r\n const index = parent.contentIds.indexOf(blockId);\r\n const prevId = index > 0 ? parent.contentIds[index - 1] : null;\r\n const prev = prevId ? store.getBlock(prevId) : null;\r\n\r\n if (!prev || prev.type !== 'listItem') {\r\n focusAdjacentBlock(store, blockId, 'down');\r\n return;\r\n }\r\n\r\n store.applyOperation(moveBlock(blockId, prevId, prev.contentIds.length));\r\n focusBlockStart(store, blockId);\r\n}\r\n\r\n/**\r\n * Shift+Tab: promotes this list item to be a sibling of its current parent\r\n * list item, placed right after it. No-op if the parent isn't itself a\r\n * list item (i.e. this item is already at the top level). Also reparents\r\n * (see indentListItem's note above) — refocuses afterward for the same\r\n * reason.\r\n */\r\nexport function outdentListItem(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n const currentParent = store.getBlock(block.parentId);\r\n if (!currentParent || currentParent.type !== 'listItem') return;\r\n const grandParentId = currentParent.parentId;\r\n const grandParent = store.getBlock(grandParentId);\r\n const parentIndex = grandParent.contentIds.indexOf(currentParent.id);\r\n store.applyOperation(moveBlock(blockId, grandParentId, parentIndex + 1));\r\n focusBlockStart(store, blockId);\r\n}\r\n","import { removeBlock, updateBlockProps, insertBlock } from '../../store/operations.js';\r\nimport { outdentListItem } from './indentCommands.js';\r\nimport { isContentlessBlock } from '../shared/contentless.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\nexport function isBlankTitle(store, titleRunIds) {\r\n return titleRunIds.length === 0 || (titleRunIds.length === 1 && (store.getRun(titleRunIds[0])?.value ?? '') === '');\r\n}\r\n\r\n/**\r\n * True when a list item's own nested content is empty — either no children\r\n * at all, or just its single seeded blank paragraph, still untouched. A\r\n * toggle item (collapsed !== undefined) is *always* seeded with one blank\r\n * paragraph child by createListItemBlock, so checking for literally zero\r\n * children (as the rest of this file used to) can never be true for a\r\n * toggle in practice — making an entirely empty toggle permanently\r\n * undeletable via Backspace. This treats \"just the untouched seeded\r\n * paragraph\" the same as \"no children\", matching the same fix already\r\n * applied to toggle heading (see toggleHeading/mergeCommands.js's\r\n * isBodyEmpty).\r\n */\r\nfunction isBodyEmpty(store, block) {\r\n const childIds = block.contentIds ?? [];\r\n if (childIds.length === 0) return true;\r\n if (childIds.length > 1) return false;\r\n const onlyChild = store.getBlock(childIds[0]);\r\n return Boolean(onlyChild) && onlyChild.type === 'paragraph' && isRunsEmpty(store, onlyChild.contentIds);\r\n}\r\n\r\n/**\r\n * Backspace-at-start-of-title behavior for a list item, distinct from\r\n * mergeWithPreviousOrDelete (paragraph/heading) because a list item's own\r\n * text lives in props.titleRunIds, not contentIds (contentIds holds nested\r\n * child items instead).\r\n *\r\n * - Previous sibling at this level is contentless (e.g. a divider): delete\r\n * *it* first and stay put, same convention as mergeWithPreviousOrDelete.\r\n * - Previous sibling at this level + this item is empty: just delete it.\r\n * - Previous sibling at this level + this item has text, no nested\r\n * children of its own: merge its title onto the previous sibling's title\r\n * (only when the previous sibling is also a listItem) and delete the\r\n * shell. If it has nested children, merging is skipped (v1 scope — see\r\n * navigationCommands' similar container-boundary caveat).\r\n * - No previous sibling, but nested under another list item: outdent\r\n * instead (matches common list-editor Backspace behavior).\r\n * - No previous sibling and already top-level: no-op (nothing sensible to\r\n * merge into without cross-container merging, which is out of scope).\r\n *\r\n * Returns `{ focusBlockId, needsRefocus }` or null if nothing happened.\r\n * `needsRefocus` distinguishes two cases that both return the item's own\r\n * id: after an outdent the item is reparented (a different contentIds\r\n * array owns it, so React remounts it and focus is lost — needsRefocus:\r\n * true); after deleting a preceding divider the item never moved (same\r\n * parent, same position, no remount — needsRefocus: false, the browser\r\n * keeps the caret where it already was).\r\n */\r\nexport function mergeListItemOrOutdent(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n if (!block) return null;\r\n const parent = store.getBlock(block.parentId);\r\n const index = parent.contentIds.indexOf(blockId);\r\n const titleRunIds = block.props.titleRunIds ?? [];\r\n const titleEmpty = isBlankTitle(store, titleRunIds);\r\n // Entirely empty means BOTH the title and the nested body are empty (see\r\n // isBodyEmpty) — an empty title with real nested content underneath\r\n // (very common for a toggle, whose whole point is holding content under\r\n // a collapsed/expanded line) must not vanish along with its subtree just\r\n // because its own title happens to be blank right now.\r\n const empty = titleEmpty && isBodyEmpty(store, block);\r\n\r\n if (index > 0) {\r\n const prevId = parent.contentIds[index - 1];\r\n const prev = store.getBlock(prevId);\r\n\r\n // An empty CURRENT item goes first, even next to a non-editable\r\n // previous sibling (divider) — see the matching comment in\r\n // shared/mergeCommands.js for why this ordering matters.\r\n if (empty) {\r\n applyOps(store, [removeBlock(blockId)]);\r\n return { focusBlockId: prevId, needsRefocus: true };\r\n }\r\n\r\n if (isContentlessBlock(store, prev)) {\r\n applyOps(store, [removeBlock(prevId)]);\r\n return { focusBlockId: blockId, needsRefocus: false };\r\n }\r\n\r\n if (prev?.type === 'listItem' && block.contentIds.length === 0) {\r\n const mergedTitleRunIds = [...(prev.props.titleRunIds ?? []), ...titleRunIds];\r\n applyOps(store, [\r\n updateBlockProps(prevId, { titleRunIds: mergedTitleRunIds }),\r\n updateBlockProps(blockId, { titleRunIds: [] }), // detach before delete\r\n removeBlock(blockId),\r\n ]);\r\n return { focusBlockId: prevId, needsRefocus: true };\r\n }\r\n\r\n return null; // has nested children or previous sibling isn't a listItem: v1 skips this merge\r\n }\r\n\r\n if (parent.type === 'listItem') {\r\n outdentListItem(store, blockId);\r\n return { focusBlockId: blockId, needsRefocus: true }; // reparented: remounted, needs explicit refocus\r\n }\r\n\r\n // Top-level first item with nothing before it: real content stays put,\r\n // matching every other editor's \"Backspace at the absolute start is a\r\n // no-op when there's something to preserve\". But an entirely empty item\r\n // should still be removable — same \"never a permanent dead end\" fallback\r\n // as mergeToggleHeadingOrNoop/mergeWithPreviousOrDelete: without this, a\r\n // toggle (always seeded with one blank child) could never satisfy the old\r\n // \"contentIds.length === 0\" check, making it permanently undeletable\r\n // whenever it happens to be first/only in its container.\r\n if (!empty) return null;\r\n\r\n if (parent.contentIds.length > 1) {\r\n applyOps(store, [removeBlock(blockId)]);\r\n return { focusBlockId: store.getBlock(parent.id).contentIds[0], needsRefocus: true };\r\n }\r\n\r\n const { block: fallbackBlock, runs } = createTextLeafBlock('paragraph')(parent.id);\r\n applyOps(store, [\r\n insertBlock(fallbackBlock, parent.id, index, { blocks: [fallbackBlock], runs }),\r\n removeBlock(blockId),\r\n ]);\r\n return { focusBlockId: fallbackBlock.id, needsRefocus: true };\r\n}\r\n","import { insertBlock, removeBlock, updateBlockProps } from '../../store/operations.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { focusBlockStart } from '../shared/navigationCommands.js';\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n/**\r\n * Enter on an empty, top-level (not nested under another list item),\r\n * childless list item exits the list entirely: it's replaced in place by\r\n * an empty paragraph, and focus moves there. Matches every other list\r\n * editor's \"Enter on the last empty bullet leaves the list\" convention —\r\n * the nested case (mergeCommands.js's outdent-on-empty) only pops one\r\n * level; this is the top-level equivalent that leaves the list altogether.\r\n */\r\nexport function exitListItemToParagraph(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n const parentId = block.parentId;\r\n const parent = store.getBlock(parentId);\r\n const index = parent.contentIds.indexOf(blockId);\r\n const { block: paragraphBlock, runs } = createTextLeafBlock('paragraph')(parentId);\r\n\r\n applyOps(store, [\r\n insertBlock(paragraphBlock, parentId, index, { blocks: [paragraphBlock], runs }),\r\n updateBlockProps(blockId, { titleRunIds: [] }), // detach its own (empty) run before deleting\r\n removeBlock(blockId),\r\n ]);\r\n\r\n focusBlockStart(store, paragraphBlock.id);\r\n return paragraphBlock.id;\r\n}\r\n","import { useCallback } from 'react';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useBlockChildren } from '../../react/useBlockChildren.js';\r\nimport { EditableBlockContent } from '../../react/EditableBlockContent.jsx';\r\nimport { BlockChildren } from '../../react/BlockChildren.jsx';\r\nimport { useEditorStore, useSelectedBlock, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { listItemDepth, orderedItemIndex, orderedMarkerText, bulletMarkerText } from './listMarkers.js';\r\nimport { ChevronRightIcon, ChevronDownIcon } from '../../react/icons.jsx';\r\nimport { insertSiblingSplitAtCaretAndFocus, insertFirstChildSplitAtCaretAndFocus } from '../shared/blockCommands.js';\r\nimport { createListItemBlock } from './createListItemBlock.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { indentListItem, outdentListItem } from './indentCommands.js';\r\nimport { mergeListItemOrOutdent, isBlankTitle } from './mergeCommands.js';\r\nimport { exitListItemToParagraph } from './exitListItem.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { focusAfterMerge } from '../shared/focusAfterMerge.js';\r\nimport { updateBlockProps, insertBlock } from '../../store/operations.js';\r\nimport { focusAdjacentBlock } from '../shared/navigationCommands.js';\r\nimport { resolveBlockDir } from '../shared/resolveBlockDir.js';\r\nimport { focusRunEnd } from '../../react/focusRun.js';\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n/**\r\n * Indentation/nesting is modeled the same way as every other container\r\n * block (parentId + contentIds referencing child block ids) — a list item's\r\n * own text lives in props.titleRunIds (run ids) rather than contentIds,\r\n * since a list item needs both an inline title *and* nested child blocks at\r\n * once, unlike a pure leaf (paragraph/heading) or pure container (page).\r\n *\r\n * When `props.checked` is not undefined, this doubles as a to-do item: the\r\n * marker becomes a checkbox instead of a bullet/number.\r\n */\r\nexport function ListItemBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n const { setSelectedBlockId } = useSelectedBlock();\r\n // Subscribed purely so this item re-renders when a SIBLING is inserted,\r\n // removed, or reordered at this level — needed to keep its own marker\r\n // (numbered position, or depth-based bullet/number style) correct, since\r\n // BlockRenderer's memo would otherwise skip re-rendering this item on a\r\n // sibling-only structural change (its own block data didn't change).\r\n // Cheap and scoped to exactly this list level, unlike the parent\r\n // (BlockChildren) re-rendering, which is unaffected either way.\r\n const siblingIds = useBlockChildren(block?.parentId);\r\n\r\n const handleEnter = useCallback(() => {\r\n // Enter on an empty item that's nested under another list item pops it\r\n // out one level instead of creating yet another empty nested item —\r\n // this is how the caret \"comes out\" of a list, matching every other\r\n // list editor's convention.\r\n const titleRunIds = block?.props?.titleRunIds ?? [];\r\n const parent = store.getBlock(block?.parentId);\r\n const empty = isBlankTitle(store, titleRunIds);\r\n\r\n if (empty && parent?.type === 'listItem') {\r\n outdentListItem(store, id); // refocuses itself (reparenting remounts the DOM)\r\n return;\r\n }\r\n\r\n // Enter on an empty, top-level, childless item exits the list\r\n // altogether (becomes a paragraph) — matches the same convention every\r\n // other list editor uses for \"Enter on the last empty bullet\".\r\n const hasNestedChildren = (block?.contentIds?.length ?? 0) > 0;\r\n if (empty && parent?.type !== 'listItem' && !hasNestedChildren) {\r\n exitListItemToParagraph(store, id);\r\n return;\r\n }\r\n\r\n const isTodo = block?.props?.checked !== undefined;\r\n const isToggle = block?.props?.collapsed !== undefined;\r\n const factory = createListItemBlock({\r\n ordered: block?.props?.ordered,\r\n checked: isTodo ? false : undefined,\r\n collapsed: isToggle ? false : undefined,\r\n });\r\n\r\n // If this item already has nested children, the new item belongs at\r\n // the SAME indent level as those children, positioned before them —\r\n // not as this item's own sibling, which would render below the entire\r\n // nested list instead of right after the line the caret is on. This\r\n // does NOT apply to a toggle: its contentIds are the collapsible body,\r\n // not \"the next line of a continued list\" — Enter on a toggle's own\r\n // title always creates a new sibling toggle at the same level,\r\n // (Tab is the only way to nest something under it).\r\n if (hasNestedChildren && !isToggle) {\r\n insertFirstChildSplitAtCaretAndFocus(store, id, titleRunIds, factory);\r\n } else {\r\n insertSiblingSplitAtCaretAndFocus(store, id, titleRunIds, factory);\r\n }\r\n }, [store, id, block]);\r\n\r\n const handleTab = useCallback(() => indentListItem(store, id), [store, id]);\r\n const handleShiftTab = useCallback(() => outdentListItem(store, id), [store, id]);\r\n\r\n const handleBackspaceAtStart = useCallback(() => {\r\n const result = mergeListItemOrOutdent(store, id);\r\n if (!result || !result.needsRefocus) return; // no-op, or stayed in place with no remount\r\n focusAfterMerge(store, result.focusBlockId, id, setSelectedBlockId);\r\n }, [store, id, setSelectedBlockId]);\r\n\r\n const handleArrowUp = useCallback(() => focusAdjacentBlock(store, id, 'up'), [store, id]);\r\n const handleArrowDown = useCallback(() => focusAdjacentBlock(store, id, 'down'), [store, id]);\r\n\r\n const toggleChecked = useCallback(() => {\r\n store.applyOperation(updateBlockProps(id, { checked: !block?.props?.checked }));\r\n }, [store, id, block?.props?.checked]);\r\n\r\n const toggleCollapsed = useCallback(() => {\r\n const hasChildren = (block?.contentIds?.length ?? 0) > 0;\r\n if (!hasChildren) {\r\n // A childless toggle has nothing to expand/collapse yet — this was\r\n // previously a disabled dead end (no way to ever get content into a\r\n // toggle that didn't happen to be seeded with a child already, e.g.\r\n // one created before the seeding in createListItemBlock existed, or\r\n // one whose only child was removed by some other action). Clicking\r\n // now bootstraps the first (empty) child and expands, the same\r\n // seeded shape callout/toggleHeading start with.\r\n const { block: childBlock, runs } = createTextLeafBlock('paragraph')(id);\r\n applyOps(store, [\r\n insertBlock(childBlock, id, 0, { blocks: [childBlock], runs }),\r\n updateBlockProps(id, { collapsed: false }),\r\n ]);\r\n focusRunEnd(childBlock.contentIds[0]);\r\n return;\r\n }\r\n store.applyOperation(updateBlockProps(id, { collapsed: !block?.props?.collapsed }));\r\n }, [store, id, block?.contentIds, block?.props?.collapsed]);\r\n\r\n const className = useBlockClassName('be-list-item', block);\r\n\r\n if (!block) return null;\r\n const { ordered, checked, collapsed, titleRunIds = [] } = block.props;\r\n const isTodo = checked !== undefined;\r\n const isToggle = !isTodo && collapsed !== undefined;\r\n const hasNestedChildren = block.contentIds.length > 0;\r\n // Best-effort accessible name for the checkbox: a native checkbox with no\r\n // name reads to a screen reader as just \"checkbox, checked/not checked\",\r\n // with no indication of *which* to-do it's for. Atomic (non-text) runs\r\n // contribute nothing here — this is a plain-text summary, not a full\r\n // serialization.\r\n const titleText = titleRunIds\r\n .map((runId) => store.getRun(runId))\r\n .filter((run) => run?.type === 'text')\r\n .map((run) => run.value)\r\n .join('')\r\n .trim();\r\n const dir = resolveBlockDir(store, block);\r\n\r\n return (\r\n <div className={className} data-block-id={id} dir={dir}>\r\n <div className=\"be-list-item-row\">\r\n {isTodo ? (\r\n <input\r\n type=\"checkbox\"\r\n className=\"be-list-checkbox\"\r\n checked={Boolean(checked)}\r\n onChange={toggleChecked}\r\n aria-label={titleText || 'To-do item'}\r\n />\r\n ) : isToggle ? (\r\n // A real button (not decorative, unlike the plain bullet/number\r\n // marker below): it's the only way to reveal/hide this item's\r\n // children, so assistive tech needs to know it's interactive and\r\n // what state it's in.\r\n <button\r\n type=\"button\"\r\n className=\"be-list-toggle-marker\"\r\n onClick={toggleCollapsed}\r\n aria-expanded={!collapsed}\r\n aria-label={!hasNestedChildren ? 'Add content to toggle' : collapsed ? 'Expand toggle' : 'Collapse toggle'}\r\n >\r\n {collapsed ? <ChevronRightIcon /> : <ChevronDownIcon />}\r\n </button>\r\n ) : (\r\n // Decorative: list structure/position is conveyed by the DOM\r\n // order itself, not by this glyph, so it's hidden from assistive\r\n // tech. The glyph itself cycles with nesting depth (1,2,3 ->\r\n // a,b,c -> i,ii,iii for numbered; disc -> circle -> square for\r\n // bulleted, repeating every 3 levels), a common list-nesting\r\n // convention — see listMarkers.js.\r\n <span className=\"be-list-marker\" aria-hidden=\"true\">\r\n {ordered\r\n ? orderedMarkerText(listItemDepth(store, block), orderedItemIndex(store, block, siblingIds))\r\n : bulletMarkerText(listItemDepth(store, block))}\r\n </span>\r\n )}\r\n <div\r\n className=\"be-list-item-title\"\r\n data-empty={isRunsEmpty(store, titleRunIds) ? '' : undefined}\r\n data-placeholder={isTodo ? 'To-do' : isToggle ? 'Toggle' : 'List item'}\r\n style={checked ? { textDecoration: 'line-through', opacity: 0.6 } : undefined}\r\n >\r\n <EditableBlockContent\r\n blockId={id}\r\n runIds={titleRunIds}\r\n dir={dir}\r\n onEnter={handleEnter}\r\n onTab={handleTab}\r\n onShiftTab={handleShiftTab}\r\n onBackspaceAtStart={handleBackspaceAtStart}\r\n onArrowUp={handleArrowUp}\r\n onArrowDown={handleArrowDown}\r\n />\r\n </div>\r\n </div>\r\n {/*\r\n A toggle's children stay in the store (contentIds unchanged) while\r\n collapsed — only the DOM for them is skipped. Copy/cut/paste,\r\n select-all, and serialization all walk contentIds directly and have\r\n no notion of \"collapsed\" at all, so a collapsed toggle's hidden\r\n content still copies/serializes/undoes correctly for free; this is\r\n the only place collapsed state has any effect.\r\n */}\r\n {(!isToggle || !collapsed) && (\r\n <div className=\"be-list-item-children\">\r\n <BlockChildren parentId={id} />\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { ListItemBlock } from './ListItemBlock.jsx';\r\nimport { runToHTML, runToPlainText } from '../../inline/marks.js';\r\nimport { domInlineToRuns } from '../../inline/runOps.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createListItemBlock } from './createListItemBlock.js';\r\nimport { BulletedListIcon, NumberedListIcon, CheckboxIcon, ChevronRightIcon } from '../../react/icons.jsx';\r\n\r\n/**\r\n * Emits just `<li>...</li>` (with nested `<ul>/<ol>` for indented children).\r\n * Grouping consecutive sibling list items into one wrapping `<ul>/<ol>` is\r\n * the container serializer's job (see clipboard/serialize.js), not this\r\n * block type's — a single item doesn't know about its siblings.\r\n */\r\nfunction toHTML(block, ctx) {\r\n const { titleRunIds = [], ordered } = block.props;\r\n const titleHTML = titleRunIds.map((runId) => runToHTML(ctx.store.getRun(runId), ctx)).join('');\r\n const childrenHTML = block.contentIds\r\n .map((childId) => ctx.registry.get(ctx.store.getBlock(childId).type).toHTML(ctx.store.getBlock(childId), ctx))\r\n .join('');\r\n const nested = childrenHTML ? `<${ordered ? 'ol' : 'ul'}>${childrenHTML}</${ordered ? 'ol' : 'ul'}>` : '';\r\n return `<li>${titleHTML}${nested}</li>`;\r\n}\r\n\r\nfunction toPlainText(block, ctx) {\r\n const { titleRunIds = [] } = block.props;\r\n return titleRunIds.map((runId) => runToPlainText(ctx.store.getRun(runId), ctx)).join('');\r\n}\r\n\r\n/** Builds one list item block (+ its nested list items) from a single <li>. */\r\nfunction fromLiNode(liNode, ctx) {\r\n const inlineNodes = [];\r\n const nestedListNodes = [];\r\n for (const child of liNode.childNodes) {\r\n if (child.nodeType === 1 && (child.tagName === 'UL' || child.tagName === 'OL')) {\r\n nestedListNodes.push(child);\r\n } else {\r\n inlineNodes.push(child);\r\n }\r\n }\r\n\r\n const wrapper = liNode.ownerDocument.createElement('span');\r\n for (const n of inlineNodes) wrapper.appendChild(n.cloneNode(true));\r\n const titleRuns = domInlineToRuns(wrapper, ctx);\r\n\r\n const blockId = genId();\r\n const childRuns = [...titleRuns];\r\n const childBlocks = [];\r\n const contentIds = [];\r\n\r\n for (const listNode of nestedListNodes) {\r\n const ordered = listNode.tagName === 'OL';\r\n for (const li of listNode.children) {\r\n if (li.tagName !== 'LI') continue;\r\n const nested = fromLiNode(li, ctx);\r\n nested.block.parentId = blockId;\r\n nested.block.props.ordered = ordered;\r\n childBlocks.push(nested.block, ...nested.childBlocks);\r\n childRuns.push(...nested.runs);\r\n contentIds.push(nested.block.id);\r\n }\r\n }\r\n\r\n const block = {\r\n id: blockId,\r\n type: 'listItem',\r\n parentId: null,\r\n contentIds,\r\n props: { ordered: false, titleRunIds: titleRuns.map((r) => r.id) },\r\n };\r\n\r\n return { block, runs: childRuns, childBlocks };\r\n}\r\n\r\nfunction fromHTML(node, ctx) {\r\n if (node.tagName !== 'LI') return null;\r\n const { block, runs, childBlocks } = fromLiNode(node, ctx);\r\n return { block, runs, subtreeBlocks: childBlocks };\r\n}\r\n\r\nexport const listItemBlockType = {\r\n component: ListItemBlock,\r\n isLeaf: false,\r\n defaultProps: { ordered: false, titleRunIds: [] },\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommands: [\r\n {\r\n label: 'Bulleted list',\r\n icon: BulletedListIcon,\r\n keywords: ['list', 'bullet', 'ul'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createListItemBlock({ ordered: false })),\r\n },\r\n {\r\n label: 'Numbered list',\r\n icon: NumberedListIcon,\r\n keywords: ['list', 'number', 'ordered', 'ol'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createListItemBlock({ ordered: true })),\r\n },\r\n {\r\n label: 'To-do list',\r\n icon: CheckboxIcon,\r\n keywords: ['todo', 'checkbox', 'task', 'checklist'],\r\n run: (store, ctx) =>\r\n trimSlashQueryAndInsertAfter(store, ctx, createListItemBlock({ ordered: false, checked: false })),\r\n },\r\n {\r\n label: 'Toggle list',\r\n icon: ChevronRightIcon,\r\n keywords: ['toggle', 'collapse', 'expand', 'dropdown', 'accordion'],\r\n run: (store, ctx) =>\r\n trimSlashQueryAndInsertAfter(store, ctx, createListItemBlock({ ordered: false, collapsed: false })),\r\n },\r\n ],\r\n};\r\n","import { genId } from '../../utils/idGen.js';\r\n\r\nexport const COLUMN_TYPES = ['text', 'date', 'checkbox', 'select'];\r\nexport const DEFAULT_COLUMN_TYPE = 'text';\r\nexport const DEFAULT_COLUMN_WIDTH = 160;\r\nexport const MIN_COLUMN_WIDTH = 80;\r\n\r\nexport function defaultColumnLabel(index) {\r\n return `Column ${index + 1}`;\r\n}\r\n\r\nexport function createDefaultColumns(count) {\r\n return Array.from({ length: count }, (_, i) => ({\r\n id: genId(),\r\n label: defaultColumnLabel(i),\r\n type: DEFAULT_COLUMN_TYPE,\r\n width: DEFAULT_COLUMN_WIDTH,\r\n }));\r\n}\r\n\r\n/**\r\n * Returns a table's column metadata (`{ id, label, type, width }` per\r\n * column), falling back to generated (all-text, default-width) defaults\r\n * when it's missing or the wrong length — a table pasted in from external\r\n * HTML, loaded from a document saved before this feature existed, or\r\n * hand-built by a host app never had a chance to set `props.columns` at\r\n * all, and it's cheap insurance against a stale array (e.g. a column\r\n * added/removed through a code path that didn't know to keep it in sync)\r\n * ever crashing the header row instead of just re-deriving something\r\n * sensible. Also fills in `type: 'text'`/`width: DEFAULT_COLUMN_WIDTH` for\r\n * any column entry that predates those fields.\r\n */\r\nexport function resolveColumns(table, colCount) {\r\n const columns = table.props?.columns;\r\n if (!Array.isArray(columns) || columns.length !== colCount) return createDefaultColumns(colCount);\r\n return columns.map((c) => {\r\n const type = c.type ?? DEFAULT_COLUMN_TYPE;\r\n const width = c.width ?? DEFAULT_COLUMN_WIDTH;\r\n return type === c.type && width === c.width ? c : { ...c, type, width };\r\n });\r\n}\r\n\r\n/**\r\n * A blank run of the given column type — the shape reused table-wide,\r\n * whether creating a fresh cell or converting an existing one. A \"select\"\r\n * column's runs are `tableSelect` runs with no options of their own — the\r\n * shared, column-level `options` array (see resolveColumns) is the single\r\n * source of truth every cell's dropdown reads from, so a brand new blank\r\n * cell in an already-typed select column immediately gets the same\r\n * choices as every other cell in that column, with nothing to seed here.\r\n */\r\nexport function blankRunForType(type) {\r\n switch (type) {\r\n case 'date':\r\n return { id: genId(), type: 'date', value: '', marks: {}, data: { isoDate: '' } };\r\n case 'checkbox':\r\n return { id: genId(), type: 'checkbox', value: '', marks: {}, data: { checked: false, label: '' } };\r\n case 'select':\r\n return { id: genId(), type: 'tableSelect', value: '', marks: {}, data: { selectedValue: '', selectedLabel: '' } };\r\n default:\r\n return { id: genId(), type: 'text', value: '', marks: {} };\r\n }\r\n}\r\n\r\n/** A fresh empty cell block + its one run, matching `column`'s type — the single \"create a table cell\" primitive every row/column insert path shares. */\r\nexport function createCellForColumn(parentId, column) {\r\n const run = blankRunForType(column?.type);\r\n return { block: { id: genId(), type: 'tableCell', parentId, contentIds: [run.id], props: {} }, run };\r\n}\r\n\r\n/**\r\n * Converts one existing run to `newType`, attempting to preserve its data\r\n * rather than silently discarding it (the bug this whole feature set was\r\n * partly motivated by fixing, compared to the legacy notevo table's\r\n * \"change type wipes the cell\" behavior). Converting *from* a non-text\r\n * atomic type reads its plain-text value via the old type's own\r\n * `toPlainText` (through the inline registry) rather than needing a\r\n * hand-written conversion for every type pair — e.g. a date becomes its\r\n * formatted string, which then seeds the new checkbox's label, etc.\r\n * `inlineRegistry` may be omitted only when `run.type` is already `'text'`\r\n * (no lookup needed for that case).\r\n *\r\n * Does NOT handle `newType === 'select'` — converting a whole column *to*\r\n * select needs to look at every cell together (to build one shared,\r\n * deduplicated option list), which a single-run function can't do; see\r\n * setColumnType's own dedicated handling for that case instead.\r\n */\r\nexport function convertRunToType(run, newType, inlineRegistry) {\r\n if (run.type === newType) return run;\r\n\r\n let text;\r\n if (run.type === 'text') {\r\n text = run.value ?? '';\r\n } else {\r\n const entry = inlineRegistry?.get(run.type);\r\n text = entry?.toPlainText ? entry.toPlainText(run) : '';\r\n }\r\n\r\n if (newType === 'date') {\r\n const parsed = text ? new Date(text) : null;\r\n const isoDate = parsed && !Number.isNaN(parsed.getTime()) ? parsed.toISOString().slice(0, 10) : '';\r\n return { id: genId(), type: 'date', value: '', marks: {}, data: { isoDate } };\r\n }\r\n if (newType === 'checkbox') {\r\n return { id: genId(), type: 'checkbox', value: '', marks: {}, data: { checked: false, label: text } };\r\n }\r\n return { id: genId(), type: 'text', value: text, marks: {} };\r\n}\r\n","import { removeBlock, insertBlock, updateBlockProps, setBlockRuns, updateRun } from '../../store/operations.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { focusBlockStart } from '../shared/navigationCommands.js';\r\nimport { ensureRootNonEmpty } from '../shared/ensureRootNonEmpty.js';\r\nimport { resolveColumns, createCellForColumn, convertRunToType, DEFAULT_COLUMN_TYPE, DEFAULT_COLUMN_WIDTH, MIN_COLUMN_WIDTH } from './tableColumns.js';\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n/** Removes the whole table (used when deleting its last row/column) and focuses whatever's now at its old position. */\r\nfunction removeTableAndFocusSibling(store, table) {\r\n const parent = store.getBlock(table.parentId);\r\n const tableIndex = parent.contentIds.indexOf(table.id);\r\n applyOps(store, [removeBlock(table.id)]);\r\n\r\n // The table may have been the only block in the whole document — never\r\n // leave the document with zero blocks (see ensureRootNonEmpty).\r\n const fallbackParagraphId = ensureRootNonEmpty(store);\r\n if (fallbackParagraphId) {\r\n focusBlockStart(store, fallbackParagraphId);\r\n return null;\r\n }\r\n\r\n const parentAfter = store.getBlock(table.parentId);\r\n const siblingId = parentAfter.contentIds[tableIndex] ?? parentAfter.contentIds[tableIndex - 1];\r\n if (siblingId) focusBlockStart(store, siblingId);\r\n return null;\r\n}\r\n\r\n/**\r\n * Inserts a new empty row right after `rowId`, with the same column count,\r\n * and focuses its first cell. Each new cell matches its own column's\r\n * configured type (see tableColumns.js) — a date/select/checkbox column\r\n * keeps getting date/select/checkbox cells for every row added after it\r\n * was typed, not a plain blank text cell.\r\n */\r\nexport function insertRowAfter(store, rowId) {\r\n const row = store.getBlock(rowId);\r\n const table = store.getBlock(row.parentId);\r\n const rowIndex = table.contentIds.indexOf(rowId);\r\n const columns = resolveColumns(table, row.contentIds.length);\r\n\r\n const newRowId = genId();\r\n const cellBlocks = [];\r\n const runs = [];\r\n const contentIds = [];\r\n for (const column of columns) {\r\n const cell = createCellForColumn(newRowId, column);\r\n cellBlocks.push(cell.block);\r\n runs.push(cell.run);\r\n contentIds.push(cell.block.id);\r\n }\r\n const newRow = { id: newRowId, type: 'tableRow', parentId: table.id, contentIds, props: {} };\r\n\r\n store.applyOperation(insertBlock(newRow, table.id, rowIndex + 1, { blocks: [newRow, ...cellBlocks], runs }));\r\n focusBlockStart(store, newRowId);\r\n return newRowId;\r\n}\r\n\r\n/**\r\n * Removes a row. If it's the table's only row, removes the whole table\r\n * instead (nothing left to show otherwise) and focuses the block now at\r\n * the table's old position. Otherwise focuses the row that ends up in the\r\n * same slot (the next row, or the new-last row if the deleted one was last).\r\n */\r\nexport function deleteRow(store, rowId) {\r\n const row = store.getBlock(rowId);\r\n const table = store.getBlock(row.parentId);\r\n\r\n if (table.contentIds.length <= 1) {\r\n return removeTableAndFocusSibling(store, table);\r\n }\r\n\r\n const rowIndex = table.contentIds.indexOf(rowId);\r\n applyOps(store, [removeBlock(rowId)]);\r\n\r\n const updatedTable = store.getBlock(table.id);\r\n const targetRowIndex = Math.min(rowIndex, updatedTable.contentIds.length - 1);\r\n const targetRowId = updatedTable.contentIds[targetRowIndex];\r\n if (targetRowId) focusBlockStart(store, targetRowId);\r\n return targetRowId ?? null;\r\n}\r\n\r\n/** Inserts a new (always plain-text) column at `colIndex + 1` in every row of the table, and focuses the first new cell. One atomic undo step, including the new column's metadata. */\r\nexport function insertColumnAfter(store, tableId, colIndex) {\r\n const table = store.getBlock(tableId);\r\n const currentColumns = resolveColumns(table, table.contentIds[0] ? store.getBlock(table.contentIds[0]).contentIds.length : 0);\r\n const newColumn = { id: genId(), label: 'New Column', type: DEFAULT_COLUMN_TYPE, width: DEFAULT_COLUMN_WIDTH };\r\n const ops = [];\r\n let firstNewCellId = null;\r\n\r\n for (const rowId of table.contentIds) {\r\n const cell = createCellForColumn(rowId, newColumn);\r\n if (firstNewCellId === null) firstNewCellId = cell.block.id;\r\n ops.push(insertBlock(cell.block, rowId, colIndex + 1, { blocks: [cell.block], runs: [cell.run] }));\r\n }\r\n\r\n const nextColumns = [...currentColumns];\r\n nextColumns.splice(colIndex + 1, 0, newColumn);\r\n ops.push(updateBlockProps(tableId, { columns: nextColumns }));\r\n\r\n applyOps(store, ops);\r\n if (firstNewCellId) focusBlockStart(store, firstNewCellId);\r\n return firstNewCellId;\r\n}\r\n\r\n/**\r\n * Removes the cell at `colIndex` from every row. If it's the table's only\r\n * column, removes the whole table instead (same convention as deleteRow).\r\n * Otherwise focuses the cell now in the same column slot of the first row.\r\n * One atomic undo step, including the removed column's metadata.\r\n */\r\nexport function deleteColumn(store, tableId, colIndex) {\r\n const table = store.getBlock(tableId);\r\n const firstRow = store.getBlock(table.contentIds[0]);\r\n\r\n if (!firstRow || firstRow.contentIds.length <= 1) {\r\n return removeTableAndFocusSibling(store, table);\r\n }\r\n\r\n const currentColumns = resolveColumns(table, firstRow.contentIds.length);\r\n const ops = table.contentIds.map((rowId) => {\r\n const row = store.getBlock(rowId);\r\n return removeBlock(row.contentIds[colIndex]);\r\n });\r\n const nextColumns = currentColumns.filter((_, i) => i !== colIndex);\r\n ops.push(updateBlockProps(tableId, { columns: nextColumns }));\r\n applyOps(store, ops);\r\n\r\n const updatedFirstRow = store.getBlock(table.contentIds[0]);\r\n const targetColIndex = Math.min(colIndex, updatedFirstRow.contentIds.length - 1);\r\n const targetCellId = updatedFirstRow.contentIds[targetColIndex];\r\n if (targetCellId) focusBlockStart(store, targetCellId);\r\n return targetCellId ?? null;\r\n}\r\n\r\n/** Sets the column at `colIndex`'s pixel width (clamped to MIN_COLUMN_WIDTH) — one atomic undo step. */\r\nexport function setColumnWidth(store, tableId, colIndex, width) {\r\n const table = store.getBlock(tableId);\r\n const firstRow = store.getBlock(table.contentIds[0]);\r\n const currentColumns = resolveColumns(table, firstRow ? firstRow.contentIds.length : 0);\r\n if (!currentColumns[colIndex]) return;\r\n const nextColumns = [...currentColumns];\r\n nextColumns[colIndex] = { ...currentColumns[colIndex], width: Math.max(MIN_COLUMN_WIDTH, Math.round(width)) };\r\n store.applyOperation(updateBlockProps(tableId, { columns: nextColumns }));\r\n}\r\n\r\n/** Renames the column at `colIndex` — one atomic undo step. */\r\nexport function renameColumn(store, tableId, colIndex, label) {\r\n const table = store.getBlock(tableId);\r\n const firstRow = store.getBlock(table.contentIds[0]);\r\n const currentColumns = resolveColumns(table, firstRow ? firstRow.contentIds.length : 0);\r\n const nextColumns = [...currentColumns];\r\n if (!nextColumns[colIndex]) return;\r\n nextColumns[colIndex] = { ...nextColumns[colIndex], label };\r\n store.applyOperation(updateBlockProps(tableId, { columns: nextColumns }));\r\n}\r\n\r\nfunction cellRunsForColumn(store, table, colIndex) {\r\n return table.contentIds.map((rowId) => {\r\n const row = store.getBlock(rowId);\r\n const cellId = row.contentIds[colIndex];\r\n const cell = store.getBlock(cellId);\r\n return { cellId, run: store.getRun(cell.contentIds[0]) };\r\n });\r\n}\r\n\r\nfunction runPlainText(run, inlineRegistry) {\r\n if (!run) return '';\r\n if (run.type === 'text') return run.value ?? '';\r\n const entry = inlineRegistry?.get(run.type);\r\n return entry?.toPlainText ? entry.toPlainText(run) : '';\r\n}\r\n\r\n/**\r\n * Changing a column *to* select needs every cell's current value at once\r\n * (to build one shared, deduplicated option list — the common \"text ->\r\n * select\" convention: one tag per distinct existing string, not one per\r\n * cell), which is why it's split out from the generic per-run\r\n * convertRunToType. Each cell is assigned whichever option matches its own\r\n * former text (blank cells stay unselected).\r\n */\r\nfunction buildSelectColumnConversion(store, table, colIndex, inlineRegistry) {\r\n const cellRuns = cellRunsForColumn(store, table, colIndex);\r\n const options = [];\r\n const optionByLabel = new Map();\r\n\r\n for (const { run } of cellRuns) {\r\n const text = runPlainText(run, inlineRegistry).trim();\r\n if (!text || optionByLabel.has(text)) continue;\r\n const option = { value: genId(), label: text };\r\n optionByLabel.set(text, option);\r\n options.push(option);\r\n }\r\n\r\n const newRuns = cellRuns.map(({ cellId, run }) => {\r\n const text = runPlainText(run, inlineRegistry).trim();\r\n const option = optionByLabel.get(text);\r\n return { cellId, run: { id: genId(), type: 'tableSelect', value: '', marks: {}, data: { selectedValue: option?.value ?? '', selectedLabel: option?.label ?? '' } } };\r\n });\r\n\r\n return { options, newRuns };\r\n}\r\n\r\n/**\r\n * Changes the column at `colIndex` to `newType`, converting every existing\r\n * cell's run in that column instead of discarding their data (unlike the\r\n * legacy notevo table this was modeled after, which silently wiped a\r\n * column's values on any type change). `inlineRegistry` is needed to read\r\n * a non-text run's plain-text value when converting *away* from an atomic\r\n * type (date/checkbox/select) — pass the one from `useInlineRegistry()`.\r\n * One atomic undo step for the whole column, metadata and every cell\r\n * together.\r\n */\r\nexport function setColumnType(store, tableId, colIndex, newType, inlineRegistry) {\r\n const table = store.getBlock(tableId);\r\n const firstRow = store.getBlock(table.contentIds[0]);\r\n const currentColumns = resolveColumns(table, firstRow ? firstRow.contentIds.length : 0);\r\n const column = currentColumns[colIndex];\r\n if (!column || column.type === newType) return;\r\n\r\n const nextColumns = [...currentColumns];\r\n\r\n if (newType === 'select') {\r\n const { options, newRuns } = buildSelectColumnConversion(store, table, colIndex, inlineRegistry);\r\n nextColumns[colIndex] = { ...column, type: newType, options };\r\n const ops = [updateBlockProps(tableId, { columns: nextColumns })];\r\n for (const { cellId, run } of newRuns) ops.push(setBlockRuns(cellId, [run]));\r\n applyOps(store, ops);\r\n return;\r\n }\r\n\r\n nextColumns[colIndex] = { ...column, type: newType };\r\n const ops = [updateBlockProps(tableId, { columns: nextColumns })];\r\n for (const { cellId, run: oldRun } of cellRunsForColumn(store, table, colIndex)) {\r\n if (!oldRun) continue;\r\n const newRun = convertRunToType(oldRun, newType, inlineRegistry);\r\n ops.push(setBlockRuns(cellId, [newRun]));\r\n }\r\n applyOps(store, ops);\r\n}\r\n\r\n/**\r\n * Replaces a \"select\" column's shared option list — the header menu's\r\n * add/rename/remove-option UI, acting on the whole column at once (unlike\r\n * the general inline `select` type's per-cell add/remove buttons). Any\r\n * cell whose `selectedValue` no longer matches a surviving option (i.e.\r\n * that option was removed) is cleared back to unselected rather than left\r\n * pointing at a dangling id; a cell whose option was only *renamed* keeps\r\n * its selection and just picks up the new label. One atomic undo step.\r\n */\r\nexport function setColumnOptions(store, tableId, colIndex, options) {\r\n const table = store.getBlock(tableId);\r\n const firstRow = store.getBlock(table.contentIds[0]);\r\n const currentColumns = resolveColumns(table, firstRow ? firstRow.contentIds.length : 0);\r\n const column = currentColumns[colIndex];\r\n if (!column) return;\r\n\r\n const nextColumns = [...currentColumns];\r\n nextColumns[colIndex] = { ...column, options };\r\n const ops = [updateBlockProps(tableId, { columns: nextColumns })];\r\n\r\n const optionById = new Map(options.map((o) => [o.value, o]));\r\n for (const { run } of cellRunsForColumn(store, table, colIndex)) {\r\n if (!run || run.type !== 'tableSelect') continue;\r\n const selectedValue = run.data?.selectedValue ?? '';\r\n const match = optionById.get(selectedValue);\r\n const nextSelectedValue = match ? selectedValue : '';\r\n const nextSelectedLabel = match ? match.label : '';\r\n if (nextSelectedValue !== selectedValue || nextSelectedLabel !== (run.data?.selectedLabel ?? '')) {\r\n ops.push(updateRun(run.id, { data: { selectedValue: nextSelectedValue, selectedLabel: nextSelectedLabel } }));\r\n }\r\n }\r\n\r\n applyOps(store, ops);\r\n}\r\n","import { useLayoutEffect, useState } from 'react';\nimport { clampLeftToViewport } from './popoverPosition.js';\n\n// All three hooks below share the exact two-phase shape\n// useAutoAdjustedPosition.js documents in full (snap to the raw anchor\n// first so nothing jumps, then measure + clamp once real layout exists,\n// both as useLayoutEffects so the whole chain settles before the browser\n// ever paints) — only the *anchor math* differs per popover's own CSS\n// convention, so each is kept as its own tiny hook rather than forcing one\n// generic shape to cover every transform variant.\n\n/**\n * For a popover that's LEFT-anchored (plain `left: <value>`, no transform)\n * but already owns its own vertical placement (Select/SlashMenu both flip\n * between `top`/`bottom` to dodge the on-screen keyboard) — this only ever\n * touches the horizontal axis, leaving the caller's vertical decision alone.\n */\nexport function useHorizontalAutoAdjustedLeft(menuRef, isOpen, rawLeft) {\n const [left, setLeft] = useState(null);\n\n useLayoutEffect(() => {\n setLeft(rawLeft ?? null);\n }, [rawLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || left == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const clamped = clampLeftToViewport(left, rect.width);\n if (clamped !== left) setLeft(clamped);\n }, [isOpen, menuRef, left]);\n\n return left;\n}\n\n/**\n * For a popover CENTERED on an x-coordinate via `left: <centerX>;\n * transform: translateX(-50%)` (FloatingToolbar's own bubble, centered over\n * the text selection it's formatting) — clamps the box's actual left/right\n * edges (accounting for the -50% shift) and returns an adjusted `centerX`\n * for that same `left` + `transform: translateX(-50%)` pairing, so the\n * caller's JSX doesn't need to change anything but the number.\n */\nexport function useAutoAdjustedCenteredLeft(menuRef, isOpen, rawCenterLeft) {\n const [centerLeft, setCenterLeft] = useState(null);\n\n useLayoutEffect(() => {\n setCenterLeft(rawCenterLeft ?? null);\n }, [rawCenterLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || centerLeft == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const half = rect.width / 2;\n const clampedEdge = clampLeftToViewport(centerLeft - half, rect.width);\n const nextCenter = clampedEdge + half;\n if (nextCenter !== centerLeft) setCenterLeft(nextCenter);\n }, [isOpen, menuRef, centerLeft]);\n\n return centerLeft;\n}\n\n/**\n * For a popover RIGHT-anchored on an x-coordinate via `left: <rightEdgeX>;\n * transform: translateX(-100%)` (TableHeaderRow's column menu, whose right\n * edge lines up with the header cell's own right edge and grows leftward)\n * — clamps the box's actual left edge and returns an adjusted `rightEdgeX`\n * for that same `left` + `transform: translateX(-100%)` pairing.\n */\nexport function useAutoAdjustedRightLeft(menuRef, isOpen, rawRightEdgeLeft) {\n const [rightLeft, setRightLeft] = useState(null);\n\n useLayoutEffect(() => {\n setRightLeft(rawRightEdgeLeft ?? null);\n }, [rawRightEdgeLeft]);\n\n useLayoutEffect(() => {\n if (!isOpen || !menuRef.current || rightLeft == null) return;\n const rect = menuRef.current.getBoundingClientRect();\n const clampedEdge = clampLeftToViewport(rightLeft - rect.width, rect.width);\n const nextRightLeft = clampedEdge + rect.width;\n if (nextRightLeft !== rightLeft) setRightLeft(nextRightLeft);\n }, [isOpen, menuRef, rightLeft]);\n\n return rightLeft;\n}\n","import { useEffect, useState } from 'react';\n\nfunction computeInset() {\n if (typeof window === 'undefined' || !window.visualViewport) return 0;\n const vv = window.visualViewport;\n // How much of the layout viewport's bottom is currently covered by the\n // on-screen keyboard (or any other viewport-shrinking browser chrome):\n // the gap between the full layout height and the visual viewport's own\n // bottom edge (its height plus however far it's scrolled/offset down).\n const inset = window.innerHeight - (vv.height + vv.offsetTop);\n return inset > 0 ? Math.round(inset) : 0;\n}\n\n/**\n * Tracks the on-screen keyboard's real height via the visualViewport API —\n * 0 when there's no keyboard (or no visualViewport support at all, e.g.\n * older browsers/SSR). This is what lets MobileActionBar sit at\n * `bottom: <inset>px` and land exactly above the keyboard instead of\n * guessing a fixed offset, and lets trigger-menu/Select popovers clamp\n * their own vertical position so they don't render underneath it.\n *\n * Listens on visualViewport's own 'resize'/'scroll' (not window's) — the\n * keyboard opening/closing changes the *visual* viewport, not the layout\n * one, and most mobile browsers don't fire window 'resize' for it at all.\n */\nexport function useVirtualKeyboardInset() {\n const [inset, setInset] = useState(computeInset);\n\n useEffect(() => {\n if (typeof window === 'undefined' || !window.visualViewport) return undefined;\n const vv = window.visualViewport;\n const handleChange = () => setInset(computeInset());\n handleChange();\n vv.addEventListener('resize', handleChange);\n vv.addEventListener('scroll', handleChange);\n return () => {\n vv.removeEventListener('resize', handleChange);\n vv.removeEventListener('scroll', handleChange);\n };\n }, []);\n\n return inset;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { ChevronDownIcon } from './icons.jsx';\r\nimport { useOutsideClickAndEscape } from './useOutsideClickAndEscape.js';\r\nimport { useVirtualKeyboardInset } from './useVirtualKeyboardInset.js';\r\nimport { useHorizontalAutoAdjustedLeft } from './usePopoverEdgeClamp.js';\r\n\r\n// Rough worst-case popover height (max-height in .be-select-options's own\r\n// CSS is 220px, plus the search input and padding) — only used to decide\r\n// which side of the trigger to open on, not as an exact pixel budget.\r\nconst ESTIMATED_POPOVER_HEIGHT = 280;\r\n\r\nfunction matchesQuery(option, query) {\r\n if (!query) return true;\r\n return option.label.toLowerCase().includes(query.toLowerCase());\r\n}\r\n\r\n/**\r\n * A lightweight, dependency-free \"searchable select\" (Ant Design Select-\r\n * style combobox) used everywhere this editor previously used a native\r\n * `<select>`: a trigger button showing the current value, opening a\r\n * fixed-position popover with a search input and a filtered, keyboard-\r\n * navigable option list on click. A native `<select>`'s own dropdown can't\r\n * be styled or searched, which is the whole reason this exists — visually\r\n * and behaviorally consistent across every dropdown in the editor instead\r\n * of each one looking like the browser's own chrome.\r\n *\r\n * `options` is `[{ value, label }]`; `onChange(value, option)` fires on\r\n * pick (both are passed since several call sites want the option's label\r\n * too, e.g. to store alongside its id). Deliberately does NOT support\r\n * creating new options inline — that's each call site's own concern (e.g.\r\n * a table's \"select\" column options are managed via TableHeaderRow's own\r\n * add/rename/remove UI) — this component only ever picks one of the\r\n * options it's given.\r\n *\r\n * The popover (search input + option list) is rendered via a portal to\r\n * `document.body` — same as SlashMenu/FloatingToolbar, which are also\r\n * mounted as siblings of the contentEditable tree, never nested inside it.\r\n * Several call sites mount this *trigger* deep inside an atomic\r\n * contentEditable=false inline chip (select/table-select/custom field type), which\r\n * itself lives inside a contentEditable=true paragraph. A real, focusable\r\n * `<input>` — unlike a native `<select>`'s own OS-level dropdown, which\r\n * never actually hands page focus to anything — left nested that deep\r\n * fights the surrounding contentEditable region for focus in ways real\r\n * browsers resolve inconsistently (and jsdom doesn't reproduce at all):\r\n * the very first character typed could land back in the paragraph instead\r\n * of the search box, since a real native `<input>` there is a genuinely new\r\n * DOM subtree fighting for focus a native `<select>` never had to. Portaling\r\n * the popover out to `document.body` sidesteps the whole problem — it's a\r\n * true DOM sibling of the editor surface, not a descendant, so it can never\r\n * lose that tug-of-war.\r\n *\r\n * `variant=\"tag\"` renders the selected value (and each option in the list)\r\n * as a small colored pill instead of plain text in a bordered/chevroned\r\n * box — a familiar Select-property look. Pass `color: { bg, text }` on\r\n * each option for this (see blocks/table/tagColors.js); the trigger itself\r\n * loses its border/background/chevron chrome entirely in this mode — just\r\n * the pill (or the placeholder, if nothing's chosen yet) is clickable.\r\n *\r\n * `options` may also be a function `(query) => Option[] | Promise<Option[]>`\r\n * instead of a plain array — this is how custom field types (see\r\n * createSelectFieldType) support DB/API-backed option sources (react-\r\n * select's `loadOptions`, essentially) alongside plain static lists,\r\n * through the exact same component and contract. When `options` is a\r\n * function it's called fresh on every query change (debounced ~250ms so\r\n * fast typing doesn't fire one request per keystroke) — deliberately no\r\n * caching layer here, so the host's own resolver is always the source of\r\n * truth for a given query; any caching is that function's own concern.\r\n * Static array callers are entirely unaffected: filtering there stays\r\n * synchronous and instant, exactly as before.\r\n *\r\n * Since a dynamic resolver's currently-loaded page may not contain the\r\n * option matching the CURRENT value (it was picked under a different\r\n * query, or came from elsewhere), pass `selectedLabel` to control what the\r\n * trigger displays for the current value directly, instead of relying on\r\n * an `options.find(...)` lookup that only works for static arrays.\r\n */\r\nexport function Select({\r\n value,\r\n options,\r\n onChange,\r\n placeholder = 'Select…',\r\n ariaLabel,\r\n className = '',\r\n variant = 'default',\r\n selectedLabel,\r\n selectedColor,\r\n onManageOptions,\r\n manageOptionsLabel = 'Manage options…',\r\n mention = false,\r\n}) {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [query, setQuery] = useState('');\r\n const [activeIndex, setActiveIndex] = useState(0);\r\n const [rect, setRect] = useState(null);\r\n const keyboardInset = useVirtualKeyboardInset();\r\n const [asyncOptions, setAsyncOptions] = useState([]);\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [loadError, setLoadError] = useState(false);\r\n const rootRef = useRef(null);\r\n const buttonRef = useRef(null);\r\n const popoverRef = useRef(null);\r\n const inputRef = useRef(null);\r\n const activeOptionRef = useRef(null);\r\n const outsideRefs = useMemo(() => [rootRef, popoverRef], []);\r\n const isTag = variant === 'tag';\r\n const isDynamic = typeof options === 'function';\r\n\r\n const staticSelected = !isDynamic ? options.find((o) => o.value === value) : undefined;\r\n const selected = value\r\n ? (staticSelected ?? (selectedLabel ? { value, label: selectedLabel, color: selectedColor } : undefined))\r\n : undefined;\r\n\r\n const filtered = useMemo(\r\n () => (isDynamic ? asyncOptions : options.filter((o) => matchesQuery(o, query))),\r\n [isDynamic, asyncOptions, options, query],\r\n );\r\n\r\n // Dynamic resolvers already do their own query-based filtering (a DB\r\n // search, typically) — refetch on every query change while the popover\r\n // is open, debounced so a fast typist doesn't fire one call per keystroke.\r\n useEffect(() => {\r\n if (!isDynamic || !isOpen) return undefined;\r\n let cancelled = false;\r\n setIsLoading(true);\r\n setLoadError(false);\r\n const timer = setTimeout(() => {\r\n Promise.resolve(options(query))\r\n .then((result) => {\r\n if (cancelled) return;\r\n setAsyncOptions(result ?? []);\r\n setIsLoading(false);\r\n })\r\n .catch(() => {\r\n if (cancelled) return;\r\n setAsyncOptions([]);\r\n setIsLoading(false);\r\n setLoadError(true);\r\n });\r\n }, 250);\r\n return () => {\r\n cancelled = true;\r\n clearTimeout(timer);\r\n };\r\n }, [isDynamic, isOpen, options, query]);\r\n\r\n const close = useCallback(() => setIsOpen(false), []);\r\n\r\n useOutsideClickAndEscape(outsideRefs, isOpen, close);\r\n const adjustedLeft = useHorizontalAutoAdjustedLeft(popoverRef, isOpen, rect?.left);\r\n\r\n const open = useCallback(() => {\r\n setRect(buttonRef.current?.getBoundingClientRect() ?? null);\r\n setQuery('');\r\n setActiveIndex(0);\r\n setIsOpen(true);\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (isOpen) inputRef.current?.focus();\r\n }, [isOpen]);\r\n\r\n // Keeps the keyboard-active option (Arrow Up/Down) visible as it moves\r\n // past the edge of the scrollable list — without this, arrowing down\r\n // past the bottom of a long option list leaves the \"active\" highlight\r\n // scrolled out of view with nothing on screen showing which one it is.\r\n useEffect(() => {\r\n activeOptionRef.current?.scrollIntoView?.({ block: 'nearest' });\r\n }, [activeIndex]);\r\n\r\n const selectOption = useCallback(\r\n (option) => {\r\n onChange(option.value, option);\r\n close();\r\n buttonRef.current?.focus();\r\n },\r\n [onChange, close],\r\n );\r\n\r\n const handleSearchKeyDown = useCallback(\r\n (event) => {\r\n if (event.key === 'ArrowDown') {\r\n event.preventDefault();\r\n setActiveIndex((i) => Math.min(i + 1, Math.max(filtered.length - 1, 0)));\r\n } else if (event.key === 'ArrowUp') {\r\n event.preventDefault();\r\n setActiveIndex((i) => Math.max(i - 1, 0));\r\n } else if (event.key === 'Enter') {\r\n event.preventDefault();\r\n if (filtered[activeIndex]) selectOption(filtered[activeIndex]);\r\n } else if (event.key === 'Escape') {\r\n event.preventDefault();\r\n close();\r\n buttonRef.current?.focus();\r\n }\r\n },\r\n [filtered, activeIndex, selectOption, close],\r\n );\r\n\r\n return (\r\n <span className={`be-select ${className}`.trim()} ref={rootRef}>\r\n <button\r\n type=\"button\"\r\n ref={buttonRef}\r\n className={`be-select-trigger${isTag ? ' be-select-trigger-tag' : ''}${mention ? ' be-select-trigger-mention' : ''}`}\r\n aria-haspopup=\"listbox\"\r\n aria-expanded={isOpen}\r\n aria-label={ariaLabel}\r\n onClick={() => (isOpen ? close() : open())}\r\n >\r\n {isTag ? (\r\n selected ? (\r\n <span\r\n className={`be-select-tag${mention ? ' be-select-tag-mention' : ''}`}\r\n style={mention ? undefined : { background: selected.color?.bg, color: selected.color?.text }}\r\n >\r\n {mention ? `@${selected.label}` : selected.label}\r\n </span>\r\n ) : (\r\n <span className=\"be-select-value be-select-value-placeholder\">{placeholder}</span>\r\n )\r\n ) : (\r\n <>\r\n <span className=\"be-select-value\">{selected ? selected.label : placeholder}</span>\r\n <ChevronDownIcon size={14} className=\"be-select-chevron\" />\r\n </>\r\n )}\r\n </button>\r\n {isOpen &&\r\n rect &&\r\n adjustedLeft != null &&\r\n createPortal(\r\n <div\r\n ref={popoverRef}\r\n className=\"be-select-popover\"\r\n style={{\r\n position: 'fixed',\r\n left: adjustedLeft,\r\n minWidth: rect.width,\r\n // Flips above the trigger instead of below it once there isn't\r\n // enough room left before the keyboard (or screen bottom) —\r\n // otherwise the popover can render partly/entirely hidden\r\n // underneath an open on-screen keyboard.\r\n ...(rect.bottom + ESTIMATED_POPOVER_HEIGHT > window.innerHeight - keyboardInset\r\n ? { bottom: window.innerHeight - rect.top + 4 }\r\n : { top: rect.bottom + 4 }),\r\n }}\r\n >\r\n <input\r\n ref={inputRef}\r\n type=\"text\"\r\n className=\"be-select-search\"\r\n value={query}\r\n onChange={(event) => {\r\n setQuery(event.target.value);\r\n setActiveIndex(0);\r\n }}\r\n onKeyDown={handleSearchKeyDown}\r\n placeholder=\"Search…\"\r\n aria-label={ariaLabel ? `Search ${ariaLabel}` : 'Search options'}\r\n />\r\n <div className=\"be-select-options\" role=\"listbox\">\r\n {isDynamic && isLoading && <div className=\"be-select-empty\">Loading…</div>}\r\n {isDynamic && !isLoading && loadError && <div className=\"be-select-empty be-select-error\">Couldn't load options</div>}\r\n {!isLoading && !loadError && filtered.length === 0 && <div className=\"be-select-empty\">No results</div>}\r\n {!isLoading &&\r\n !loadError &&\r\n filtered.map((option, i) => (\r\n <div\r\n key={option.value}\r\n ref={i === activeIndex ? activeOptionRef : undefined}\r\n role=\"option\"\r\n aria-selected={option.value === value}\r\n className={`be-select-option${i === activeIndex ? ' be-select-option-active' : ''}${\r\n option.value === value ? ' be-select-option-selected' : ''\r\n }`}\r\n onMouseDown={(event) => {\r\n event.preventDefault(); // keep focus in the search input until a real selection commits\r\n selectOption(option);\r\n }}\r\n onMouseEnter={() => setActiveIndex(i)}\r\n >\r\n {isTag ? (\r\n <span className=\"be-select-tag\" style={{ background: option.color?.bg, color: option.color?.text }}>\r\n {option.label}\r\n </span>\r\n ) : (\r\n option.label\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n {onManageOptions && (\r\n <button\r\n type=\"button\"\r\n className=\"be-select-manage-options\"\r\n onMouseDown={(event) => {\r\n event.preventDefault();\r\n close();\r\n onManageOptions();\r\n }}\r\n >\r\n {manageOptionsLabel}\r\n </button>\r\n )}\r\n </div>,\r\n document.body,\r\n )}\r\n </span>\r\n );\r\n}\r\n","/**\r\n * Tag color palette for a table's \"select\" column — assigned\r\n * once, at option-creation time (see TableHeaderRow's SelectOptionsManager),\r\n * and stored on the option itself (`{ value, label, color }`) so it stays\r\n * stable across reorders/removals: a tag keeps whatever color it was\r\n * first given.\r\n */\r\nexport const TAG_COLORS = [\r\n { bg: '#e9e9e7', text: '#32302c' }, // gray (default)\r\n { bg: '#eee0da', text: '#64473a' }, // brown\r\n { bg: '#fadec9', text: '#8a4b23' }, // orange\r\n { bg: '#fdecc8', text: '#8a6116' }, // yellow\r\n { bg: '#dbeddb', text: '#256029' }, // green\r\n { bg: '#d3e5ef', text: '#1a5f8a' }, // blue\r\n { bg: '#e8deee', text: '#5b3a8a' }, // purple\r\n { bg: '#f5e0e9', text: '#8a3a5f' }, // pink\r\n { bg: '#ffe2dd', text: '#a13a2f' }, // red\r\n];\r\n\r\n/** Cycles through TAG_COLORS by index — deterministic, no randomness. */\r\nexport function pickTagColor(index) {\r\n return TAG_COLORS[((index % TAG_COLORS.length) + TAG_COLORS.length) % TAG_COLORS.length];\r\n}\r\n","import { useCallback, useMemo, useRef, useState } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { useEditorStore, useInlineRegistry } from '../../react/EditorProvider.jsx';\r\nimport { useOutsideClickAndEscape } from '../../react/useOutsideClickAndEscape.js';\r\nimport { useMenuKeyboardNav } from '../../react/useMenuKeyboardNav.js';\r\nimport { useAutoAdjustedRightLeft } from '../../react/usePopoverEdgeClamp.js';\r\nimport { insertColumnAfter, deleteColumn, renameColumn, setColumnType, setColumnOptions, setColumnWidth } from './tableEditCommands.js';\r\nimport { COLUMN_TYPES, MIN_COLUMN_WIDTH } from './tableColumns.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { XIcon } from '../../react/icons.jsx';\r\nimport { Select } from '../../react/Select.jsx';\r\nimport { pickTagColor } from './tagColors.js';\r\n\r\nconst TYPE_LABELS = { text: 'Text', date: 'Date', checkbox: 'Checkbox', select: 'Select' };\r\nconst TYPE_OPTIONS = COLUMN_TYPES.map((type) => ({ value: type, label: TYPE_LABELS[type] }));\r\n\r\n// A column's actual drag width is unbounded (no real max exists in\r\n// tableColumns.js) — this is only a hint for the resize handle's own\r\n// aria-valuemax, so a screen reader has *some* sense of position within a\r\n// reasonable range, not a value that's ever enforced against real dragging.\r\nconst MAX_COLUMN_WIDTH_HINT = 800;\r\n\r\n/**\r\n * Manages a \"select\" column's shared option list (add/rename/remove) —\r\n * configured once here, for the whole column, rather than per cell. This\r\n * is the piece that makes a select column behave like a shared property\r\n * instead of the general-purpose inline `select` type's\r\n * independent-per-chip options: every cell reads the *same* list (see\r\n * TableSelectInlineNode), so it only needs managing in one place.\r\n */\r\nfunction SelectOptionsManager({ tableId, colIndex, options }) {\r\n const store = useEditorStore();\r\n const [draft, setDraft] = useState('');\r\n\r\n const handleRename = useCallback(\r\n (optionValue, label) => {\r\n setColumnOptions(store, tableId, colIndex, options.map((o) => (o.value === optionValue ? { ...o, label } : o)));\r\n },\r\n [store, tableId, colIndex, options],\r\n );\r\n const handleRemove = useCallback(\r\n (optionValue) => setColumnOptions(store, tableId, colIndex, options.filter((o) => o.value !== optionValue)),\r\n [store, tableId, colIndex, options],\r\n );\r\n const handleAdd = useCallback(() => {\r\n const label = draft.trim();\r\n setDraft('');\r\n if (!label) return;\r\n // Color is assigned once, here, at creation time — not derived from\r\n // position at render time — so it stays the same tag color even after\r\n // other options are reordered/removed — a tag's color is fixed once\r\n // you pick/create it.\r\n setColumnOptions(store, tableId, colIndex, [...options, { value: genId(), label, color: pickTagColor(options.length) }]);\r\n }, [store, tableId, colIndex, options, draft]);\r\n\r\n return (\r\n <div className=\"be-table-header-menu-options\">\r\n <div className=\"be-table-header-menu-options-label\">Options</div>\r\n {options.map((option, i) => (\r\n <div key={option.value} className=\"be-table-header-menu-option-row\">\r\n <span\r\n className=\"be-table-header-menu-option-swatch\"\r\n style={{ background: (option.color ?? pickTagColor(i)).bg }}\r\n aria-hidden=\"true\"\r\n />\r\n <input\r\n className=\"be-table-header-menu-option-input\"\r\n value={option.label}\r\n onChange={(event) => handleRename(option.value, event.target.value)}\r\n aria-label={`Rename option ${option.label}`}\r\n />\r\n <button\r\n type=\"button\"\r\n className=\"be-table-header-menu-option-remove\"\r\n onClick={() => handleRemove(option.value)}\r\n aria-label={`Remove option ${option.label}`}\r\n >\r\n <XIcon size={14} />\r\n </button>\r\n </div>\r\n ))}\r\n <div className=\"be-table-header-menu-option-row\">\r\n <input\r\n className=\"be-table-header-menu-option-input\"\r\n value={draft}\r\n onChange={(event) => setDraft(event.target.value)}\r\n placeholder=\"New option…\"\r\n onKeyDown={(event) => {\r\n if (event.key === 'Enter') {\r\n event.preventDefault();\r\n handleAdd();\r\n }\r\n }}\r\n />\r\n <button type=\"button\" className=\"be-table-header-menu-option-add\" onClick={handleAdd} aria-label=\"Add option\">\r\n +\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n/**\r\n * One header cell: an editable label, a small self-built menu (change\r\n * type, manage select options, insert column left/right, delete column),\r\n * and a drag handle on its right edge to resize the column.\r\n *\r\n * The menu is portaled to `document.body` (`position: fixed`, computed\r\n * from the trigger button's own bounding rect) — same convention as\r\n * Select/SlashMenu elsewhere in this codebase — instead of a plain\r\n * absolutely-positioned child of this `<th>`. A table can genuinely\r\n * overflow its wrapper (see `.be-table-wrapper`'s `overflow-x: auto`), and\r\n * a plain in-flow popup gets visually clipped by that; portaling escapes\r\n * it entirely, the same reason Select's own popover is portaled.\r\n *\r\n * Changing type runs every existing cell in the column through\r\n * setColumnType's data-preserving conversion (see tableColumns.js) rather\r\n * than discarding values — the actual gap this feature was built to close\r\n * versus the legacy notevo table it's modeled after.\r\n */\r\nfunction ColumnHeaderCell({ tableId, column, colIndex, colCount }) {\r\n const store = useEditorStore();\r\n const inlineRegistry = useInlineRegistry();\r\n const [isMenuOpen, setIsMenuOpen] = useState(false);\r\n const [rect, setRect] = useState(null);\r\n const [dragWidth, setDragWidth] = useState(null);\r\n const triggerRef = useRef(null);\r\n const menuRef = useRef(null);\r\n const thRef = useRef(null);\r\n const outsideRefs = useMemo(() => [triggerRef, menuRef], []);\r\n\r\n const closeMenu = useCallback(() => setIsMenuOpen(false), []);\r\n useOutsideClickAndEscape(outsideRefs, isMenuOpen, closeMenu);\r\n useMenuKeyboardNav(menuRef, isMenuOpen, closeMenu, triggerRef);\r\n const rightLeft = useAutoAdjustedRightLeft(menuRef, isMenuOpen, rect?.right);\r\n\r\n const openMenu = useCallback(() => {\r\n // Anchor to the whole header cell, not the small vertically-centered\r\n // trigger icon (triggerRef) — using the icon's own rect put the menu's\r\n // top a few px below the icon's *midpoint*, which sat mid-cell and\r\n // overlapped the column label instead of opening cleanly below it.\r\n setRect(thRef.current?.getBoundingClientRect() ?? null);\r\n setIsMenuOpen(true);\r\n }, []);\r\n\r\n const handleLabelChange = useCallback(\r\n (event) => renameColumn(store, tableId, colIndex, event.target.value),\r\n [store, tableId, colIndex],\r\n );\r\n const handleInsertLeft = useCallback(() => {\r\n insertColumnAfter(store, tableId, colIndex - 1);\r\n closeMenu();\r\n }, [store, tableId, colIndex, closeMenu]);\r\n const handleInsertRight = useCallback(() => {\r\n insertColumnAfter(store, tableId, colIndex);\r\n closeMenu();\r\n }, [store, tableId, colIndex, closeMenu]);\r\n const handleDelete = useCallback(() => {\r\n deleteColumn(store, tableId, colIndex);\r\n closeMenu();\r\n }, [store, tableId, colIndex, closeMenu]);\r\n const handleTypeChange = useCallback(\r\n (type) => setColumnType(store, tableId, colIndex, type, inlineRegistry),\r\n [store, tableId, colIndex, inlineRegistry],\r\n );\r\n\r\n // Live-updates the <colgroup>'s own <col> element directly during drag\r\n // (see TableBlock.jsx's data-col-index) rather than dispatching a store\r\n // write on every mousemove — the store only gets ONE write, on mouseup,\r\n // matching EmbedBlock's own resize-handle convention.\r\n const handleResizeStart = useCallback(\r\n (event) => {\r\n event.preventDefault();\r\n const table = thRef.current?.closest('table');\r\n const col = table?.querySelector(`col[data-col-index=\"${colIndex}\"]`);\r\n if (!col) return;\r\n const startWidth = thRef.current.getBoundingClientRect().width;\r\n const startX = event.clientX;\r\n\r\n const computeWidth = (moveEvent) => Math.max(MIN_COLUMN_WIDTH, Math.round(startWidth + (moveEvent.clientX - startX)));\r\n\r\n const handleMouseMove = (moveEvent) => {\r\n const width = computeWidth(moveEvent);\r\n col.style.width = `${width}px`;\r\n setDragWidth(width);\r\n };\r\n const handleMouseUp = (upEvent) => {\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n document.removeEventListener('mouseup', handleMouseUp);\r\n setColumnWidth(store, tableId, colIndex, computeWidth(upEvent));\r\n setDragWidth(null);\r\n };\r\n document.addEventListener('mousemove', handleMouseMove);\r\n document.addEventListener('mouseup', handleMouseUp);\r\n },\r\n [store, tableId, colIndex],\r\n );\r\n\r\n return (\r\n <th ref={thRef} scope=\"col\" className=\"be-table-header-cell\" contentEditable={false}>\r\n <input\r\n className=\"be-table-header-label\"\r\n value={column.label}\r\n onChange={handleLabelChange}\r\n aria-label={`Column ${colIndex + 1} name`}\r\n />\r\n <button\r\n ref={triggerRef}\r\n type=\"button\"\r\n className=\"be-table-header-menu-trigger\"\r\n aria-label={`Column ${colIndex + 1} options`}\r\n aria-haspopup=\"menu\"\r\n aria-expanded={isMenuOpen}\r\n onClick={() => (isMenuOpen ? closeMenu() : openMenu())}\r\n >\r\n &#8942;\r\n </button>\r\n <div\r\n className=\"be-table-col-resize-handle\"\r\n onMouseDown={handleResizeStart}\r\n role=\"slider\"\r\n aria-label={`Resize column ${colIndex + 1}`}\r\n aria-valuemin={MIN_COLUMN_WIDTH}\r\n aria-valuemax={MAX_COLUMN_WIDTH_HINT}\r\n aria-valuenow={dragWidth ?? column.width}\r\n />\r\n {isMenuOpen &&\r\n rect &&\r\n rightLeft != null &&\r\n createPortal(\r\n <div\r\n ref={menuRef}\r\n role=\"menu\"\r\n aria-label={`Column ${colIndex + 1} options`}\r\n className=\"be-table-header-menu\"\r\n style={{ position: 'fixed', top: rect.bottom + 4, left: rightLeft, transform: 'translateX(-100%)' }}\r\n >\r\n <div className=\"be-table-header-menu-type\">\r\n <span id={`be-table-col-type-${column.id}`}>Type</span>\r\n <Select\r\n value={column.type}\r\n options={TYPE_OPTIONS}\r\n onChange={handleTypeChange}\r\n ariaLabel=\"Column type\"\r\n className=\"\"\r\n />\r\n </div>\r\n {column.type === 'select' && (\r\n <SelectOptionsManager tableId={tableId} colIndex={colIndex} options={column.options ?? []} />\r\n )}\r\n <button type=\"button\" role=\"menuitem\" className=\"be-table-header-menu-item\" onClick={handleInsertLeft}>\r\n Insert column left\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-table-header-menu-item\" onClick={handleInsertRight}>\r\n Insert column right\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"menuitem\"\r\n className=\"be-table-header-menu-item be-table-header-menu-item-danger\"\r\n onClick={handleDelete}\r\n disabled={colCount <= 1}\r\n >\r\n Delete column\r\n </button>\r\n </div>,\r\n document.body,\r\n )}\r\n </th>\r\n );\r\n}\r\n\r\n/**\r\n * Renders as a real `<thead>` above the table's `<tbody>` (see TableBlock),\r\n * one `<th>` per column driven by the table's own `props.columns` metadata\r\n * (see tableColumns.js) — not a \"block\" of its own, since column labels\r\n * are table-level metadata, not content that needs runs/selection/undo\r\n * machinery of its own. A trailing spacer `<th>` keeps header columns\r\n * aligned with TableRowBlock's extra row-actions column.\r\n */\r\nexport function TableHeaderRow({ tableId, columns }) {\r\n return (\r\n <thead>\r\n <tr className=\"be-table-header-row\">\r\n {columns.map((column, i) => (\r\n <ColumnHeaderCell key={column.id} tableId={tableId} column={column} colIndex={i} colCount={columns.length} />\r\n ))}\r\n <th className=\"be-table-header-spacer\" aria-hidden=\"true\" />\r\n </tr>\r\n </thead>\r\n );\r\n}\r\n","import { useCallback } from 'react';\r\nimport { BlockChildren } from '../../react/BlockChildren.jsx';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { insertRowAfter } from './tableEditCommands.js';\r\nimport { resolveColumns } from './tableColumns.js';\r\nimport { TableHeaderRow } from './TableHeaderRow.jsx';\r\nimport { PlusIcon } from '../../react/icons.jsx';\r\n\r\nexport function TableBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n\r\n const handleAddRow = useCallback(() => {\r\n const lastRowId = block?.contentIds?.[block.contentIds.length - 1];\r\n if (lastRowId) insertRowAfter(store, lastRowId);\r\n }, [store, block]);\r\n\r\n const className = useBlockClassName('be-table-wrapper', block);\r\n\r\n if (!block) return null;\r\n\r\n const firstRow = store.getBlock(block.contentIds[0]);\r\n const columns = resolveColumns(block, firstRow?.contentIds?.length ?? 0);\r\n\r\n return (\r\n // be-table-scroll is a second, OUTER scroll boundary around\r\n // be-table-wrapper's own overflow-x:auto: a fixed-layout table whose\r\n // columns sum wider than the page can otherwise force its ancestors\r\n // (this block's row content, .be-surface, ...) to grow to fit it\r\n // instead of actually scrolling inside be-table-wrapper — depending on\r\n // the host app's own surrounding layout, that can bubble all the way\r\n // up to the whole page scrolling horizontally. This wrapper's own\r\n // max-width:100% + overflow-x:auto is a hard stop that can't be\r\n // out-grown by anything inside it, regardless of what's going on\r\n // further up the tree.\r\n <div className=\"be-table-scroll\">\r\n <div className={className} data-block-id={id}>\r\n <table className=\"be-table\">\r\n {/*\r\n A <colgroup> is what makes column resizing work at all: with\r\n table-layout: fixed (see CSS), every <col>'s own width applies\r\n uniformly to that column across the header row AND every body\r\n row's cell at that index — one <col> per column is the single\r\n source of truth for its rendered width, so TableCellBlock/\r\n TableRowBlock never need their own column-width prop-threading.\r\n data-col-index is how the header's own resize-drag handler finds\r\n and live-updates the right <col> imperatively while dragging (see\r\n ColumnHeaderCell), without touching React state on every\r\n mousemove.\r\n */}\r\n <colgroup>\r\n {columns.map((column, i) => (\r\n <col key={column.id} data-col-index={i} style={{ width: column.width }} />\r\n ))}\r\n <col className=\"be-table-header-spacer-col\" />\r\n </colgroup>\r\n <TableHeaderRow tableId={id} columns={columns} />\r\n <tbody>\r\n <BlockChildren parentId={id} />\r\n </tbody>\r\n </table>\r\n <button type=\"button\" className=\"be-table-add-row\" contentEditable={false} onClick={handleAddRow}>\r\n <PlusIcon size={14} /> Add row\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useCallback } from 'react';\r\nimport { BlockChildren } from '../../react/BlockChildren.jsx';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { deleteRow } from './tableEditCommands.js';\r\nimport { XIcon } from '../../react/icons.jsx';\r\n\r\n// Reuses the exact same container/tree-walking mechanism as every other\r\n// non-leaf block (page, layout column, list item children) — the only\r\n// difference is the wrapping <tr> tag.\r\nexport function TableRowBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n const className = useBlockClassName('be-table-row', block);\r\n const handleDeleteRow = useCallback(() => deleteRow(store, id), [store, id]);\r\n\r\n return (\r\n <tr className={className} data-block-id={id}>\r\n <BlockChildren parentId={id} />\r\n <td className=\"be-table-row-actions\" contentEditable={false}>\r\n <button type=\"button\" className=\"be-table-delete-row\" onClick={handleDeleteRow} aria-label=\"Delete row\" title=\"Delete row\">\r\n <XIcon size={14} />\r\n </button>\r\n </td>\r\n </tr>\r\n );\r\n}\r\n","import { focusRunEnd } from '../../react/focusRun.js';\r\nimport { resolveAdjacentFocusTarget } from '../shared/navigationCommands.js';\r\nimport { insertSiblingAfterAndFocus } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\n\r\nfunction locateCell(store, cellId) {\r\n const cell = store.getBlock(cellId);\r\n const row = store.getBlock(cell.parentId);\r\n const table = store.getBlock(row.parentId);\r\n return { table, row, rowIndex: table.contentIds.indexOf(row.id), colIndex: row.contentIds.indexOf(cellId) };\r\n}\r\n\r\n/**\r\n * Resolves the target cell id when moving from `cellId` in `direction`\r\n * ('left' | 'right' | 'up' | 'down'). Pure, no side effects — returns null\r\n * at any of the table's edges (first/last cell of a row, top/bottom of a\r\n * column), leaving what to do about that boundary to the caller\r\n * (moveToAdjacentCell).\r\n *\r\n * 'up'/'down' stay in the same column and return null at the table's\r\n * top/bottom edge — moving out of the table into a sibling block above/below\r\n * it is a follow-up (same cross-container caveat as navigationCommands.js).\r\n */\r\nexport function resolveAdjacentCellTarget(store, cellId, direction) {\r\n const { table, row, rowIndex, colIndex } = locateCell(store, cellId);\r\n\r\n if (direction === 'left' || direction === 'right') {\r\n const delta = direction === 'right' ? 1 : -1;\r\n const nextColIndex = colIndex + delta;\r\n if (nextColIndex >= 0 && nextColIndex < row.contentIds.length) {\r\n return row.contentIds[nextColIndex];\r\n }\r\n\r\n const nextRowIndex = rowIndex + delta;\r\n if (nextRowIndex < 0 || nextRowIndex >= table.contentIds.length) return null; // at the table's very first/last cell\r\n\r\n const targetRow = store.getBlock(table.contentIds[nextRowIndex]);\r\n const targetColIndex = direction === 'right' ? 0 : targetRow.contentIds.length - 1;\r\n return targetRow.contentIds[targetColIndex];\r\n }\r\n\r\n const delta = direction === 'down' ? 1 : -1;\r\n const targetRowIndex = rowIndex + delta;\r\n if (targetRowIndex < 0 || targetRowIndex >= table.contentIds.length) return null;\r\n const targetRow = store.getBlock(table.contentIds[targetRowIndex]);\r\n return targetRow.contentIds[colIndex] ?? targetRow.contentIds[targetRow.contentIds.length - 1] ?? null;\r\n}\r\n\r\n/**\r\n * Tab past the table's very last cell exits it entirely — focuses whatever\r\n * block already follows the table (entering it the same way arrow-key\r\n * navigation between top-level blocks does), or, if the table is the last\r\n * block in its container, creates a fresh blank paragraph after it and\r\n * focuses that. Either way Tab always lands somewhere, never a silent\r\n * no-op that leaves the user stuck at the end of a document that happens\r\n * to end in a table.\r\n */\r\nfunction exitTableForward(store, tableId) {\r\n const targetRunId = resolveAdjacentFocusTarget(store, tableId, 'down');\r\n if (targetRunId) {\r\n focusRunEnd(targetRunId);\r\n return;\r\n }\r\n insertSiblingAfterAndFocus(store, tableId, createTextLeafBlock('paragraph'));\r\n}\r\n\r\n/** Moves DOM focus to the adjacent cell resolved by resolveAdjacentCellTarget, or exits the table on Tab past its last cell (see exitTableForward). */\r\nexport function moveToAdjacentCell(store, cellId, direction) {\r\n const targetCellId = resolveAdjacentCellTarget(store, cellId, direction);\r\n if (targetCellId) {\r\n const targetCell = store.getBlock(targetCellId);\r\n const runId = targetCell?.contentIds?.[0];\r\n if (runId) focusRunEnd(runId);\r\n return;\r\n }\r\n\r\n if (direction === 'right') {\r\n const { table } = locateCell(store, cellId);\r\n exitTableForward(store, table.id);\r\n }\r\n // 'left' at the very first cell, and 'up'/'down' at the table's\r\n // top/bottom edge, remain a no-op (see resolveAdjacentCellTarget's doc\r\n // comment on that scope).\r\n}\r\n","import { useCallback } from 'react';\r\nimport { EditableBlockContent } from '../../react/EditableBlockContent.jsx';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { moveToAdjacentCell } from './tableNavigation.js';\r\nimport { resolveBlockDir } from '../shared/resolveBlockDir.js';\r\n\r\n// Deliberately near-identical to ParagraphBlock: a cell is a leaf block\r\n// whose contentIds are run ids, exactly like a paragraph — it gets\r\n// formatting/selection/serialization for free from the same run machinery.\r\n//\r\n// No Backspace-at-start handling: a cell merging into an adjacent cell has\r\n// no sensible meaning (no \"merge cells\" in v1), so native no-op is already\r\n// correct default behavior — not an omission.\r\nexport function TableCellBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n\r\n const handleTab = useCallback(() => moveToAdjacentCell(store, id, 'right'), [store, id]);\r\n const handleShiftTab = useCallback(() => moveToAdjacentCell(store, id, 'left'), [store, id]);\r\n const handleArrowUp = useCallback(() => moveToAdjacentCell(store, id, 'up'), [store, id]);\r\n const handleArrowDown = useCallback(() => moveToAdjacentCell(store, id, 'down'), [store, id]);\r\n // Enter moves down a row (spreadsheet-familiar), matching Tab's row-wrap convention.\r\n const handleEnter = useCallback(() => moveToAdjacentCell(store, id, 'down'), [store, id]);\r\n\r\n const className = useBlockClassName('be-table-cell', block);\r\n\r\n if (!block) return null;\r\n const dir = resolveBlockDir(store, block);\r\n\r\n return (\r\n <td className={className} data-block-id={id} dir={dir}>\r\n <EditableBlockContent\r\n blockId={id}\r\n runIds={block.contentIds}\r\n dir={dir}\r\n onTab={handleTab}\r\n onShiftTab={handleShiftTab}\r\n onArrowUp={handleArrowUp}\r\n onArrowDown={handleArrowDown}\r\n onEnter={handleEnter}\r\n />\r\n </td>\r\n );\r\n}\r\n","import { genId } from '../../utils/idGen.js';\r\nimport { createDefaultColumns, createCellForColumn } from './tableColumns.js';\r\n\r\nfunction createRow(parentId, columns) {\r\n const rowId = genId();\r\n const cellBlocks = [];\r\n const runs = [];\r\n const contentIds = [];\r\n for (const column of columns) {\r\n const cell = createCellForColumn(rowId, column);\r\n cellBlocks.push(cell.block);\r\n runs.push(cell.run);\r\n contentIds.push(cell.block.id);\r\n }\r\n return { block: { id: rowId, type: 'tableRow', parentId, contentIds, props: {} }, blocks: cellBlocks, runs };\r\n}\r\n\r\n/** factory(parentId) -> {block, runs, subtreeBlocks} for a fresh rows x cols table. */\r\nexport function createTableBlock({ rows = 2, cols = 2 } = {}) {\r\n return function factory(parentId) {\r\n const tableId = genId();\r\n const columns = createDefaultColumns(cols);\r\n const subtreeBlocks = [];\r\n const allRuns = [];\r\n const rowIds = [];\r\n\r\n for (let r = 0; r < rows; r += 1) {\r\n const row = createRow(tableId, columns);\r\n subtreeBlocks.push(row.block, ...row.blocks);\r\n allRuns.push(...row.runs);\r\n rowIds.push(row.block.id);\r\n }\r\n\r\n const block = { id: tableId, type: 'table', parentId, contentIds: rowIds, props: { columns } };\r\n return { block, runs: allRuns, subtreeBlocks };\r\n };\r\n}\r\n","import { TableBlock } from './TableBlock.jsx';\r\nimport { TableRowBlock } from './TableRowBlock.jsx';\r\nimport { TableCellBlock } from './TableCellBlock.jsx';\r\nimport { runToHTML, runToPlainText, escapeHTML } from '../../inline/marks.js';\r\nimport { domInlineToRuns } from '../../inline/runOps.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createTableBlock } from './createTableBlock.js';\r\nimport { resolveColumns } from './tableColumns.js';\r\nimport { TableIcon } from '../../react/icons.jsx';\r\n\r\n// --- tableCell: near-identical to paragraph's toHTML/fromHTML/toPlainText ---\r\n\r\nfunction cellToHTML(block, ctx) {\r\n const runs = block.contentIds.map((runId) => ctx.store.getRun(runId));\r\n return `<td>${runs.map((r) => runToHTML(r, ctx)).join('')}</td>`;\r\n}\r\n\r\nfunction cellToPlainText(block, ctx) {\r\n return block.contentIds.map((runId) => runToPlainText(ctx.store.getRun(runId), ctx)).join('');\r\n}\r\n\r\nfunction cellFromHTML(node, ctx) {\r\n if (node.tagName !== 'TD' && node.tagName !== 'TH') return null;\r\n const runs = domInlineToRuns(node, ctx);\r\n const block = { id: genId(), type: 'tableCell', parentId: null, contentIds: runs.map((r) => r.id), props: {} };\r\n return { block, runs };\r\n}\r\n\r\n// --- tableRow: pure container, recurses into cells via the registry ---\r\n\r\nfunction rowToHTML(block, ctx) {\r\n const cellsHTML = block.contentIds\r\n .map((cellId) => {\r\n const cellBlock = ctx.store.getBlock(cellId);\r\n return ctx.registry.get(cellBlock.type).toHTML(cellBlock, ctx);\r\n })\r\n .join('');\r\n return `<tr>${cellsHTML}</tr>`;\r\n}\r\n\r\nfunction rowToPlainText(block, ctx) {\r\n return block.contentIds\r\n .map((cellId) => {\r\n const cellBlock = ctx.store.getBlock(cellId);\r\n return ctx.registry.get(cellBlock.type).toPlainText(cellBlock, ctx);\r\n })\r\n .join('\\t');\r\n}\r\n\r\nfunction rowFromHTML(node, ctx) {\r\n if (node.tagName !== 'TR') return null;\r\n const cellNodes = [...node.children].filter((c) => c.tagName === 'TD' || c.tagName === 'TH');\r\n const rowId = genId();\r\n const cellBlocks = [];\r\n const runs = [];\r\n const contentIds = [];\r\n for (const cellNode of cellNodes) {\r\n const result = ctx.registry.get('tableCell').fromHTML(cellNode, ctx);\r\n if (!result) continue;\r\n result.block.parentId = rowId;\r\n cellBlocks.push(result.block);\r\n runs.push(...result.runs);\r\n contentIds.push(result.block.id);\r\n }\r\n const block = { id: rowId, type: 'tableRow', parentId: null, contentIds, props: {} };\r\n return { block, runs, subtreeBlocks: cellBlocks };\r\n}\r\n\r\n// --- table: container of rows ---\r\n\r\nfunction tableToHTML(block, ctx) {\r\n const firstRow = block.contentIds[0] && ctx.store.getBlock(block.contentIds[0]);\r\n const columns = resolveColumns(block, firstRow?.contentIds?.length ?? 0);\r\n const theadHTML = columns.length\r\n ? `<thead><tr>${columns.map((c) => `<th>${escapeHTML(c.label ?? '')}</th>`).join('')}</tr></thead>`\r\n : '';\r\n\r\n const rowsHTML = block.contentIds\r\n .map((rowId) => {\r\n const rowBlock = ctx.store.getBlock(rowId);\r\n return ctx.registry.get(rowBlock.type).toHTML(rowBlock, ctx);\r\n })\r\n .join('');\r\n return `<table>${theadHTML}<tbody>${rowsHTML}</tbody></table>`;\r\n}\r\n\r\nfunction tableToPlainText(block, ctx) {\r\n return block.contentIds\r\n .map((rowId) => {\r\n const rowBlock = ctx.store.getBlock(rowId);\r\n return ctx.registry.get(rowBlock.type).toPlainText(rowBlock, ctx);\r\n })\r\n .join('\\n');\r\n}\r\n\r\nfunction tableFromHTML(node, ctx) {\r\n if (node.tagName !== 'TABLE') return null;\r\n\r\n // A <thead> row holds column labels, not data — it must never be parsed\r\n // as a body row too (querySelectorAll('tr') would otherwise match it as\r\n // well as every <tbody> row, double-counting it). Its own labels are read\r\n // separately, into props.columns; external HTML with no <thead> at all\r\n // (pasted from another app) just gets none, and TableBlock/tableToHTML's\r\n // resolveColumns fallback generates sensible defaults for it.\r\n const theadRow = node.querySelector('thead tr');\r\n const bodyRowNodes = node.querySelector('tbody')\r\n ? [...node.querySelectorAll('tbody tr')]\r\n : [...node.querySelectorAll('tr')].filter((tr) => tr !== theadRow);\r\n\r\n const tableId = genId();\r\n const subtreeBlocks = [];\r\n const runs = [];\r\n const rowIds = [];\r\n for (const rowNode of bodyRowNodes) {\r\n const result = ctx.registry.get('tableRow').fromHTML(rowNode, ctx);\r\n if (!result) continue;\r\n result.block.parentId = tableId;\r\n for (const cellBlock of result.subtreeBlocks) cellBlock.parentId = result.block.id;\r\n subtreeBlocks.push(result.block, ...result.subtreeBlocks);\r\n runs.push(...result.runs);\r\n rowIds.push(result.block.id);\r\n }\r\n\r\n const props = {};\r\n if (theadRow) {\r\n const headerCells = [...theadRow.children].filter((c) => c.tagName === 'TH' || c.tagName === 'TD');\r\n props.columns = headerCells.map((cell) => ({ id: genId(), label: cell.textContent ?? '' }));\r\n }\r\n\r\n const block = { id: tableId, type: 'table', parentId: null, contentIds: rowIds, props };\r\n return { block, runs, subtreeBlocks };\r\n}\r\n\r\nexport const tableCellBlockType = {\r\n component: TableCellBlock,\r\n isLeaf: true,\r\n defaultProps: {},\r\n toHTML: cellToHTML,\r\n toPlainText: cellToPlainText,\r\n fromHTML: cellFromHTML,\r\n};\r\n\r\nexport const tableRowBlockType = {\r\n component: TableRowBlock,\r\n isLeaf: false,\r\n defaultProps: {},\r\n toHTML: rowToHTML,\r\n toPlainText: rowToPlainText,\r\n fromHTML: rowFromHTML,\r\n};\r\n\r\nexport const tableBlockType = {\r\n component: TableBlock,\r\n isLeaf: false,\r\n defaultProps: {},\r\n toHTML: tableToHTML,\r\n toPlainText: tableToPlainText,\r\n fromHTML: tableFromHTML,\r\n slashCommand: {\r\n label: 'Table',\r\n icon: TableIcon,\r\n keywords: ['table', 'grid'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createTableBlock({ rows: 2, cols: 2 })),\r\n },\r\n};\r\n","import { BlockChildren } from '../../react/BlockChildren.jsx';\nimport { useBlock } from '../../react/useBlock.js';\nimport { useBlockClassName } from '../../react/EditorProvider.jsx';\n\nexport function LayoutBlock({ id }) {\n const block = useBlock(id);\n const className = useBlockClassName('be-layout', block);\n return (\n <div className={className} data-block-id={id} style={{ display: 'flex', gap: '1em' }}>\n <BlockChildren parentId={id} />\n </div>\n );\n}\n","import { BlockChildren } from '../../react/BlockChildren.jsx';\nimport { useBlock } from '../../react/useBlock.js';\nimport { useBlockClassName } from '../../react/EditorProvider.jsx';\n\n// Identical container mechanism to Page — a column just holds arbitrary\n// child blocks via contentIds, same as the document root does.\nexport function LayoutColumnBlock({ id }) {\n const block = useBlock(id);\n const className = useBlockClassName('be-layout-column', block);\n return (\n <div className={className} data-block-id={id}>\n <BlockChildren parentId={id} />\n </div>\n );\n}\n","import { genId } from '../../utils/idGen.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\n\r\n/** factory(parentId) -> {block, runs, subtreeBlocks} for a fresh N-column layout. */\r\nexport function createLayoutBlock({ columns = 2 } = {}) {\r\n return function factory(parentId) {\r\n const layoutId = genId();\r\n const subtreeBlocks = [];\r\n const allRuns = [];\r\n const columnIds = [];\r\n\r\n for (let c = 0; c < columns; c += 1) {\r\n const columnId = genId();\r\n // seed each column with one empty paragraph so there's somewhere to type\r\n const { block: paragraphBlock, runs } = createTextLeafBlock('paragraph')(columnId);\r\n const columnBlock = { id: columnId, type: 'layoutColumn', parentId: layoutId, contentIds: [paragraphBlock.id], props: {} };\r\n subtreeBlocks.push(columnBlock, paragraphBlock);\r\n allRuns.push(...runs);\r\n columnIds.push(columnId);\r\n }\r\n\r\n const block = { id: layoutId, type: 'layout', parentId, contentIds: columnIds, props: {} };\r\n return { block, runs: allRuns, subtreeBlocks };\r\n };\r\n}\r\n","import { LayoutBlock } from './LayoutBlock.jsx';\r\nimport { LayoutColumnBlock } from './LayoutColumnBlock.jsx';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createLayoutBlock } from './createLayoutBlock.js';\r\nimport { ColumnsIcon } from '../../react/icons.jsx';\r\n\r\nfunction containerToHTML(tagOpen, tagClose) {\r\n return (block, ctx) =>\r\n `${tagOpen}${block.contentIds\r\n .map((childId) => {\r\n const child = ctx.store.getBlock(childId);\r\n return ctx.registry.get(child.type).toHTML(child, ctx);\r\n })\r\n .join('')}${tagClose}`;\r\n}\r\n\r\nfunction containerToPlainText(block, ctx) {\r\n return block.contentIds\r\n .map((childId) => {\r\n const child = ctx.store.getBlock(childId);\r\n return ctx.registry.get(child.type).toPlainText(child, ctx);\r\n })\r\n .join('\\n');\r\n}\r\n\r\nexport const layoutColumnBlockType = {\r\n component: LayoutColumnBlock,\r\n isLeaf: false,\r\n defaultProps: {},\r\n toHTML: containerToHTML('<div>', '</div>'),\r\n toPlainText: containerToPlainText,\r\n // no fromHTML: a bare column has no distinct HTML representation of its\r\n // own outside a parent `layout`'s markup; layout.fromHTML would construct\r\n // both together if/when generic multi-column HTML import is added.\r\n};\r\n\r\nexport const layoutBlockType = {\r\n component: LayoutBlock,\r\n isLeaf: false,\r\n defaultProps: {},\r\n toHTML: containerToHTML('<div style=\"display:flex;gap:1em\">', '</div>'),\r\n toPlainText: containerToPlainText,\r\n slashCommands: [2, 3, 4, 5].map((columns) => ({\r\n label: `${columns} columns`,\r\n icon: ColumnsIcon,\r\n keywords: ['layout', 'columns', 'column', String(columns)],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createLayoutBlock({ columns })),\r\n })),\r\n};\r\n","import { useBlock } from '../../react/useBlock.js';\nimport { useBlockClassName } from '../../react/EditorProvider.jsx';\n\n// tabIndex={-1}: not in the normal Tab order, but focusable via .focus() —\n// needed so setSelectedBlockId (EditorProvider) can actually move DOM focus\n// here when it selects this block, keeping the surface's own keydown\n// listener capturing the next Backspace/Delete even after whatever\n// previously had focus (e.g. an adjacent empty paragraph) has just been\n// removed from the DOM entirely.\nexport function DividerBlock({ id }) {\n const block = useBlock(id);\n const className = useBlockClassName('be-divider', block);\n return <hr className={className} data-block-id={id} contentEditable={false} tabIndex={-1} />;\n}\n","import { DividerBlock } from './DividerBlock.jsx';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { insertSiblingAfter, insertSiblingAfterAndFocus } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { updateRun } from '../../store/operations.js';\r\nimport { DividerIcon } from '../../react/icons.jsx';\r\n\r\nfunction createDividerBlock() {\r\n return function factory(parentId) {\r\n return { block: { id: genId(), type: 'divider', parentId, contentIds: [], props: {} }, runs: [] };\r\n };\r\n}\r\n\r\nfunction toHTML() {\r\n return '<hr />';\r\n}\r\n\r\nfunction toPlainText() {\r\n return '---';\r\n}\r\n\r\nfunction fromHTML(node) {\r\n if (node.tagName !== 'HR') return null;\r\n return { block: { id: genId(), type: 'divider', parentId: null, contentIds: [], props: {} }, runs: [] };\r\n}\r\n\r\nexport const dividerBlockType = {\r\n component: DividerBlock,\r\n isLeaf: true,\r\n defaultProps: {},\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: {\r\n label: 'Divider',\r\n icon: DividerIcon,\r\n keywords: ['divider', 'hr', 'separator', 'line'],\r\n run: (store, { blockId, runId, sliceStart, sliceEnd }) => {\r\n const run = store.getRun(runId);\r\n const value = run?.value ?? '';\r\n store.applyOperation(updateRun(runId, { value: value.slice(0, sliceStart) + value.slice(sliceEnd) }));\r\n\r\n // seed a paragraph right after so there's always somewhere to type\r\n // past the divider — it has no run of its own to focus into.\r\n const dividerId = insertSiblingAfter(store, blockId, createDividerBlock());\r\n insertSiblingAfterAndFocus(store, dividerId, createTextLeafBlock('paragraph'));\r\n return dividerId;\r\n },\r\n },\r\n};\r\n","import { useCallback, useMemo, useRef, useState } from 'react';\nimport { BlockChildren } from '../../react/BlockChildren.jsx';\nimport { useBlock } from '../../react/useBlock.js';\nimport { useEditorStore, useBlockClassName } from '../../react/EditorProvider.jsx';\nimport { useOutsideClickAndEscape } from '../../react/useOutsideClickAndEscape.js';\nimport { updateBlockProps } from '../../store/operations.js';\nimport { DEFAULT_CALLOUT_ICON, DEFAULT_CALLOUT_COLOR } from './createCalloutBlock.js';\n\nexport const CALLOUT_COLORS = [\n { value: 'gray', label: 'Gray' },\n { value: 'blue', label: 'Blue' },\n { value: 'green', label: 'Green' },\n { value: 'yellow', label: 'Yellow' },\n { value: 'orange', label: 'Orange' },\n { value: 'red', label: 'Red' },\n { value: 'purple', label: 'Purple' },\n { value: 'pink', label: 'Pink' },\n];\n\n/**\n * A plain container (contentIds hold child block ids, exactly like\n * layoutColumn/page) wrapped in a colored card with an editable icon — same\n * mechanism used for \"callout\": no bespoke text/run handling\n * of its own, so every child block (paragraph, list, another callout, ...)\n * gets full selection/copy/paste/format/undo support for free from the\n * shared container machinery, the same way layout columns already do.\n *\n * \"Title\" and \"description\" (see the CSS: `.be-callout-content > :first-\n * child` vs the rest) aren't a separate data shape — they're just the\n * first child block rendered bold vs. every child after it rendered\n * muted/smaller. That keeps the callout exactly as flexible as before (any\n * number of arbitrary child blocks, not a fixed two-field shape) while\n * still matching the title+description card look, since a callout's first\n * line reads as its heading in practice anyway.\n *\n * The icon is a plain text input rather than a dedicated emoji picker for\n * now (item 7 in the requested list) — swap this for that picker once it\n * exists; typing/pasting any emoji directly already works today.\n */\nexport function CalloutBlock({ id }) {\n const store = useEditorStore();\n const block = useBlock(id);\n const [editingIcon, setEditingIcon] = useState(false);\n const [isColorPickerOpen, setIsColorPickerOpen] = useState(false);\n const colorTriggerRef = useRef(null);\n const colorPickerRef = useRef(null);\n const colorOutsideRefs = useMemo(() => [colorTriggerRef, colorPickerRef], []);\n\n const closeColorPicker = useCallback(() => setIsColorPickerOpen(false), []);\n useOutsideClickAndEscape(colorOutsideRefs, isColorPickerOpen, closeColorPicker);\n\n const icon = block?.props?.icon ?? DEFAULT_CALLOUT_ICON;\n const color = block?.props?.color ?? DEFAULT_CALLOUT_COLOR;\n\n const commitIcon = useCallback(\n (event) => {\n const next = event.target.value.trim();\n if (next) store.applyOperation(updateBlockProps(id, { icon: next }));\n setEditingIcon(false);\n },\n [store, id],\n );\n\n const handleIconKeyDown = useCallback((event) => {\n if (event.key === 'Enter') event.currentTarget.blur();\n if (event.key === 'Escape') setEditingIcon(false);\n }, []);\n\n const handleColorChange = useCallback(\n (next) => {\n store.applyOperation(updateBlockProps(id, { color: next }));\n setIsColorPickerOpen(false);\n },\n [store, id],\n );\n\n const className = useBlockClassName('be-callout', block);\n\n if (!block) return null;\n\n return (\n <div className={className} data-block-id={id} data-color={color}>\n <div className=\"be-callout-icon-wrap\">\n {editingIcon ? (\n <input\n type=\"text\"\n className=\"be-callout-icon-input\"\n defaultValue={icon}\n autoFocus\n onBlur={commitIcon}\n onKeyDown={handleIconKeyDown}\n aria-label=\"Callout icon (paste or type an emoji)\"\n />\n ) : (\n <button\n type=\"button\"\n className=\"be-callout-icon\"\n onClick={() => setEditingIcon(true)}\n aria-label=\"Change callout icon\"\n title=\"Change icon\"\n >\n {icon}\n </button>\n )}\n </div>\n\n <div className=\"be-callout-content\">\n <BlockChildren parentId={id} />\n </div>\n\n <div className=\"be-callout-color-wrap\" contentEditable={false}>\n <button\n ref={colorTriggerRef}\n type=\"button\"\n className=\"be-callout-color-trigger\"\n aria-label=\"Callout color\"\n aria-haspopup=\"true\"\n aria-expanded={isColorPickerOpen}\n title=\"Callout color\"\n onClick={() => setIsColorPickerOpen((open) => !open)}\n >\n <span className={`be-callout-color-dot be-callout-color-dot-${color}`} />\n </button>\n {isColorPickerOpen && (\n <div ref={colorPickerRef} className=\"be-callout-color-picker\" role=\"menu\" aria-label=\"Callout color\">\n {CALLOUT_COLORS.map((c) => (\n <button\n key={c.value}\n type=\"button\"\n role=\"menuitem\"\n className={`be-callout-color-option be-callout-color-option-${c.value}${\n c.value === color ? ' be-callout-color-option-active' : ''\n }`}\n title={c.label}\n aria-label={c.label}\n onClick={() => handleColorChange(c.value)}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import { CalloutBlock } from './CalloutBlock.jsx';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createCalloutBlock, DEFAULT_CALLOUT_ICON } from './createCalloutBlock.js';\r\nimport { CalloutIcon } from '../../react/icons.jsx';\r\n\r\nfunction childrenToHTML(block, ctx) {\r\n return block.contentIds\r\n .map((childId) => {\r\n const child = ctx.store.getBlock(childId);\r\n return ctx.registry.get(child.type).toHTML(child, ctx);\r\n })\r\n .join('');\r\n}\r\n\r\nfunction toHTML(block, ctx) {\r\n const icon = block.props?.icon ?? DEFAULT_CALLOUT_ICON;\r\n return `<div class=\"callout\" data-icon=\"${icon}\"><div class=\"callout-icon\">${icon}</div><div class=\"callout-content\">${childrenToHTML(block, ctx)}</div></div>`;\r\n}\r\n\r\nfunction toPlainText(block, ctx) {\r\n const icon = block.props?.icon ?? DEFAULT_CALLOUT_ICON;\r\n const inner = block.contentIds\r\n .map((childId) => {\r\n const child = ctx.store.getBlock(childId);\r\n return ctx.registry.get(child.type).toPlainText(child, ctx);\r\n })\r\n .join('\\n');\r\n return `${icon} ${inner}`;\r\n}\r\n\r\nexport const calloutBlockType = {\r\n component: CalloutBlock,\r\n isLeaf: false,\r\n defaultProps: { icon: DEFAULT_CALLOUT_ICON },\r\n toHTML,\r\n toPlainText,\r\n // No fromHTML: same precedent as layoutColumn — there's no standard\r\n // external HTML shape for a \"callout\" box, so plain-HTML paste doesn't\r\n // need to reconstruct one. Same-editor copy/paste is already lossless\r\n // via the generic block-subtree JSON clipboard path\r\n // (captureSubtree in clipboard/serialize.js), which walks\r\n // contentIds generically and needs no per-type awareness at all.\r\n slashCommand: {\r\n label: 'Callout',\r\n icon: CalloutIcon,\r\n keywords: ['callout', 'aside', 'note', 'info', 'tip', 'warning'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createCalloutBlock()),\r\n },\r\n};\r\n","import { useCallback } from 'react';\r\nimport { EditableBlockContent } from '../../react/EditableBlockContent.jsx';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useSelectedBlock, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { insertSiblingSplitAtCaretAndFocus } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { mergeWithPreviousOrDelete } from '../shared/mergeCommands.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { focusAfterMerge } from '../shared/focusAfterMerge.js';\r\nimport { focusAdjacentBlock } from '../shared/navigationCommands.js';\r\nimport { resolveBlockDir } from '../shared/resolveBlockDir.js';\r\n\r\n/**\r\n * A leaf block, exactly like ParagraphBlock/HeadingBlock (contentIds are\r\n * its own run ids, not child blocks) — the only difference is presentation\r\n * (a <blockquote> tag with a left border). Enter exits the quote into a\r\n * plain paragraph sibling, matching heading's own convention — a quote\r\n * is a single formatted block,\r\n * not a container you keep typing new lines into via Enter.\r\n */\r\nexport function BlockquoteBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n const { setSelectedBlockId } = useSelectedBlock();\r\n\r\n const handleEnter = useCallback(() => {\r\n insertSiblingSplitAtCaretAndFocus(store, id, block?.contentIds ?? [], createTextLeafBlock('paragraph'));\r\n }, [store, id, block]);\r\n\r\n const handleBackspaceAtStart = useCallback(() => {\r\n const focusBlockId = mergeWithPreviousOrDelete(store, id);\r\n focusAfterMerge(store, focusBlockId, id, setSelectedBlockId);\r\n }, [store, id, setSelectedBlockId]);\r\n\r\n const handleArrowUp = useCallback(() => focusAdjacentBlock(store, id, 'up'), [store, id]);\r\n const handleArrowDown = useCallback(() => focusAdjacentBlock(store, id, 'down'), [store, id]);\r\n\r\n const className = useBlockClassName('be-blockquote', block);\r\n\r\n if (!block) return null;\r\n const isEmpty = isRunsEmpty(store, block.contentIds);\r\n const dir = resolveBlockDir(store, block);\r\n\r\n return (\r\n <blockquote\r\n className={className}\r\n data-block-id={id}\r\n data-empty={isEmpty ? '' : undefined}\r\n data-placeholder=\"Empty quote\"\r\n dir={dir}\r\n >\r\n <EditableBlockContent\r\n blockId={id}\r\n runIds={block.contentIds}\r\n dir={dir}\r\n onEnter={handleEnter}\r\n onBackspaceAtStart={handleBackspaceAtStart}\r\n onArrowUp={handleArrowUp}\r\n onArrowDown={handleArrowDown}\r\n />\r\n </blockquote>\r\n );\r\n}\r\n","import { BlockquoteBlock } from './BlockquoteBlock.jsx';\r\nimport { runToHTML, runToPlainText } from '../../inline/marks.js';\r\nimport { domInlineToRuns } from '../../inline/runOps.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { QuoteIcon } from '../../react/icons.jsx';\r\n\r\nfunction toHTML(block, ctx) {\r\n const runs = block.contentIds.map((runId) => ctx.store.getRun(runId));\r\n return `<p>${runs.map((r) => runToHTML(r, ctx)).join('')}</p>`;\r\n}\r\n\r\nfunction toPlainText(block, ctx) {\r\n return block.contentIds.map((runId) => runToPlainText(ctx.store.getRun(runId), ctx)).join('');\r\n}\r\n\r\nfunction fromHTML(node, ctx) {\r\n if (node.tagName !== 'BLOCKQUOTE') return null;\r\n const runs = domInlineToRuns(node, ctx);\r\n const block = { id: genId(), type: 'blockquote', parentId: null, contentIds: runs.map((r) => r.id), props: {} };\r\n return { block, runs };\r\n}\r\n\r\nexport const blockquoteBlockType = {\r\n component: BlockquoteBlock,\r\n isLeaf: true,\r\n defaultProps: {},\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: {\r\n label: 'Quote',\r\n icon: QuoteIcon,\r\n keywords: ['quote', 'blockquote', 'citation'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createTextLeafBlock('blockquote')),\r\n },\r\n};\r\n","import { useCallback } from 'react';\r\nimport { EditableBlockContent } from '../../react/EditableBlockContent.jsx';\r\nimport { Select } from '../../react/Select.jsx';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { mergeWithPreviousOrDelete } from '../shared/mergeCommands.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { focusRunEnd, focusRunAtOffset } from '../../react/focusRun.js';\r\nimport { resolveCollapsedCaret } from '../../react/selectionResolve.js';\r\nimport { updateRun, updateBlockProps } from '../../store/operations.js';\r\nimport { focusAdjacentBlock } from '../shared/navigationCommands.js';\r\nimport { deleteBlockAndFocusSibling } from '../shared/blockActions.js';\r\nimport { TrashIcon } from '../../react/icons.jsx';\r\n\r\nexport const LANGUAGES = ['plaintext', 'javascript', 'python', 'html', 'css', 'json', 'bash', 'sql'];\r\nconst LANGUAGE_OPTIONS = LANGUAGES.map((lang) => ({ value: lang, label: lang }));\r\n\r\n/**\r\n * Inserts literal text at the live caret within `blockId`'s own run,\r\n * splicing directly into that run's value — used for Enter (a real \"\\n\",\r\n * not a block split: a code block is multi-line *within one block*, like a\r\n * <textarea>) and Tab (two literal spaces, since\r\n * Tab inside code should never trigger indent-list/next-cell navigation).\r\n * Deliberately simple (single-run splice, no split-into-marks handling)\r\n * because code content is plain text — no rich inline formatting is\r\n * offered for it in this UI.\r\n */\r\nfunction insertLiteralTextAtCaret(store, blockId, text) {\r\n const caret = resolveCollapsedCaret();\r\n if (!caret || caret.blockId !== blockId) return;\r\n const run = store.getRun(caret.runId);\r\n if (!run || run.type !== 'text') return;\r\n const value = run.value ?? '';\r\n const newValue = value.slice(0, caret.offset) + text + value.slice(caret.offset);\r\n store.applyOperation(updateRun(run.id, { value: newValue }));\r\n focusRunAtOffset(run.id, caret.offset + text.length);\r\n}\r\n\r\n/**\r\n * A leaf block (own runs, same mechanism as paragraph/heading) rendered\r\n * inside a <pre><code> so embedded \"\\n\" characters actually break lines\r\n * (white-space: pre-wrap, see the CSS) — the only block type where Enter\r\n * doesn't split into a new sibling. Backspace-at-start still goes through\r\n * the ordinary shared mergeWithPreviousOrDelete: code is deliberately NOT\r\n * in MERGEABLE_TEXT_TYPES (concatenating code text into a plain paragraph,\r\n * or vice versa, has no sensible meaning — same exclusion as table/\r\n * listItem), so a *non-empty* code block simply won't merge into its\r\n * previous sibling; an *empty* one is still removed outright, landing\r\n * focus on whatever came before it.\r\n *\r\n * No syntax highlighting (tokenizing/coloring code) is performed — that\r\n * needs a highlighter library, which the zero-runtime-dependency\r\n * constraint on this package rules out. `props.language` is kept as plain\r\n * metadata (round-trips through copy/paste and serialization) for a host\r\n * app to feed into its own highlighter if it has one.\r\n */\r\nexport function CodeBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n\r\n const handleEnter = useCallback(() => insertLiteralTextAtCaret(store, id, '\\n'), [store, id]);\r\n const handleTab = useCallback(() => insertLiteralTextAtCaret(store, id, ' '), [store, id]);\r\n\r\n const handleBackspaceAtStart = useCallback(() => {\r\n const focusBlockId = mergeWithPreviousOrDelete(store, id);\r\n if (!focusBlockId || focusBlockId === id) return;\r\n const focusBlock = store.getBlock(focusBlockId);\r\n const lastRunId = focusBlock?.contentIds?.[focusBlock.contentIds.length - 1];\r\n if (lastRunId) focusRunEnd(lastRunId);\r\n }, [store, id]);\r\n\r\n const handleArrowUp = useCallback(() => focusAdjacentBlock(store, id, 'up'), [store, id]);\r\n const handleArrowDown = useCallback(() => focusAdjacentBlock(store, id, 'down'), [store, id]);\r\n\r\n const handleLanguageChange = useCallback(\r\n (language) => store.applyOperation(updateBlockProps(id, { language })),\r\n [store, id],\r\n );\r\n\r\n const handleDelete = useCallback(() => deleteBlockAndFocusSibling(store, id), [store, id]);\r\n\r\n const className = useBlockClassName('be-code-block', block);\r\n\r\n if (!block) return null;\r\n const language = block.props?.language ?? 'plaintext';\r\n const isEmpty = isRunsEmpty(store, block.contentIds);\r\n\r\n return (\r\n <div className={className} data-block-id={id}>\r\n <div className=\"be-code-block-header\" contentEditable={false}>\r\n <Select\r\n className=\"be-code-block-language\"\r\n value={language}\r\n options={LANGUAGE_OPTIONS}\r\n onChange={handleLanguageChange}\r\n ariaLabel=\"Code language\"\r\n />\r\n <button type=\"button\" className=\"be-code-block-delete\" onClick={handleDelete} aria-label=\"Delete code block\" title=\"Delete code block\">\r\n <TrashIcon size={14} />\r\n </button>\r\n </div>\r\n {/*\r\n Deliberately always dir=\"ltr\", never resolveBlockDir — code syntax\r\n (brackets, operators, punctuation) is structurally LTR regardless of\r\n what language a comment/string literal happens to be written in;\r\n letting it inherit an RTL document default would scramble the\r\n visual order of the code itself, not just the prose inside it. Every\r\n real code editor (VS Code included) forces LTR for code for the\r\n same reason.\r\n */}\r\n <pre className=\"be-code-block-pre\" dir=\"ltr\">\r\n <code data-empty={isEmpty ? '' : undefined} data-placeholder=\"Empty code block\">\r\n <EditableBlockContent\r\n blockId={id}\r\n runIds={block.contentIds}\r\n dir=\"ltr\"\r\n onEnter={handleEnter}\r\n onTab={handleTab}\r\n onBackspaceAtStart={handleBackspaceAtStart}\r\n onArrowUp={handleArrowUp}\r\n onArrowDown={handleArrowDown}\r\n />\r\n </code>\r\n </pre>\r\n </div>\r\n );\r\n}\r\n","import { CodeBlock } from './CodeBlock.jsx';\r\nimport { runToHTML, runToPlainText, escapeHTML } from '../../inline/marks.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { CodeIcon } from '../../react/icons.jsx';\r\n\r\nfunction toHTML(block, ctx) {\r\n const runs = block.contentIds.map((runId) => ctx.store.getRun(runId));\r\n const language = block.props?.language;\r\n const langAttr = language && language !== 'plaintext' ? ` data-language=\"${escapeHTML(language)}\"` : '';\r\n return `<pre><code${langAttr}>${runs.map((r) => runToHTML(r, ctx)).join('')}</code></pre>`;\r\n}\r\n\r\nfunction toPlainText(block, ctx) {\r\n return block.contentIds.map((runId) => runToPlainText(ctx.store.getRun(runId), ctx)).join('');\r\n}\r\n\r\nfunction fromHTML(node, ctx) {\r\n if (node.tagName !== 'PRE') return null;\r\n const codeEl = node.querySelector('code') ?? node;\r\n const language = codeEl.getAttribute?.('data-language');\r\n const runId = genId();\r\n const block = {\r\n id: genId(),\r\n type: 'code',\r\n parentId: null,\r\n contentIds: [runId],\r\n props: language ? { language } : {},\r\n };\r\n return { block, runs: [{ id: runId, type: 'text', value: codeEl.textContent ?? '', marks: {} }] };\r\n}\r\n\r\nexport const codeBlockType = {\r\n component: CodeBlock,\r\n isLeaf: true,\r\n defaultProps: { language: 'plaintext' },\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: {\r\n label: 'Code',\r\n icon: CodeIcon,\r\n keywords: ['code', 'codeblock', 'snippet', 'pre'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createTextLeafBlock('code')),\r\n },\r\n};\r\n","import { removeBlock, insertBlock } from '../../store/operations.js';\r\nimport { isContentlessBlock } from '../shared/contentless.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\n\r\nexport function isBlankTitle(store, titleRunIds) {\r\n return titleRunIds.length === 0 || (titleRunIds.length === 1 && (store.getRun(titleRunIds[0])?.value ?? '') === '');\r\n}\r\n\r\n/**\r\n * True when this toggle heading's body has no real content at all — either\r\n * no children (shouldn't normally happen; createToggleHeadingBlock always\r\n * seeds one) or just its single seeded blank paragraph, still untouched.\r\n * Anything more (a second child, or the sole child holding real text/other\r\n * content) counts as \"has content\".\r\n */\r\nfunction isBodyEmpty(store, block) {\r\n const childIds = block.contentIds ?? [];\r\n if (childIds.length === 0) return true;\r\n if (childIds.length > 1) return false;\r\n const onlyChild = store.getBlock(childIds[0]);\r\n return Boolean(onlyChild) && onlyChild.type === 'paragraph' && isRunsEmpty(store, onlyChild.contentIds);\r\n}\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n/**\r\n * Backspace-at-start for a toggle heading's own title. A toggle heading is\r\n * only ever removable when it's *entirely* blank — title empty AND its\r\n * body is empty too (see isBodyEmpty) — since createToggleHeadingBlock\r\n * always seeds one blank paragraph child, checking for literally zero\r\n * children (the previous version of this check) could never be true in\r\n * practice, making an empty toggle heading permanently undeletable via\r\n * Backspace. isBodyEmpty treats \"just the untouched seeded paragraph\" the\r\n * same as \"no children\" to fix that.\r\n *\r\n * No merge-into-previous-sibling behavior at all (unlike plain paragraph/\r\n * heading, which concatenate text into whatever's before them): a toggle\r\n * heading isn't in MERGEABLE_TEXT_TYPES, since \"concatenate this section's\r\n * title into a plain paragraph\" has no well-defined meaning once it may be\r\n * carrying nested children — matches the same non-mergeable precedent as\r\n * table/listItem/callout.\r\n */\r\nexport function mergeToggleHeadingOrNoop(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n if (!block) return null;\r\n const parent = store.getBlock(block.parentId);\r\n const index = parent.contentIds.indexOf(blockId);\r\n const titleRunIds = block.props.titleRunIds ?? [];\r\n const empty = isBlankTitle(store, titleRunIds) && isBodyEmpty(store, block);\r\n\r\n if (index <= 0) {\r\n if (!empty) return null; // real content somewhere, nothing before it: no-op, as every other editor does\r\n\r\n if (parent.contentIds.length > 1) {\r\n applyOps(store, [removeBlock(blockId)]);\r\n return { focusBlockId: store.getBlock(parent.id).contentIds[0], needsRefocus: true };\r\n }\r\n\r\n // sole block in its container: replace with a blank paragraph so\r\n // there's still somewhere to type, same \"never leave nothing to click\r\n // into\" fallback as mergeWithPreviousOrDelete/ensureRootNonEmpty.\r\n const { block: fallbackBlock, runs } = createTextLeafBlock('paragraph')(parent.id);\r\n applyOps(store, [\r\n insertBlock(fallbackBlock, parent.id, index, { blocks: [fallbackBlock], runs }),\r\n removeBlock(blockId),\r\n ]);\r\n return { focusBlockId: fallbackBlock.id, needsRefocus: true };\r\n }\r\n\r\n const prevId = parent.contentIds[index - 1];\r\n const prev = store.getBlock(prevId);\r\n\r\n // An entirely-empty CURRENT toggle heading goes first, even next to a\r\n // non-editable previous sibling — see the matching comment in\r\n // shared/mergeCommands.js for why this ordering matters.\r\n if (empty) {\r\n applyOps(store, [removeBlock(blockId)]);\r\n return { focusBlockId: prevId, needsRefocus: true };\r\n }\r\n\r\n if (isContentlessBlock(store, prev)) {\r\n applyOps(store, [removeBlock(prevId)]);\r\n return { focusBlockId: blockId, needsRefocus: false };\r\n }\r\n\r\n return null;\r\n}\r\n","import { useCallback } from 'react';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { EditableBlockContent } from '../../react/EditableBlockContent.jsx';\r\nimport { BlockChildren } from '../../react/BlockChildren.jsx';\r\nimport { useEditorStore, useSelectedBlock, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { insertSiblingSplitAtCaretAndFocus, insertFirstChildSplitAtCaretAndFocus } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { mergeToggleHeadingOrNoop } from './mergeCommands.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { focusAfterMerge } from '../shared/focusAfterMerge.js';\r\nimport { updateBlockProps, insertBlock } from '../../store/operations.js';\r\nimport { focusAdjacentBlock } from '../shared/navigationCommands.js';\r\nimport { resolveBlockDir } from '../shared/resolveBlockDir.js';\r\nimport { focusRunEnd } from '../../react/focusRun.js';\r\nimport { ChevronRightIcon, ChevronDownIcon } from '../../react/icons.jsx';\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n/**\r\n * A heading whose section can be collapsed — same title+children split as\r\n * ListItemBlock (own text in props.titleRunIds, nested content in\r\n * contentIds), so collapsing is a purely local re-render (this component\r\n * conditionally skips <BlockChildren>) rather than needing any sibling-\r\n * range computation. Deliberately a distinct block type from `heading`\r\n * (not a retrofit) to avoid touching that type's existing leaf shape\r\n * (contentIds = its own runs) — heading is used throughout the merge/\r\n * split/serialize code as a plain leaf, and changing that shape would\r\n * ripple into all of it.\r\n */\r\nexport function ToggleHeadingBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n const { setSelectedBlockId } = useSelectedBlock();\r\n\r\n const handleEnter = useCallback(() => {\r\n const titleRunIds = block?.props?.titleRunIds ?? [];\r\n const hasNestedChildren = (block?.contentIds?.length ?? 0) > 0;\r\n const factory = createTextLeafBlock('paragraph');\r\n if (hasNestedChildren) {\r\n insertFirstChildSplitAtCaretAndFocus(store, id, titleRunIds, factory);\r\n } else {\r\n insertSiblingSplitAtCaretAndFocus(store, id, titleRunIds, factory);\r\n }\r\n }, [store, id, block]);\r\n\r\n const handleBackspaceAtStart = useCallback(() => {\r\n const result = mergeToggleHeadingOrNoop(store, id);\r\n if (!result || !result.needsRefocus) return;\r\n focusAfterMerge(store, result.focusBlockId, id, setSelectedBlockId);\r\n }, [store, id, setSelectedBlockId]);\r\n\r\n const handleArrowUp = useCallback(() => focusAdjacentBlock(store, id, 'up'), [store, id]);\r\n const handleArrowDown = useCallback(() => focusAdjacentBlock(store, id, 'down'), [store, id]);\r\n\r\n const toggleCollapsed = useCallback(() => {\r\n const hasChildren = (block?.contentIds?.length ?? 0) > 0;\r\n if (!hasChildren) {\r\n // A childless toggle heading has nothing to expand/collapse yet —\r\n // this was previously a disabled dead end. Clicking now bootstraps\r\n // the first (empty) child and expands, same fix as the toggle list\r\n // item's own marker.\r\n const { block: childBlock, runs } = createTextLeafBlock('paragraph')(id);\r\n applyOps(store, [\r\n insertBlock(childBlock, id, 0, { blocks: [childBlock], runs }),\r\n updateBlockProps(id, { collapsed: false }),\r\n ]);\r\n focusRunEnd(childBlock.contentIds[0]);\r\n return;\r\n }\r\n store.applyOperation(updateBlockProps(id, { collapsed: !block?.props?.collapsed }));\r\n }, [store, id, block?.contentIds, block?.props?.collapsed]);\r\n\r\n const className = useBlockClassName('be-toggle-heading', block);\r\n\r\n if (!block) return null;\r\n const { level = 2, collapsed, titleRunIds = [] } = block.props;\r\n const hasNestedChildren = block.contentIds.length > 0;\r\n const Tag = `h${level}`;\r\n const dir = resolveBlockDir(store, block);\r\n\r\n return (\r\n <div className={className} data-block-id={id} dir={dir}>\r\n <div className=\"be-toggle-heading-row\">\r\n <button\r\n type=\"button\"\r\n className=\"be-toggle-heading-marker\"\r\n onClick={toggleCollapsed}\r\n aria-expanded={!collapsed}\r\n aria-label={!hasNestedChildren ? 'Add content to section' : collapsed ? 'Expand section' : 'Collapse section'}\r\n >\r\n {collapsed ? <ChevronRightIcon /> : <ChevronDownIcon />}\r\n </button>\r\n <Tag\r\n className={`be-heading be-heading-${level} be-toggle-heading-title`}\r\n data-empty={isRunsEmpty(store, titleRunIds) ? '' : undefined}\r\n data-placeholder={`Toggle heading ${level}`}\r\n >\r\n <EditableBlockContent\r\n blockId={id}\r\n runIds={titleRunIds}\r\n dir={dir}\r\n onEnter={handleEnter}\r\n onBackspaceAtStart={handleBackspaceAtStart}\r\n onArrowUp={handleArrowUp}\r\n onArrowDown={handleArrowDown}\r\n />\r\n </Tag>\r\n </div>\r\n {!collapsed && (\r\n <div className=\"be-toggle-heading-children\">\r\n <BlockChildren parentId={id} />\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { genId } from '../../utils/idGen.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\n\r\n/**\r\n * factory(parentId, initialRuns?) -> {block, runs, subtreeBlocks} for a\r\n * toggle heading — its own text lives in props.titleRunIds (same\r\n * title+children split as listItem), while contentIds holds the section's\r\n * nested content, rendered only while props.collapsed is false. Seeded\r\n * with one empty paragraph child (same convention as callout/layout's\r\n * columns) so there's always at least one place to type into right away —\r\n * critical here specifically, since Enter on the title only ever inserts a\r\n * *first child* when the toggle heading already has children (see\r\n * ToggleHeadingBlock's handleEnter); without a seeded child, there'd be no\r\n * way to get content under a brand-new toggle heading at all.\r\n */\r\nexport function createToggleHeadingBlock({ level = 2, collapsed = false } = {}) {\r\n return function factory(parentId, initialRuns) {\r\n const blockId = genId();\r\n const runs = initialRuns?.length ? initialRuns : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n const { block: childBlock, runs: childRuns } = createTextLeafBlock('paragraph')(blockId);\r\n return {\r\n block: {\r\n id: blockId,\r\n type: 'toggleHeading',\r\n parentId,\r\n contentIds: [childBlock.id],\r\n props: { level, collapsed, titleRunIds: runs.map((r) => r.id) },\r\n },\r\n runs: [...runs, ...childRuns],\r\n subtreeBlocks: [childBlock],\r\n };\r\n };\r\n}\r\n","import { ToggleHeadingBlock } from './ToggleHeadingBlock.jsx';\r\nimport { runToHTML, runToPlainText } from '../../inline/marks.js';\r\nimport { domInlineToRuns } from '../../inline/runOps.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createToggleHeadingBlock } from './createToggleHeadingBlock.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { ChevronRightIcon } from '../../react/icons.jsx';\r\n\r\n/**\r\n * <details>/<summary> is a genuine semantic match for a toggle heading —\r\n * `open` reflects the expanded state natively, so this round-trips through\r\n * any HTML consumer that understands plain HTML5 disclosure widgets, not\r\n * just this editor.\r\n */\r\nfunction toHTML(block, ctx) {\r\n const { titleRunIds = [], level = 2, collapsed } = block.props;\r\n const titleHTML = titleRunIds.map((runId) => runToHTML(ctx.store.getRun(runId), ctx)).join('');\r\n const childrenHTML = block.contentIds\r\n .map((childId) => {\r\n const child = ctx.store.getBlock(childId);\r\n return ctx.registry.get(child.type).toHTML(child, ctx);\r\n })\r\n .join('');\r\n return `<details${collapsed ? '' : ' open'}><summary><h${level}>${titleHTML}</h${level}></summary>${childrenHTML}</details>`;\r\n}\r\n\r\nfunction toPlainText(block, ctx) {\r\n const { titleRunIds = [] } = block.props;\r\n const title = titleRunIds.map((runId) => runToPlainText(ctx.store.getRun(runId), ctx)).join('');\r\n const children = block.contentIds\r\n .map((childId) => {\r\n const child = ctx.store.getBlock(childId);\r\n return ctx.registry.get(child.type).toPlainText(child, ctx);\r\n })\r\n .join('\\n');\r\n return children ? `${title}\\n${children}` : title;\r\n}\r\n\r\n/** Only reconstructs top-level <p> children on paste (matches blockquote's fromHTML scope) — deeper nested block types fall back to a single blank paragraph. */\r\nfunction fromHTML(node, ctx) {\r\n if (node.tagName !== 'DETAILS') return null;\r\n const summary = [...node.children].find((c) => c.tagName === 'SUMMARY');\r\n const headingEl = summary?.querySelector('h1,h2,h3,h4,h5,h6');\r\n const level = headingEl ? Math.min(6, Math.max(1, Number(headingEl.tagName[1]))) : 2;\r\n const titleRuns = headingEl ? domInlineToRuns(headingEl, ctx) : [{ id: genId(), type: 'text', value: '', marks: {} }];\r\n\r\n const blockId = genId();\r\n const childBlocks = [];\r\n const childRuns = [];\r\n const contentIds = [];\r\n for (const child of node.children) {\r\n if (child === summary || child.tagName !== 'P') continue;\r\n const runs = domInlineToRuns(child, ctx);\r\n const pBlock = { id: genId(), type: 'paragraph', parentId: blockId, contentIds: runs.map((r) => r.id), props: {} };\r\n childBlocks.push(pBlock);\r\n childRuns.push(...runs);\r\n contentIds.push(pBlock.id);\r\n }\r\n if (contentIds.length === 0) {\r\n const { block: fallback, runs } = createTextLeafBlock('paragraph')(blockId);\r\n childBlocks.push(fallback);\r\n childRuns.push(...runs);\r\n contentIds.push(fallback.id);\r\n }\r\n\r\n const block = {\r\n id: blockId,\r\n type: 'toggleHeading',\r\n parentId: null,\r\n contentIds,\r\n props: { level, collapsed: !node.hasAttribute('open'), titleRunIds: titleRuns.map((r) => r.id) },\r\n };\r\n return { block, runs: [...titleRuns, ...childRuns], subtreeBlocks: childBlocks };\r\n}\r\n\r\nexport const toggleHeadingBlockType = {\r\n component: ToggleHeadingBlock,\r\n isLeaf: false,\r\n defaultProps: { level: 2, collapsed: false, titleRunIds: [] },\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommands: [1, 2, 3].map((level) => ({\r\n label: `Toggle heading ${level}`,\r\n icon: ChevronRightIcon,\r\n // Deliberately does NOT include \"h1\"/\"h2\"/\"h3\" — those short forms\r\n // already belong exclusively to the plain heading commands (see\r\n // heading/index.js); duplicating them here would make \"/h3\" ambiguous\r\n // between \"Heading 3\" and \"Toggle heading 3\".\r\n keywords: ['toggle', 'heading', 'collapse', 'section'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createToggleHeadingBlock({ level })),\r\n })),\r\n};\r\n","import { useCallback, useEffect, useState } from 'react';\r\nimport { Modal } from '../../react/Modal.jsx';\r\nimport { updateBlockProps, setBlockRuns } from '../../store/operations.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { XIcon } from '../../react/icons.jsx';\r\n\r\nconst COLORS = [\r\n { label: 'Blue', value: '#2b6fd6' },\r\n { label: 'Green', value: '#2f9e44' },\r\n { label: 'Red', value: '#e03131' },\r\n { label: 'Purple', value: '#9c36b5' },\r\n { label: 'Gray', value: '#495057' },\r\n { label: 'Black', value: '#1a1a1a' },\r\n];\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n/**\r\n * One-stop editor for a button block: label text, link URL, pill color,\r\n * and an open-ended list of custom key/value attributes (rendered as\r\n * data-* attributes on the button's own DOM node — see ButtonBlock — so a\r\n * host app can hook its own CSS/JS onto a button by whatever attribute\r\n * name it likes, without this package needing to know what for).\r\n *\r\n * Renaming the label here replaces the block's runs with a single plain\r\n * text run (see the save handler) — the inline contentEditable label\r\n * (click directly into the button's text) is still there and still keeps\r\n * full rich-text/marks support; this is just a faster, consolidated way to\r\n * set everything about the button in one place, matching how every other\r\n * \"edit this block's settings\" affordance in this package works.\r\n */\r\nexport function ButtonEditModal({ isOpen, onClose, store, blockId }) {\r\n const [label, setLabel] = useState('');\r\n const [href, setHref] = useState('');\r\n const [color, setColor] = useState(COLORS[0].value);\r\n const [attrs, setAttrs] = useState([{ key: '', value: '' }]);\r\n\r\n useEffect(() => {\r\n if (!isOpen) return;\r\n const block = store.getBlock(blockId);\r\n if (!block) return;\r\n const text = block.contentIds.map((runId) => store.getRun(runId)?.value ?? '').join('');\r\n const existingAttrs = block.props?.customAttrs ?? [];\r\n setLabel(text);\r\n setHref(block.props?.href ?? '');\r\n setColor(block.props?.color ?? COLORS[0].value);\r\n setAttrs([...existingAttrs, { key: '', value: '' }]);\r\n }, [isOpen, blockId, store]);\r\n\r\n const updateAttrRow = useCallback((index, patch) => {\r\n setAttrs((rows) => {\r\n const next = rows.map((row, i) => (i === index ? { ...row, ...patch } : row));\r\n const last = next[next.length - 1];\r\n if (last.key.trim() || last.value.trim()) next.push({ key: '', value: '' }); // always keep one trailing blank row to add more\r\n return next;\r\n });\r\n }, []);\r\n\r\n const removeAttrRow = useCallback((index) => {\r\n setAttrs((rows) => rows.filter((_, i) => i !== index));\r\n }, []);\r\n\r\n const handleSave = useCallback(() => {\r\n const newRun = { id: genId(), type: 'text', value: label, marks: {} };\r\n const customAttrs = attrs.filter((row) => row.key.trim());\r\n\r\n applyOps(store, [\r\n setBlockRuns(blockId, [newRun]),\r\n updateBlockProps(blockId, { href: href.trim(), color, customAttrs }),\r\n ]);\r\n onClose();\r\n }, [store, blockId, label, href, color, attrs, onClose]);\r\n\r\n return (\r\n <Modal isOpen={isOpen} onClose={onClose} title=\"Edit button\">\r\n <label className=\"be-modal-field\">\r\n <span>Label</span>\r\n <input type=\"text\" value={label} onChange={(event) => setLabel(event.target.value)} placeholder=\"Button\" />\r\n </label>\r\n\r\n <label className=\"be-modal-field\">\r\n <span>Link URL</span>\r\n <input\r\n type=\"url\"\r\n value={href}\r\n onChange={(event) => setHref(event.target.value)}\r\n placeholder=\"https://example.com\"\r\n />\r\n </label>\r\n\r\n <div className=\"be-modal-field\">\r\n <span>Color</span>\r\n <div className=\"be-modal-color-row\">\r\n {COLORS.map((c) => (\r\n <button\r\n key={c.value}\r\n type=\"button\"\r\n className={`be-modal-color-swatch${color === c.value ? ' be-modal-color-swatch-active' : ''}`}\r\n style={{ backgroundColor: c.value }}\r\n title={c.label}\r\n aria-label={c.label}\r\n onClick={() => setColor(c.value)}\r\n />\r\n ))}\r\n </div>\r\n </div>\r\n\r\n <div className=\"be-modal-field\">\r\n <span>Custom attributes</span>\r\n {attrs.map((row, index) => (\r\n <div className=\"be-modal-attr-row\" key={index}>\r\n <input\r\n type=\"text\"\r\n placeholder=\"name\"\r\n value={row.key}\r\n onChange={(event) => updateAttrRow(index, { key: event.target.value })}\r\n />\r\n <input\r\n type=\"text\"\r\n placeholder=\"value\"\r\n value={row.value}\r\n onChange={(event) => updateAttrRow(index, { value: event.target.value })}\r\n />\r\n {(row.key || row.value) && (\r\n <button type=\"button\" className=\"be-modal-attr-remove\" onClick={() => removeAttrRow(index)} aria-label=\"Remove attribute\">\r\n <XIcon size={14} />\r\n </button>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n\r\n <div className=\"be-modal-actions\">\r\n <button type=\"button\" className=\"be-modal-cancel\" onClick={onClose}>\r\n Cancel\r\n </button>\r\n <button type=\"button\" className=\"be-modal-save\" onClick={handleSave}>\r\n Save\r\n </button>\r\n </div>\r\n </Modal>\r\n );\r\n}\r\n","import { useCallback, useState } from 'react';\r\nimport { EditableBlockContent } from '../../react/EditableBlockContent.jsx';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useSelectedBlock, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { insertSiblingSplitAtCaretAndFocus } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { mergeWithPreviousOrDelete } from '../shared/mergeCommands.js';\r\nimport { isRunsEmpty } from '../shared/blockEmpty.js';\r\nimport { focusAfterMerge } from '../shared/focusAfterMerge.js';\r\nimport { focusAdjacentBlock } from '../shared/navigationCommands.js';\r\nimport { resolveBlockDir } from '../shared/resolveBlockDir.js';\r\nimport { ButtonEditModal } from './ButtonEditModal.jsx';\r\n\r\nconst DEFAULT_COLOR = '#2b6fd6';\r\n\r\n/**\r\n * A leaf block (own runs, same mechanism as paragraph/heading) styled as a\r\n * clickable button, with `href`/`color`/`customAttrs` props. Editing the\r\n * label inline (click into the text, type, format, etc.) and *activating*\r\n * the button (following its link) are kept as two entirely separate\r\n * controls — a plain click inside the label only ever places the caret,\r\n * the same as any other block's text, and never navigates; the small\r\n * \"open ↗\" button is the only thing that does. The \"⚙\" button opens a\r\n * one-stop modal for label/link/color/custom-attributes (see\r\n * ButtonEditModal) as a faster consolidated alternative to editing the\r\n * label inline and there being nowhere else to set the rest.\r\n *\r\n * `customAttrs` (arbitrary name/value pairs from the modal) render as\r\n * data-* attributes directly on the pill element, not as raw injected\r\n * HTML/JS — a host app can hook its own CSS or event delegation onto\r\n * whatever attribute name it likes without this package needing to know\r\n * what for, without any injection risk.\r\n *\r\n * Enter creates a plain paragraph sibling (not another button), matching\r\n * heading's own convention — a run of several consecutive buttons from\r\n * repeated Enter isn't a sensible default.\r\n */\r\nexport function ButtonBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n const { setSelectedBlockId } = useSelectedBlock();\r\n const [isEditModalOpen, setIsEditModalOpen] = useState(false);\r\n\r\n const handleEnter = useCallback(() => {\r\n insertSiblingSplitAtCaretAndFocus(store, id, block?.contentIds ?? [], createTextLeafBlock('paragraph'));\r\n }, [store, id, block]);\r\n\r\n const handleBackspaceAtStart = useCallback(() => {\r\n const focusBlockId = mergeWithPreviousOrDelete(store, id);\r\n focusAfterMerge(store, focusBlockId, id, setSelectedBlockId);\r\n }, [store, id, setSelectedBlockId]);\r\n\r\n const handleArrowUp = useCallback(() => focusAdjacentBlock(store, id, 'up'), [store, id]);\r\n const handleArrowDown = useCallback(() => focusAdjacentBlock(store, id, 'down'), [store, id]);\r\n\r\n const openLink = useCallback(() => {\r\n const href = block?.props?.href;\r\n if (href) window.open(href, '_blank', 'noopener,noreferrer');\r\n }, [block?.props?.href]);\r\n\r\n const className = useBlockClassName('be-button-block', block);\r\n\r\n if (!block) return null;\r\n const href = block.props?.href ?? '';\r\n const color = block.props?.color ?? DEFAULT_COLOR;\r\n const customAttrs = block.props?.customAttrs ?? [];\r\n const isEmpty = isRunsEmpty(store, block.contentIds);\r\n\r\n const dataAttrs = {};\r\n for (const { key, value } of customAttrs) {\r\n if (key.trim()) dataAttrs[`data-${key.trim()}`] = value;\r\n }\r\n const dir = resolveBlockDir(store, block);\r\n\r\n return (\r\n <div className={className} data-block-id={id} dir={dir}>\r\n <div className=\"be-button-block-pill\" style={{ backgroundColor: color }} {...dataAttrs}>\r\n <span className=\"be-button-block-label\" data-empty={isEmpty ? '' : undefined} data-placeholder=\"Button\">\r\n <EditableBlockContent\r\n blockId={id}\r\n runIds={block.contentIds}\r\n dir={dir}\r\n onEnter={handleEnter}\r\n onBackspaceAtStart={handleBackspaceAtStart}\r\n onArrowUp={handleArrowUp}\r\n onArrowDown={handleArrowDown}\r\n />\r\n </span>\r\n <button\r\n type=\"button\"\r\n className=\"be-button-block-open\"\r\n onClick={openLink}\r\n disabled={!href}\r\n title={href || 'No link set'}\r\n aria-label=\"Open link\"\r\n >\r\n ↗\r\n </button>\r\n <button\r\n type=\"button\"\r\n className=\"be-button-block-settings\"\r\n onClick={() => setIsEditModalOpen(true)}\r\n aria-label=\"Edit button\"\r\n title=\"Edit label, link, color…\"\r\n >\r\n ⚙\r\n </button>\r\n </div>\r\n <ButtonEditModal isOpen={isEditModalOpen} onClose={() => setIsEditModalOpen(false)} store={store} blockId={id} />\r\n </div>\r\n );\r\n}\r\n","import { genId } from '../../utils/idGen.js';\r\n\r\n/**\r\n * factory(parentId, initialRuns?) -> {block, runs} for a button — a plain\r\n * leaf (contentIds are its own run ids, exactly like paragraph/heading),\r\n * plus a `href` prop. Not in MERGEABLE_TEXT_TYPES (see mergeCommands.js):\r\n * concatenating a button's label into a preceding paragraph would silently\r\n * drop its href, so it's excluded the same way table/listItem/callout are.\r\n */\r\nexport function createButtonBlock({ href = '', label = 'Button', color = '', customAttrs = [] } = {}) {\r\n return function factory(parentId, initialRuns) {\r\n const blockId = genId();\r\n const runs = initialRuns?.length ? initialRuns : [{ id: genId(), type: 'text', value: label, marks: {} }];\r\n return {\r\n block: { id: blockId, type: 'button', parentId, contentIds: runs.map((r) => r.id), props: { href, color, customAttrs } },\r\n runs,\r\n };\r\n };\r\n}\r\n","import { ButtonBlock } from './ButtonBlock.jsx';\r\nimport { runToHTML, runToPlainText, escapeAttr } from '../../inline/marks.js';\r\nimport { domInlineToRuns } from '../../inline/runOps.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { trimSlashQueryAndInsertAfter } from '../shared/blockCommands.js';\r\nimport { createButtonBlock } from './createButtonBlock.js';\r\nimport { ButtonIcon } from '../../react/icons.jsx';\r\n\r\n// Distinctive class (not just a bare <a>) so this never collides with an\r\n// ordinary link pasted from elsewhere — walkDomToBlocks's generic matcher\r\n// loop only claims an anchor as a button when this exact marker is present;\r\n// any other <a> falls through to the normal inline-link-within-a-paragraph\r\n// handling, which is what plain link pasting should do.\r\nconst MARKER_CLASS = 'be-button-block-link';\r\n\r\nfunction toHTML(block, ctx) {\r\n const runs = block.contentIds.map((runId) => ctx.store.getRun(runId));\r\n const href = block.props?.href ?? '';\r\n const color = block.props?.color;\r\n const style = color ? ` style=\"background-color:${escapeAttr(color)}\"` : '';\r\n const customAttrs = block.props?.customAttrs ?? [];\r\n const attrHTML = customAttrs\r\n .filter((a) => a.key?.trim())\r\n .map((a) => ` data-${escapeAttr(a.key.trim())}=\"${escapeAttr(a.value ?? '')}\"`)\r\n .join('');\r\n return `<a class=\"${MARKER_CLASS}\" href=\"${escapeAttr(href)}\"${style}${attrHTML}>${runs.map((r) => runToHTML(r, ctx)).join('')}</a>`;\r\n}\r\n\r\nfunction toPlainText(block, ctx) {\r\n return block.contentIds.map((runId) => runToPlainText(ctx.store.getRun(runId), ctx)).join('');\r\n}\r\n\r\nfunction fromHTML(node, ctx) {\r\n if (node.tagName !== 'A' || !node.classList.contains(MARKER_CLASS)) return null;\r\n const runs = domInlineToRuns(node, ctx);\r\n const customAttrs = [];\r\n for (const attr of node.attributes) {\r\n if (attr.name.startsWith('data-')) customAttrs.push({ key: attr.name.slice(5), value: attr.value });\r\n }\r\n const block = {\r\n id: genId(),\r\n type: 'button',\r\n parentId: null,\r\n contentIds: runs.map((r) => r.id),\r\n props: {\r\n href: node.getAttribute('href') ?? '',\r\n color: node.style?.backgroundColor || undefined,\r\n customAttrs,\r\n },\r\n };\r\n return { block, runs };\r\n}\r\n\r\nexport const buttonBlockType = {\r\n component: ButtonBlock,\r\n isLeaf: true,\r\n defaultProps: { href: '', color: '', customAttrs: [] },\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: {\r\n label: 'Button',\r\n icon: ButtonIcon,\r\n keywords: ['button', 'link', 'cta', 'action'],\r\n run: (store, ctx) => trimSlashQueryAndInsertAfter(store, ctx, createButtonBlock()),\r\n },\r\n};\r\n","import { useCallback, useRef, useState } from 'react';\r\nimport { useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore, useBlockClassName } from '../../react/EditorProvider.jsx';\r\nimport { updateBlockProps } from '../../store/operations.js';\r\nimport { Modal } from '../../react/Modal.jsx';\r\nimport { PaperclipIcon, AlignLeftIcon, AlignCenterIcon, AlignRightIcon } from '../../react/icons.jsx';\r\n\r\nfunction readFileAsDataURL(file) {\r\n return new Promise((resolve, reject) => {\r\n const reader = new FileReader();\r\n reader.onload = () => resolve(reader.result);\r\n reader.onerror = () => reject(reader.error);\r\n reader.readAsDataURL(file);\r\n });\r\n}\r\n\r\nconst KIND_LABEL = { image: 'image', video: 'video', audio: 'audio', file: 'file' };\r\nconst KIND_ACCEPT = { image: 'image/*', video: 'video/*', audio: 'audio/*', file: '*/*' };\r\nconst MIN_WIDTH = 20;\r\nconst MAX_WIDTH = 100;\r\nconst ALIGN_OPTIONS = [\r\n { value: 'left', Icon: AlignLeftIcon, label: 'Align left' },\r\n { value: 'center', Icon: AlignCenterIcon, label: 'Align center' },\r\n { value: 'right', Icon: AlignRightIcon, label: 'Align right' },\r\n];\r\n\r\nfunction clampWidth(pct) {\r\n return Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, Math.round(pct)));\r\n}\r\n\r\nfunction EmbedPreview({ kind, src, name, alt }) {\r\n // Deliberately never falls back to `name` (the uploaded file's raw\r\n // filename, e.g. \"IMG_2481.HEIC\", or a pasted URL string) — neither is\r\n // meaningful alt text, and silently presenting one as if it were a real\r\n // description is worse than an empty (but at least honest) alt.\r\n if (kind === 'image') return <img className=\"be-embed-image\" src={src} alt={alt || ''} />;\r\n if (kind === 'video') return <video className=\"be-embed-video\" src={src} controls />;\r\n if (kind === 'audio') return <audio className=\"be-embed-audio\" src={src} controls />;\r\n return (\r\n <a className=\"be-embed-file-link\" href={src} download={name || undefined} target=\"_blank\" rel=\"noopener noreferrer\">\r\n <PaperclipIcon size={14} /> {name || src}\r\n </a>\r\n );\r\n}\r\n\r\n/**\r\n * A pure \"widget\" block — no runs/text at all (contentIds always []), same\r\n * shape as DividerBlock — so it participates in cross-block select/copy/\r\n * cut/delete for free via the exact same generic mechanisms already\r\n * exercised by divider: it's \"contentless\" the same way, so backspacing\r\n * into it from a following block clears it as the nearest obstacle,\r\n * matching every other contentless block (see mergeWithPreviousOrDelete).\r\n *\r\n * There is no upload-to-a-server endpoint here — this is a zero-runtime-\r\n * dependency package with no backend component at all — so a local file\r\n * picked via the file input or dropped is read via FileReader straight\r\n * into a data: URL and stored directly in props.src. That keeps the\r\n * document fully self-contained (works offline, round-trips through copy/\r\n * paste and undo/redo like any other prop) at the cost of bloating the\r\n * document for large media; a host app that wants real upload-to-a-server\r\n * behavior should intercept this at a higher level (e.g. wrapping\r\n * createEmbedBlock/this component with its own), which is as far as a\r\n * dependency-free package can reasonably go on its own.\r\n *\r\n * `align` positions the whole widget within the line (a flex row on\r\n * `.be-embed-preview`, a common media alignment pattern). `width` is a\r\n * percentage, dragged via `.be-embed-resize-handle` — only image/video\r\n * kinds get the handle (an audio player or a file-download pill don't have\r\n * a meaningful \"shrink the visual\" concept the same way). The drag itself\r\n * only updates local state (`dragWidth`) for a live preview; the store is\r\n * only written once, on mouseup, so dragging doesn't spam undo history\r\n * with one step per pixel of mouse movement.\r\n */\r\nexport function EmbedBlock({ id }) {\r\n const store = useEditorStore();\r\n const block = useBlock(id);\r\n const [urlInput, setUrlInput] = useState('');\r\n const [isDragOver, setIsDragOver] = useState(false);\r\n const [dragWidth, setDragWidth] = useState(null);\r\n const [isAltTextOpen, setIsAltTextOpen] = useState(false);\r\n const [altDraft, setAltDraft] = useState('');\r\n const previewRef = useRef(null);\r\n const frameRef = useRef(null);\r\n\r\n const setMedia = useCallback((patch) => store.applyOperation(updateBlockProps(id, patch)), [store, id]);\r\n\r\n const openAltText = useCallback(() => {\r\n setAltDraft(block?.props?.alt ?? '');\r\n setIsAltTextOpen(true);\r\n }, [block?.props?.alt]);\r\n const closeAltText = useCallback(() => setIsAltTextOpen(false), []);\r\n const saveAltText = useCallback(\r\n (event) => {\r\n event.preventDefault();\r\n setMedia({ alt: altDraft.trim() });\r\n setIsAltTextOpen(false);\r\n },\r\n [altDraft, setMedia],\r\n );\r\n\r\n const handleFileChange = useCallback(\r\n async (event) => {\r\n const file = event.target.files?.[0];\r\n if (!file) return;\r\n const src = await readFileAsDataURL(file);\r\n setMedia({ src, name: file.name, mimeType: file.type });\r\n },\r\n [setMedia],\r\n );\r\n\r\n const handleDrop = useCallback(\r\n async (event) => {\r\n event.preventDefault();\r\n setIsDragOver(false);\r\n const file = event.dataTransfer.files?.[0];\r\n if (!file) return;\r\n const src = await readFileAsDataURL(file);\r\n setMedia({ src, name: file.name, mimeType: file.type });\r\n },\r\n [setMedia],\r\n );\r\n\r\n const handleDragOver = useCallback((event) => {\r\n event.preventDefault();\r\n setIsDragOver(true);\r\n }, []);\r\n\r\n const handleDragLeave = useCallback(() => setIsDragOver(false), []);\r\n\r\n const commitUrl = useCallback(() => {\r\n const trimmed = urlInput.trim();\r\n if (!trimmed) return;\r\n setMedia({ src: trimmed, name: trimmed });\r\n setUrlInput('');\r\n }, [urlInput, setMedia]);\r\n\r\n const clearMedia = useCallback(() => setMedia({ src: '', name: '', mimeType: '' }), [setMedia]);\r\n\r\n const handleResizeStart = useCallback(\r\n (event) => {\r\n event.preventDefault();\r\n const containerEl = previewRef.current;\r\n const frameEl = frameRef.current;\r\n if (!containerEl || !frameEl) return;\r\n const containerWidth = containerEl.getBoundingClientRect().width;\r\n const startWidth = frameEl.getBoundingClientRect().width;\r\n const startX = event.clientX;\r\n\r\n const computePct = (moveEvent) => clampWidth(((startWidth + (moveEvent.clientX - startX)) / containerWidth) * 100);\r\n\r\n const handleMouseMove = (moveEvent) => setDragWidth(computePct(moveEvent));\r\n const handleMouseUp = (upEvent) => {\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n document.removeEventListener('mouseup', handleMouseUp);\r\n setMedia({ width: computePct(upEvent) });\r\n setDragWidth(null);\r\n };\r\n document.addEventListener('mousemove', handleMouseMove);\r\n document.addEventListener('mouseup', handleMouseUp);\r\n },\r\n [setMedia],\r\n );\r\n\r\n const className = useBlockClassName('be-embed', block);\r\n\r\n if (!block) return null;\r\n const { kind = 'file', src, name, alt = '', align = 'left', width = 100 } = block.props;\r\n const canResize = kind === 'image' || kind === 'video';\r\n const effectiveWidth = dragWidth ?? width;\r\n\r\n return (\r\n // tabIndex={-1}: focusable via .focus() (see setSelectedBlockId in\r\n // EditorProvider.jsx) without joining the normal Tab order — keeps the\r\n // surface's keydown listener capturing subsequent Backspace/Delete\r\n // presses once this block becomes selected, even when whatever\r\n // previously had focus was just removed from the DOM entirely.\r\n <div className={className} data-block-id={id} data-kind={kind} contentEditable={false} tabIndex={-1}>\r\n {src ? (\r\n <div ref={previewRef} className={`be-embed-preview be-embed-align-${align}`}>\r\n <div\r\n ref={frameRef}\r\n className=\"be-embed-frame\"\r\n style={canResize ? { width: `${effectiveWidth}%` } : undefined}\r\n >\r\n <div className=\"be-embed-toolbar\" contentEditable={false}>\r\n {ALIGN_OPTIONS.map(({ value, Icon, label }) => (\r\n <button\r\n key={value}\r\n type=\"button\"\r\n className={`be-embed-toolbar-btn${align === value ? ' be-embed-toolbar-btn-active' : ''}`}\r\n title={label}\r\n aria-label={label}\r\n aria-pressed={align === value}\r\n onClick={() => setMedia({ align: value })}\r\n >\r\n <Icon size={14} />\r\n </button>\r\n ))}\r\n {kind === 'image' && (\r\n <button type=\"button\" className=\"be-embed-toolbar-btn be-embed-alt-text-btn\" onClick={openAltText}>\r\n Alt text\r\n </button>\r\n )}\r\n <button type=\"button\" className=\"be-embed-remove\" onClick={clearMedia} aria-label={`Remove ${KIND_LABEL[kind]}`}>\r\n Remove\r\n </button>\r\n </div>\r\n <EmbedPreview kind={kind} src={src} name={name} alt={alt} />\r\n {canResize && (\r\n <div\r\n className=\"be-embed-resize-handle\"\r\n onMouseDown={handleResizeStart}\r\n role=\"slider\"\r\n aria-label={`Resize ${KIND_LABEL[kind]}`}\r\n aria-valuemin={MIN_WIDTH}\r\n aria-valuemax={MAX_WIDTH}\r\n aria-valuenow={effectiveWidth}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n ) : (\r\n <div\r\n className={`be-embed-dropzone${isDragOver ? ' be-embed-dropzone-active' : ''}`}\r\n onDrop={handleDrop}\r\n onDragOver={handleDragOver}\r\n onDragLeave={handleDragLeave}\r\n >\r\n <label className=\"be-embed-upload-btn\">\r\n Upload {KIND_LABEL[kind]}\r\n <input type=\"file\" accept={KIND_ACCEPT[kind]} onChange={handleFileChange} hidden />\r\n </label>\r\n <span className=\"be-embed-dropzone-hint\">or drop a file, or paste a URL below</span>\r\n <div className=\"be-embed-url-row\">\r\n <input\r\n type=\"text\"\r\n className=\"be-embed-url-input\"\r\n placeholder={`https://... ${KIND_LABEL[kind]} URL`}\r\n value={urlInput}\r\n onChange={(event) => setUrlInput(event.target.value)}\r\n onKeyDown={(event) => event.key === 'Enter' && commitUrl()}\r\n />\r\n <button type=\"button\" className=\"be-embed-url-commit\" onClick={commitUrl}>\r\n Embed\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n <Modal isOpen={isAltTextOpen} onClose={closeAltText} title=\"Alt text\">\r\n <form onSubmit={saveAltText}>\r\n <label className=\"be-modal-field\">\r\n <span>Describe this image for screen readers</span>\r\n <input\r\n type=\"text\"\r\n value={altDraft}\r\n onChange={(event) => setAltDraft(event.target.value)}\r\n placeholder=\"e.g. A hand-drawn diagram of the release process\"\r\n autoFocus\r\n />\r\n </label>\r\n <div className=\"be-modal-actions\">\r\n <button type=\"button\" className=\"be-modal-cancel\" onClick={closeAltText}>\r\n Cancel\r\n </button>\r\n <button type=\"submit\" className=\"be-modal-save\">\r\n Save\r\n </button>\r\n </div>\r\n </form>\r\n </Modal>\r\n </div>\r\n );\r\n}\r\n","import { genId } from '../../utils/idGen.js';\r\n\r\n/**\r\n * factory(parentId) -> {block, runs} for a media embed — a pure \"widget\"\r\n * block with no runs at all (contentIds always []), same shape as divider:\r\n * `kind` is one of 'image' | 'video' | 'audio' | 'file'; `src` is either an\r\n * external URL or a data: URL (for a locally-uploaded file — see\r\n * EmbedBlock.jsx for why there's no upload-to-a-server path in a\r\n * zero-runtime-dependency package with no backend); `name` is the original\r\n * filename or the URL itself, used as download name / link text depending\r\n * on kind — deliberately NOT used as alt text (a raw filename like\r\n * \"IMG_2481.HEIC\" isn't a meaningful image description). `alt` is the\r\n * real, separately-authored description (image kind only — see\r\n * EmbedBlock's \"Alt text\" toolbar button), empty by default. `align`\r\n * ('left' | 'center' | 'right') positions the whole widget within the\r\n * line; `width` (a percentage, 20-100) is only meaningful for image/video\r\n * kinds — see EmbedBlock's resize handle.\r\n */\r\nexport function createEmbedBlock({\r\n kind = 'file',\r\n src = '',\r\n name = '',\r\n alt = '',\r\n mimeType = '',\r\n align = 'left',\r\n width = 100,\r\n} = {}) {\r\n return function factory(parentId) {\r\n return {\r\n block: { id: genId(), type: 'embed', parentId, contentIds: [], props: { kind, src, name, alt, mimeType, align, width } },\r\n runs: [],\r\n };\r\n };\r\n}\r\n","import { EmbedBlock } from './EmbedBlock.jsx';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { escapeAttr, escapeHTML } from '../../inline/marks.js';\r\nimport { insertSiblingAfter, insertSiblingAfterAndFocus } from '../shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\r\nimport { createEmbedBlock } from './createEmbedBlock.js';\r\nimport { updateRun } from '../../store/operations.js';\r\nimport { ImageIcon, VideoIcon, AudioIcon, PaperclipIcon } from '../../react/icons.jsx';\r\n\r\nconst KIND_ICONS = { image: ImageIcon, video: VideoIcon, audio: AudioIcon, file: PaperclipIcon };\r\n\r\n// Distinctive marker class for the 'file' kind's <a> — same reasoning as\r\n// the button block: an ordinary pasted link must never be mistaken for a\r\n// file embed.\r\nconst FILE_MARKER_CLASS = 'be-embed-file-link';\r\n\r\n// Only image/video kinds ever carry a non-default align/width (see\r\n// EmbedBlock's resize handle/alignment toolbar) — the inline `style`\r\n// attribute is only ever emitted for those, and only when it actually\r\n// differs from the default, so a plain default-aligned embed's HTML output\r\n// is byte-identical to before this existed.\r\nfunction alignWidthStyle(kind, align, width) {\r\n if (kind !== 'image' && kind !== 'video') return '';\r\n const declarations = [];\r\n if (width !== 100) declarations.push(`width:${width}%`);\r\n if (align === 'center') declarations.push('display:block', 'margin-left:auto', 'margin-right:auto');\r\n else if (align === 'right') declarations.push('display:block', 'margin-left:auto');\r\n return declarations.length ? ` style=\"${declarations.join(';')}\"` : '';\r\n}\r\n\r\nfunction parseAlignWidth(node) {\r\n const styleWidth = node.style?.width;\r\n const width = styleWidth && styleWidth.endsWith('%') ? parseInt(styleWidth, 10) : 100;\r\n let align = 'left';\r\n if (node.style?.marginLeft === 'auto' && node.style?.marginRight === 'auto') align = 'center';\r\n else if (node.style?.marginLeft === 'auto') align = 'right';\r\n return { align, width: Number.isFinite(width) ? width : 100 };\r\n}\r\n\r\nfunction toHTML(block) {\r\n const { kind, src, name, alt = '', align = 'left', width = 100 } = block.props;\r\n if (!src) return '<p></p>'; // nothing embedded yet: nothing meaningful to export\r\n const style = alignWidthStyle(kind, align, width);\r\n // Deliberately `alt`, never `name` (the uploaded file's raw filename) —\r\n // same \"don't silently present a filename as if it were real alt text\"\r\n // rationale as EmbedBlock.jsx's own EmbedPreview.\r\n if (kind === 'image') return `<img src=\"${escapeAttr(src)}\" alt=\"${escapeAttr(alt)}\"${style}>`;\r\n if (kind === 'video') return `<video src=\"${escapeAttr(src)}\" controls${style}></video>`;\r\n if (kind === 'audio') return `<audio src=\"${escapeAttr(src)}\" controls></audio>`;\r\n return `<a class=\"${FILE_MARKER_CLASS}\" href=\"${escapeAttr(src)}\">${escapeHTML(name || src)}</a>`;\r\n}\r\n\r\nfunction toPlainText(block) {\r\n const { kind, src, name } = block.props;\r\n return src ? `[${kind}: ${name || src}]` : '';\r\n}\r\n\r\nfunction fromHTML(node) {\r\n if (node.tagName === 'IMG') {\r\n // A pasted <img>'s own alt attribute is real alt text (however good or\r\n // bad it is at the source) — carried into props.alt, kept separate\r\n // from `name` (which has no meaningful value here; there's no \"raw\r\n // filename\" for an externally pasted image the way there is for a\r\n // locally uploaded file).\r\n return blockOf('image', node.getAttribute('src') ?? '', '', {\r\n ...parseAlignWidth(node),\r\n alt: node.getAttribute('alt') ?? '',\r\n });\r\n }\r\n if (node.tagName === 'VIDEO') {\r\n return blockOf('video', node.getAttribute('src') ?? '', '', parseAlignWidth(node));\r\n }\r\n if (node.tagName === 'AUDIO') {\r\n return blockOf('audio', node.getAttribute('src') ?? '', '');\r\n }\r\n if (node.tagName === 'A' && node.classList.contains(FILE_MARKER_CLASS)) {\r\n return blockOf('file', node.getAttribute('href') ?? '', node.textContent ?? '');\r\n }\r\n return null;\r\n}\r\n\r\nfunction blockOf(kind, src, name, { align = 'left', width = 100, alt = '' } = {}) {\r\n return {\r\n block: { id: genId(), type: 'embed', parentId: null, contentIds: [], props: { kind, src, name, alt, align, width } },\r\n runs: [],\r\n };\r\n}\r\n\r\n/** Same pattern as divider's slash command: an embed has no run of its own to focus into, so seed and focus a following paragraph. */\r\nfunction insertEmbedCommand(kind) {\r\n return (store, { blockId, runId, sliceStart, sliceEnd }) => {\r\n const run = store.getRun(runId);\r\n const value = run?.value ?? '';\r\n store.applyOperation(updateRun(runId, { value: value.slice(0, sliceStart) + value.slice(sliceEnd) }));\r\n const embedId = insertSiblingAfter(store, blockId, createEmbedBlock({ kind }));\r\n insertSiblingAfterAndFocus(store, embedId, createTextLeafBlock('paragraph'));\r\n return embedId;\r\n };\r\n}\r\n\r\nexport const embedBlockType = {\r\n component: EmbedBlock,\r\n isLeaf: true, // contentIds always [] — a pure widget, same convention as divider\r\n defaultProps: { kind: 'file', src: '', name: '', alt: '', mimeType: '', align: 'left', width: 100 },\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommands: ['image', 'video', 'audio', 'file'].map((kind) => ({\r\n label: kind.charAt(0).toUpperCase() + kind.slice(1),\r\n icon: KIND_ICONS[kind],\r\n keywords: ['embed', 'upload', 'insert', kind],\r\n run: insertEmbedCommand(kind),\r\n })),\r\n};\r\n","const DEFAULT_SIZE = 8;\nconst DEFAULT_THINNING = 0.5;\nconst DEFAULT_SMOOTHING = 0.5;\nconst TAPER_POINT_COUNT = 4;\nconst MIN_RADIUS_FACTOR = 0.15;\n// \"Speed\" is approximated as raw distance between consecutive input samples\n// (no real timestamps are captured/needed) — a reasonable proxy since\n// pointermove sampling density is roughly constant for a given device, and\n// this only needs to feel right, not model real velocity precisely. This is\n// the normalized-space (0..1000) distance a step must cover to count as\n// \"fast enough to fully thin\" the stroke.\nconst SPEED_NORM = 8;\n\nfunction dist(a, b) {\n return Math.hypot(a[0] - b[0], a[1] - b[1]);\n}\n\nfunction clamp(value, min, max) {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction round(n) {\n return Math.round(n * 100) / 100;\n}\n\n// Every pointer event handler in CanvasBlock.jsx falls back to a hardcoded\n// `event.pressure || 0.5` when the input device reports no real pressure\n// (true for every mouse and most touchscreens — only an actual\n// pressure-sensitive stylus reports something else) — see the doc comment\n// on `hasRealPressureVariation` below for what that default is used for.\nconst DEFAULT_PRESSURE = 0.5;\n\n/**\n * Whether this stroke carries genuine pressure DATA — some point's pressure\n * differs from the plain default every non-stylus input device reports.\n * Only strokes with real variation get pressure-based width scaling in\n * `computeRadii` below; otherwise the overwhelmingly common case (mouse/\n * touch, no stylus) would ALWAYS render at a fraction of its own chosen\n * `size` — a stroke drawn at \"width 20\" looking visibly thinner than a\n * width-20 shape outline, which is exactly the mismatch this exists to\n * avoid. A real stylus's pressure data is trusted and still gets full\n * variable-width treatment, since that's genuinely useful, expected\n * behavior for that input method.\n */\nexport function hasRealPressureVariation(points) {\n return points.some(([, , pressure]) => pressure !== undefined && pressure !== DEFAULT_PRESSURE);\n}\n\n/**\n * One radius (half-width) per input point — a zero-dependency reimplementation\n * of perfect-freehand's most visually important trait, not a full port of its\n * configurable easing system. Blends a pressure-based base width with a\n * velocity-based thinning term (faster movement between consecutive samples\n * -> thinner ink), then tapers both ends of the whole stroke down toward a\n * point (the \"comes to a point\" look real ink/brushes have). Exported\n * directly so its shape (radius shrinks toward both ends relative to the\n * middle) is independently testable without parsing path-string geometry.\n *\n * ALL of that — pressure scaling, velocity thinning, AND end-taper — is\n * gated behind `hasRealPressureVariation`: without genuine stylus pressure\n * data (a mouse/touchscreen stroke, the overwhelmingly common case), the\n * radius is simply `size / 2` at every single point, full stop. A stroke\n * drawn at \"width 20\" must look exactly as wide as a width-20 shape\n * outline, everywhere along its length — not just \"close\" at rest with a\n * thinner middle whenever the cursor moved at a normal drawing speed\n * (thinning) or thinner tips (taper). Only a real stylus's pressure data\n * unlocks the full natural \"ink\" look these terms exist for.\n */\nexport function computeRadii(points, { size = DEFAULT_SIZE, thinning = DEFAULT_THINNING } = {}) {\n const baseRadius = size / 2;\n const n = points.length;\n const usePressure = hasRealPressureVariation(points);\n\n if (!usePressure) return new Array(n).fill(baseRadius);\n\n const radii = new Array(n);\n let speed = 0;\n\n for (let i = 0; i < n; i += 1) {\n if (i > 0) {\n const step = dist(points[i], points[i - 1]);\n speed = speed * 0.8 + step * 0.2;\n }\n const speedFactor = clamp(speed / SPEED_NORM, 0, 1);\n const pressure = points[i][2] ?? DEFAULT_PRESSURE;\n const pressureFactor = 0.4 + 0.6 * clamp(pressure, 0, 1);\n const radius = clamp(\n baseRadius * pressureFactor * (1 - thinning * speedFactor),\n baseRadius * MIN_RADIUS_FACTOR,\n baseRadius,\n );\n radii[i] = radius;\n }\n\n const taperCount = Math.min(TAPER_POINT_COUNT, Math.floor(n / 2));\n for (let i = 0; i < taperCount; i += 1) {\n const t = (i + 1) / (taperCount + 1); // ramps 0 (exclusive) -> 1 (exclusive)\n const factor = MIN_RADIUS_FACTOR + (1 - MIN_RADIUS_FACTOR) * t;\n radii[i] *= factor;\n radii[n - 1 - i] *= factor;\n }\n\n return radii;\n}\n\n/** Simple moving-average smoothing over the centerline (position only, never pressure) — removes visible raw-input jitter without any external dependency. Endpoints are left untouched so the stroke's start/end position is never shifted. */\nfunction smoothPoints(points, smoothing) {\n const n = points.length;\n if (n < 3 || smoothing <= 0) return points;\n const result = new Array(n);\n result[0] = points[0];\n result[n - 1] = points[n - 1];\n for (let i = 1; i < n - 1; i += 1) {\n const midX = (points[i - 1][0] + points[i + 1][0]) / 2;\n const midY = (points[i - 1][1] + points[i + 1][1]) / 2;\n const x = points[i][0] + (midX - points[i][0]) * smoothing;\n const y = points[i][1] + (midY - points[i][1]) * smoothing;\n result[i] = [x, y, points[i][2]];\n }\n return result;\n}\n\n/** Left/right offset points at each centerline point, using a central-difference tangent (one-sided at the ends) rotated 90deg for the normal. */\nfunction computeOffsets(points, radii) {\n const n = points.length;\n const left = new Array(n);\n const right = new Array(n);\n for (let i = 0; i < n; i += 1) {\n const prev = points[Math.max(0, i - 1)];\n const next = points[Math.min(n - 1, i + 1)];\n let tx = next[0] - prev[0];\n let ty = next[1] - prev[1];\n const len = Math.hypot(tx, ty) || 1;\n tx /= len;\n ty /= len;\n const nx = -ty; // tangent rotated 90deg = normal\n const ny = tx;\n const r = radii[i];\n left[i] = [points[i][0] + nx * r, points[i][1] + ny * r];\n right[i] = [points[i][0] - nx * r, points[i][1] - ny * r];\n }\n return { left, right };\n}\n\nfunction pathFromPolygon(poly) {\n if (poly.length === 0) return '';\n let d = `M${round(poly[0][0])},${round(poly[0][1])}`;\n for (let i = 1; i < poly.length; i += 1) d += ` L${round(poly[i][0])},${round(poly[i][1])}`;\n return d;\n}\n\n/** A regular-polygon approximation of a filled circle, built from plain line segments (consistent with the rest of this module's \"no bezier curves in v1\" simplification) — used for a tap-without-drag, so a single click still leaves a visible mark. */\nfunction dotPath([x, y], radius) {\n const sides = 12;\n const poly = [];\n for (let i = 0; i < sides; i += 1) {\n const angle = (i / sides) * Math.PI * 2;\n poly.push([x + Math.cos(angle) * radius, y + Math.sin(angle) * radius]);\n }\n return `${pathFromPolygon(poly)} Z`;\n}\n\n/**\n * Builds an SVG path `d` string for one stroke's filled variable-width\n * outline, from raw `[x, y, pressure]` input points in the block's fixed\n * 0..1000 normalized coordinate space. This is the whole \"ink\" look: a\n * FILLED polygon (native `stroke-width` can't vary along a path), not a\n * stroked centerline.\n *\n * `size` is the stroke's full width at maximum thickness (radius = size/2);\n * `thinning` (0..1) controls how much faster movement thins the ink;\n * `smoothing` (0..1) controls how much the raw input jitter is smoothed out.\n */\nexport function getStrokeOutlinePath(rawPoints, options = {}) {\n const { size = DEFAULT_SIZE, thinning = DEFAULT_THINNING, smoothing = DEFAULT_SMOOTHING } = options;\n if (!rawPoints || rawPoints.length === 0) return '';\n\n // Drop consecutive near-duplicate points — avoids zero-length tangents/\n // divide-by-zero in computeOffsets, and can legitimately happen if the\n // pointer pauses mid-stroke without moving.\n const points = [rawPoints[0]];\n for (let i = 1; i < rawPoints.length; i += 1) {\n if (dist(rawPoints[i], points[points.length - 1]) > 0.1) points.push(rawPoints[i]);\n }\n\n if (points.length === 1) {\n const pressure = points[0][2] ?? 0.5;\n const radius = (size / 2) * (0.4 + 0.6 * clamp(pressure, 0, 1));\n return dotPath(points[0], radius);\n }\n\n const radii = computeRadii(points, { size, thinning });\n const smoothed = smoothPoints(points, smoothing);\n const { left, right } = computeOffsets(smoothed, radii);\n\n const polygon = [...left, ...right.slice().reverse()];\n return `${pathFromPolygon(polygon)} Z`;\n}\n\n/** Plain min/max bounding box over raw points — reused by the eraser's hit-test (see canvasGeometry.js). */\nexport function strokeBoundingBox(points) {\n if (!points || points.length === 0) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const [x, y] of points) {\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n }\n return { minX, minY, maxX, maxY };\n}\n","/**\n * The `<svg>` keeps its default `preserveAspectRatio` (\"xMidYMid meet\"),\n * which scales a `size x size` SQUARE viewBox to fit inside the rendered\n * box UNIFORMLY (same factor on both axes) and CENTERS it — letterboxing\n * whichever axis is \"too big\" — rather than stretching each axis\n * independently to fill it. `width`/`height` (the block's own rendered\n * pixel size) default to 480x320, a non-square box, so this letterboxing is\n * the common case, not an edge case.\n *\n * A naive `(clientX - rect.left) / rect.width` (dividing by each axis'\n * OWN rendered dimension independently) ignores that letterbox offset\n * entirely — it's only correct when the rendered box happens to be exactly\n * square. Otherwise the cursor and the point actually drawn silently drift\n * apart, worse the more the rendered box's aspect ratio departs from\n * square. This replicates the browser's own \"meet\" math (one shared\n * `scale`, plus a centering offset on whichever axis has the extra space)\n * so the two always agree, for ANY rendered box shape.\n */\nfunction computeViewTransform(svgEl, size) {\n const rect = svgEl.getBoundingClientRect();\n const rectWidth = rect.width || 1;\n const rectHeight = rect.height || 1;\n const scale = Math.min(rectWidth / size, rectHeight / size);\n const offsetX = (rectWidth - size * scale) / 2;\n const offsetY = (rectHeight - size * scale) / 2;\n return { rect, scale, offsetX, offsetY };\n}\n\n/**\n * Converts a pointer event's client coordinates into the block's fixed\n * 0..1000 normalized drawing space (see createCanvasBlock.js) — independent\n * of the SVG's own rendered pixel size, so drawing stays correct regardless\n * of how the block has been resized.\n *\n * `view` is the currently-visible window into that fixed space (pan/zoom —\n * see CanvasBlock.jsx's local, non-persisted `view` state): `{x, y}` is the\n * top-left corner currently shown and `size` is how much of the space is\n * visible across the SVG's full rendered width/height (matching whatever\n * `viewBox` the `<svg>` was actually given). Defaults to the whole\n * un-panned/un-zoomed space, so a caller that never introduces pan/zoom\n * (or a test that doesn't care about it) gets the exact same mapping as\n * before pan/zoom existed.\n */\nexport function clientToLocal(event, svgEl, view = { x: 0, y: 0, size: 1000 }) {\n const { rect, scale, offsetX, offsetY } = computeViewTransform(svgEl, view.size);\n const x = view.x + (event.clientX - rect.left - offsetX) / scale;\n const y = view.y + (event.clientY - rect.top - offsetY) / scale;\n return [x, y];\n}\n\n/**\n * How many local-space units correspond to one CSS pixel of the SVG's own\n * rendered box, at the given local `size` — used to convert a client-space\n * pixel DELTA (a pan drag's mouse movement) into a local-space delta,\n * without needing `clientToLocal`'s absolute `view.x`/`view.y` offset,\n * which a plain delta doesn't care about. Shares the exact same letterbox-\n * aware `scale` as `clientToLocal` so panning tracks the cursor 1:1\n * regardless of the rendered box's aspect ratio.\n */\nexport function localPixelScale(svgEl, size) {\n return computeViewTransform(svgEl, size).scale;\n}\n\n/**\n * Computes the next pan/zoom `view` (see CanvasBlock.jsx) that keeps the\n * point currently under the cursor fixed on screen as the zoom level\n * changes — the standard \"zoom toward the cursor\" behavior. `prevView` is\n * the view before this wheel tick; `nextSize` is the new (post-zoom) local\n * window size (`VIEW_SIZE / nextZoom`).\n */\nexport function zoomAnchoredView(event, svgEl, prevView, nextSize) {\n const [cursorLocalX, cursorLocalY] = clientToLocal(event, svgEl, prevView);\n const { rect, scale, offsetX, offsetY } = computeViewTransform(svgEl, nextSize);\n const x = cursorLocalX - (event.clientX - rect.left - offsetX) / scale;\n const y = cursorLocalY - (event.clientY - rect.top - offsetY) / scale;\n return { x, y };\n}\n\n/**\n * Computes the next pan/zoom view that keeps the CURRENT VIEW'S OWN CENTER\n * point fixed as zoom changes — the zoom in/out toolbar buttons' own\n * variant of `zoomAnchoredView` above, for when there's no cursor position\n * to anchor to (a button click, not a wheel event). Needs no DOM/event at\n * all, unlike `zoomAnchoredView` — it's pure arithmetic on the view itself.\n */\nexport function zoomCenteredView(prevView, nextSize) {\n const centerX = prevView.x + prevView.size / 2;\n const centerY = prevView.y + prevView.size / 2;\n return { x: centerX - nextSize / 2, y: centerY - nextSize / 2 };\n}\n\n/**\n * Clamps a pan offset once the view window is zoomed out wider than the\n * fixed `boundsSize x boundsSize` sheet itself (see CanvasBlock.jsx's\n * VIEW_SIZE) -- used after every pan/zoom update (wheel-drag, toolbar\n * buttons, mouse/touch drag) so scrolling can't push the sheet off to one\n * side once it's already small enough to see the whole thing at once.\n * `size <= boundsSize` (100% zoom or zoomed in) is passed through\n * unclamped -- there's always at most one sheet-edge in view at a time\n * there, so panning to any of them is meaningful, same as before this\n * clamp existed. Only once `size > boundsSize` (zoomed out PAST 100%, all\n * the way down through MIN_ZOOM) does the offset lock to dead-center --\n * beyond that point the whole sheet already fits, so there is nowhere left\n * to usefully pan to and letting the offset drift would only ever show\n * blank space beyond the sheet's edges.\n */\nexport function clampViewOffset(x, y, size, boundsSize) {\n if (size <= boundsSize) return { x, y };\n const centered = (boundsSize - size) / 2;\n return { x: centered, y: centered };\n}\n\n/** True if two `{minX,minY,maxX,maxY}` boxes overlap, optionally padded outward by `padding` on both — used by the eraser's hit-test (a stroke's own half-width is a natural padding, so a thin eraser pass still catches thick ink). */\nexport function boxesIntersect(a, b, padding = 0) {\n return a.minX - padding <= b.maxX && a.maxX + padding >= b.minX && a.minY - padding <= b.maxY && a.maxY + padding >= b.minY;\n}\n","/**\n * Turns two drag corners (in either direction — the user may drag up/left\n * just as easily as down/right) into a valid, always-non-negative-size box.\n * Shared by both the live drag preview and the final commit, so a shape's\n * stored `{x, y, width, height}` is always in this normalized form —\n * `pointInRect`/rendering never has to handle a negative width/height.\n */\nexport function normalizeRect(x1, y1, x2, y2) {\n const x = Math.min(x1, x2);\n const y = Math.min(y1, y2);\n const width = Math.abs(x2 - x1);\n const height = Math.abs(y2 - y1);\n return { x, y, width, height };\n}\n\n/**\n * Rotates `(px, py)` by `angleDeg` degrees (clockwise, matching SVG's own\n * `rotate()` transform convention) around `(cx, cy)`. Used both ways by the\n * rotate tool: to place a rotated shape's own handle/hit-test points in\n * screen space (forward), and to map a click point back into a rotated\n * shape's own unrotated local frame before running the ordinary\n * pointInRect/pointInEllipse/pointInPolygon tests (inverse — pass\n * `-angleDeg`).\n */\nexport function rotatePoint(px, py, cx, cy, angleDeg) {\n const radians = (angleDeg * Math.PI) / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n const dx = px - cx;\n const dy = py - cy;\n return [cx + dx * cos - dy * sin, cy + dx * sin + dy * cos];\n}\n\n/** True if `(px, py)` falls anywhere inside `rect`'s bounding box. */\nexport function pointInRect(px, py, rect) {\n return px >= rect.x && px <= rect.x + rect.width && py >= rect.y && py <= rect.y + rect.height;\n}\n\n/**\n * True if `(px, py)` falls inside the ellipse inscribed in `rect`'s\n * bounding box (standard `(dx/rx)^2 + (dy/ry)^2 <= 1` test) — matches what\n * is actually rendered (an `<ellipse>` inscribed in the same box a\n * rectangle would occupy), not just the box itself.\n */\nexport function pointInEllipse(px, py, rect) {\n const rx = rect.width / 2;\n const ry = rect.height / 2;\n if (rx === 0 || ry === 0) return false;\n const cx = rect.x + rx;\n const cy = rect.y + ry;\n const dx = (px - cx) / rx;\n const dy = (py - cy) / ry;\n return dx * dx + dy * dy <= 1;\n}\n\n/**\n * Distance from `(px, py)` to the line segment `(x1,y1)-(x2,y2)`, clamped to\n * the segment (not the infinite line) — the standard \"project onto the\n * segment, clamp t to [0,1]\" formula. Used for the arrow tool's hit-test:\n * `pointNearSegment(...) <= tolerance`.\n */\nexport function distanceToSegment(px, py, x1, y1, x2, y2) {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const lengthSquared = dx * dx + dy * dy;\n if (lengthSquared === 0) return Math.hypot(px - x1, py - y1);\n let t = ((px - x1) * dx + (py - y1) * dy) / lengthSquared;\n t = Math.min(1, Math.max(0, t));\n const projX = x1 + t * dx;\n const projY = y1 + t * dy;\n return Math.hypot(px - projX, py - projY);\n}\n\n/** `distanceToSegment(...) <= tolerance` — the arrow tool's own hit-test. */\nexport function pointNearSegment(px, py, x1, y1, x2, y2, tolerance) {\n return distanceToSegment(px, py, x1, y1, x2, y2) <= tolerance;\n}\n\n/** The 4 edge-midpoints of `rect`'s bounding box (top/right/bottom/left), in order — the vertices of the diamond inscribed in it. */\nexport function diamondPoints(rect) {\n const { x, y, width, height } = rect;\n return [\n [x + width / 2, y],\n [x + width, y + height / 2],\n [x + width / 2, y + height],\n [x, y + height / 2],\n ];\n}\n\n/**\n * The 3 vertices of a triangle inscribed in `rect`'s bounding box\n * (top-mid, bottom-right, bottom-left) — the shape behind the \"polygon\"\n * tool for this pass (a variable side-count control is out of scope). Not\n * necessarily equilateral unless the box happens to be square, same\n * \"inscribed in the bounding box\" convention `pointInEllipse` already uses\n * rather than a claim of geometric regularity.\n */\nexport function trianglePoints(rect) {\n const { x, y, width, height } = rect;\n return [\n [x + width / 2, y],\n [x + width, y + height],\n [x, y + height],\n ];\n}\n\n/**\n * The `spikes * 2` vertices of a star polygon centered in `rect`'s bounding\n * box, alternating between the outer radius (the box's own half-width/\n * height) and a fixed inner radius (0.4x the outer one — no configurable\n * spike count/ratio in this pass), starting from the top and going\n * clockwise.\n */\nexport function starPoints(rect, spikes = 5) {\n const { x, y, width, height } = rect;\n const cx = x + width / 2;\n const cy = y + height / 2;\n const outerRx = width / 2;\n const outerRy = height / 2;\n const innerRatio = 0.4;\n const points = [];\n const step = Math.PI / spikes;\n let angle = -Math.PI / 2;\n for (let i = 0; i < spikes * 2; i += 1) {\n const isOuter = i % 2 === 0;\n const rx = isOuter ? outerRx : outerRx * innerRatio;\n const ry = isOuter ? outerRy : outerRy * innerRatio;\n points.push([cx + Math.cos(angle) * rx, cy + Math.sin(angle) * ry]);\n angle += step;\n }\n return points;\n}\n\n/**\n * Standard ray-casting point-in-polygon test — shared by every polygon-\n * based shape's hit-test (diamond, triangle, star, and any future one),\n * rather than a bespoke closed-form check per shape. `vertices` is a plain\n * `[[x,y], ...]` array, same shape every `*Points` function above returns.\n */\nexport function pointInPolygon(px, py, vertices) {\n let inside = false;\n for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i, i += 1) {\n const [xi, yi] = vertices[i];\n const [xj, yj] = vertices[j];\n const crosses = yi > py !== yj > py;\n if (crosses && px < ((xj - xi) * (py - yi)) / (yj - yi) + xi) inside = !inside;\n }\n return inside;\n}\n\n/**\n * The 3 points of a small filled triangle for an arrow's arrowhead, planted\n * at `(x2, y2)` (the arrow's end point) and oriented along the segment's\n * own direction — computed at render time from the two endpoints rather\n * than stored, the same \"derive presentation from data\" principle\n * `strokeOutline.js` already uses for stroke outlines. Degenerates to a\n * triangle pointing along the +x axis for a zero-length segment (start\n * and end coincide) rather than producing NaNs.\n */\nexport function arrowheadPoints(x1, y1, x2, y2, size = 24) {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const length = Math.hypot(dx, dy);\n const [ux, uy] = length === 0 ? [1, 0] : [dx / length, dy / length];\n const backX = x2 - ux * size;\n const backY = y2 - uy * size;\n const nx = -uy;\n const ny = ux;\n const halfWidth = size / 2;\n return [\n [x2, y2],\n [backX + nx * halfWidth, backY + ny * halfWidth],\n [backX - nx * halfWidth, backY - ny * halfWidth],\n ];\n}\n","import { useCallback, useState } from 'react';\n\n/**\n * Generic \"drag a handle -> live-preview local state -> commit once on\n * release\" hook — extracted from `EmbedBlock.jsx`'s own inlined resize-drag\n * pattern (`mousedown` on a handle attaches `document`-level `mousemove`/\n * `mouseup`; `mousemove` only updates local state for a live preview, zero\n * store writes; `mouseup` removes both listeners and makes exactly ONE\n * commit) — the canvas block needs this identical shape a second time.\n * Deliberately NOT also wired into `EmbedBlock.jsx`/`TableHeaderRow.jsx` in\n * this same change — that would touch already-working, already-tested\n * files for no reason tied to this feature; a later, separate cleanup task\n * could migrate them onto this shared hook if desired.\n *\n * `compute(event, start)` embeds the caller's own geometry — `start` is\n * whatever snapshot the caller captured when the drag began (e.g.\n * `{ startX, startY, startWidth, startHeight }`); `compute` returns the\n * caller's own value shape (a plain number, or an object like\n * `{ width, height }`). `onCommit(value)` is called exactly once, on\n * release, with the final computed value.\n *\n * Returns `{ dragValue, startDrag }` — `dragValue` is the live in-progress\n * value (`null` when not dragging, for the caller's own\n * `effective = dragValue ?? committedValue` pattern); `startDrag(event,\n * start)` is the `onMouseDown` handler to wire onto the resize handle.\n */\nexport function useDragResize({ compute, onCommit }) {\n const [dragValue, setDragValue] = useState(null);\n\n const startDrag = useCallback(\n (event, start) => {\n event.preventDefault();\n const handleMouseMove = (moveEvent) => setDragValue(compute(moveEvent, start));\n const handleMouseUp = (upEvent) => {\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n onCommit(compute(upEvent, start));\n setDragValue(null);\n };\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n },\n [compute, onCommit],\n );\n\n return { dragValue, startDrag };\n}\n","import { genId } from '../../utils/idGen.js';\n\nexport const DEFAULT_CANVAS_WIDTH = 480;\nexport const DEFAULT_CANVAS_HEIGHT = 320;\n\n/**\n * factory(parentId) -> {block, runs} for a freehand-drawing surface — a pure\n * \"widget\" block with no runs at all (contentIds always []), same shape as\n * divider/embed. `strokes` is an array of `{ id, points, color, size }`,\n * where `points` are raw `[x, y, pressure]` triples authored in a FIXED\n * 0..1000 normalized coordinate space, decoupled from `width`/`height` (the\n * block's own rendered pixel size) — resizing the block never has to touch\n * or rescale stroke data, it only changes how big that fixed space is drawn.\n *\n * `shapes` is a sibling array in that same fixed space — rectangle/ellipse\n * entries are `{ id, type, x, y, width, height, color, strokeWidth }`\n * (top-left + always-normalized-positive size), arrow entries are\n * `{ id, type: 'arrow', x1, y1, x2, y2, color, strokeWidth }` (two\n * endpoints; the arrowhead itself is derived at render time, not stored —\n * see shapeGeometry.js's `arrowheadPoints`).\n */\nexport function createCanvasBlock({\n strokes = [],\n shapes = [],\n width = DEFAULT_CANVAS_WIDTH,\n height = DEFAULT_CANVAS_HEIGHT,\n} = {}) {\n return function factory(parentId) {\n return {\n block: { id: genId(), type: 'canvas', parentId, contentIds: [], props: { strokes, shapes, width, height } },\n runs: [],\n };\n };\n}\n","/**\n * Strokes and shapes are stored as two separate arrays (`props.strokes`/\n * `props.shapes`) for backward compatibility, but visually they share ONE\n * stacking order — a pen stroke drawn after a filled shape needs to render\n * on top of it, and vice versa, the same way every layer-based drawing tool\n * (this package included, as of this module) behaves. Before this module\n * existed, the two arrays had a hard-coded stacking instead: every shape\n * rendered above every stroke, regardless of which was actually drawn more\n * recently -- there was no way to draw on top of an already-placed shape.\n *\n * Documents from before this existed have no `z` on their strokes/shapes at\n * all. `LEGACY_Z_BASE` is a value comfortably larger than any realistic\n * shape/stroke count, so an item WITHOUT an explicit `z` keeps exactly that\n * old two-layer ordering (strokes 0..n-1, shapes LEGACY_Z_BASE..+m-1) when\n * merged into one list here -- no migration needed, nothing visually\n * changes for an already-drawn document until something new is added to it.\n * Items WITH an explicit `z` (everything created going forward, via\n * `nextZIndex` below) interleave by real creation order instead, and always\n * sort after every legacy item since their `z` starts above `LEGACY_Z_BASE`\n * too (see `nextZIndex`).\n */\nconst LEGACY_Z_BASE = 1e6;\n\nfunction effectiveZ(item, isShape, index) {\n return typeof item.z === 'number' ? item.z : isShape ? LEGACY_Z_BASE + index : index;\n}\n\n/** Merges strokes+shapes into one bottom-to-top render/hit-test order. Each entry is `{ kind: 'stroke' | 'shape', item, z }`. */\nexport function orderedDrawables(strokes, shapes) {\n const items = [\n ...strokes.map((item, i) => ({ kind: 'stroke', item, z: effectiveZ(item, false, i) })),\n ...shapes.map((item, i) => ({ kind: 'shape', item, z: effectiveZ(item, true, i) })),\n ];\n items.sort((a, b) => a.z - b.z);\n return items;\n}\n\n/** The z to stamp on a brand-new stroke/shape so it renders above everything already on the canvas (legacy or not). */\nexport function nextZIndex(strokes, shapes) {\n let maxZ = -1;\n strokes.forEach((item, i) => {\n maxZ = Math.max(maxZ, effectiveZ(item, false, i));\n });\n shapes.forEach((item, i) => {\n maxZ = Math.max(maxZ, effectiveZ(item, true, i));\n });\n return maxZ + 1;\n}\n\n/** The z one below everything already on the canvas — \"send to back\"'s own counterpart to `nextZIndex`. */\nexport function minZIndex(strokes, shapes) {\n let minZ = Infinity;\n strokes.forEach((item, i) => {\n minZ = Math.min(minZ, effectiveZ(item, false, i));\n });\n shapes.forEach((item, i) => {\n minZ = Math.min(minZ, effectiveZ(item, true, i));\n });\n return minZ === Infinity ? 0 : minZ - 1;\n}\n","import { getStrokeOutlinePath } from './strokeOutline.js';\nimport { arrowheadPoints, diamondPoints, trianglePoints, starPoints } from './shapeGeometry.js';\nimport { escapeAttr, escapeHTML } from '../../inline/marks.js';\nimport { orderedDrawables } from './zOrder.js';\n\nconst POLYGON_POINTS_BY_TYPE = { diamond: diamondPoints, triangle: trianglePoints, star: starPoints };\n\n/**\n * Bakes one shape (rectangle/ellipse/arrow/text/diamond/triangle/star) to\n * markup — reusing the exact same `arrowheadPoints`/`*Points` functions the\n * live `ShapeElement` renders with, so export always matches on-screen.\n * `fillColor` (rect/ellipse/diamond/triangle/star only) defaults to\n * `fill=\"none\"` when unset, matching `ShapeElement`. A non-zero `rotation`\n * (rect/ellipse/diamond/triangle/star/text only — arrows are never\n * rotated, see CanvasBlock.jsx's own doc comment on rotation's scope) wraps\n * the markup in a `<g rotate()>`, the same pivot (bounding-box center)\n * `ShapeElement` uses.\n */\nexport function shapeToHTML(shape) {\n const strokeWidth = shape.strokeWidth ?? 8;\n const color = escapeAttr(shape.color);\n if (shape.type === 'arrow') {\n const headSize = Math.max(16, strokeWidth * 3);\n const head = arrowheadPoints(shape.x1, shape.y1, shape.x2, shape.y2, headSize);\n const points = head.map(([x, y]) => `${x},${y}`).join(' ');\n return (\n `<line x1=\"${shape.x1}\" y1=\"${shape.y1}\" x2=\"${shape.x2}\" y2=\"${shape.y2}\" stroke=\"${color}\" stroke-width=\"${strokeWidth}\"></line>` +\n `<polygon points=\"${points}\" fill=\"${color}\"></polygon>`\n );\n }\n const fill = shape.fillColor ? escapeAttr(shape.fillColor) : 'none';\n let content;\n if (shape.type === 'rectangle') {\n content = `<rect x=\"${shape.x}\" y=\"${shape.y}\" width=\"${shape.width}\" height=\"${shape.height}\" fill=\"${fill}\" stroke=\"${color}\" stroke-width=\"${strokeWidth}\"></rect>`;\n } else if (shape.type === 'ellipse') {\n const cx = shape.x + shape.width / 2;\n const cy = shape.y + shape.height / 2;\n content = `<ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${shape.width / 2}\" ry=\"${shape.height / 2}\" fill=\"${fill}\" stroke=\"${color}\" stroke-width=\"${strokeWidth}\"></ellipse>`;\n } else if (shape.type === 'text') {\n // Same <foreignObject><div> approach as the live ShapeElement — real\n // browser text wrapping, not reimplemented SVG <text>/<tspan> layout.\n // `white-space:pre-wrap` alone (no manual <br> conversion) renders raw\n // newline characters as line breaks, matching how the live component's\n // own `{shape.text}` React text node renders under the same CSS.\n const fontSize = shape.fontSize ?? 28;\n const text = escapeHTML(shape.text ?? '');\n content =\n `<foreignObject x=\"${shape.x}\" y=\"${shape.y}\" width=\"${shape.width}\" height=\"${shape.height}\">` +\n `<div xmlns=\"http://www.w3.org/1999/xhtml\" style=\"width:100%;height:100%;overflow:hidden;color:${color};font-size:${fontSize}px;line-height:1.3;white-space:pre-wrap;word-break:break-word;\">${text}</div>` +\n `</foreignObject>`;\n } else {\n const pointsFn = POLYGON_POINTS_BY_TYPE[shape.type];\n if (!pointsFn) return '';\n const rect = { x: shape.x, y: shape.y, width: shape.width, height: shape.height };\n const points = pointsFn(rect)\n .map(([x, y]) => `${x},${y}`)\n .join(' ');\n content = `<polygon points=\"${points}\" fill=\"${fill}\" stroke=\"${color}\" stroke-width=\"${strokeWidth}\"></polygon>`;\n }\n if (!shape.rotation) return content;\n const cx = shape.x + shape.width / 2;\n const cy = shape.y + shape.height / 2;\n return `<g transform=\"rotate(${shape.rotation} ${cx} ${cy})\">${content}</g>`;\n}\n\n/**\n * Bakes a canvas block's `strokes`/`shapes` into one self-contained\n * `<svg>...</svg>` string — reusing the exact same `getStrokeOutlinePath`/\n * `shapeToHTML` functions the live component renders with, so this always\n * matches what's on screen, INCLUDING their relative stacking order\n * (`orderedDrawables`, see zOrder.js — a pen stroke drawn on top of a\n * shape live must still render on top of it here). Shared by two call sites that both need the\n * SAME markup for two different purposes (this module exists specifically\n * to let them both import it without a circular dependency — `index.js`'s\n * own `toHTML` needs `CanvasBlock.jsx` for its `component` field, and\n * `CanvasBlock.jsx`'s PNG-export button needs this markup, so this couldn't\n * live in either of those two files without one importing the other):\n * - `index.js`'s `toHTML` embeds it inline in exported document HTML.\n * - `CanvasBlock.jsx`'s \"Export PNG\" button loads it into an `Image` (via\n * an `xmlns`-qualified, standalone-valid SVG document — required for a\n * browser to parse it outside an HTML embedding context) and rasterizes\n * that onto an offscreen `<canvas>`.\n */\nexport function buildCanvasSVGMarkup(block) {\n const { strokes = [], shapes = [], width, height } = block.props;\n const markup = orderedDrawables(strokes, shapes)\n .map(({ kind, item }) =>\n kind === 'stroke'\n ? `<path fill=\"${escapeAttr(item.color)}\" d=\"${getStrokeOutlinePath(item.points, { size: item.size })}\"></path>`\n : shapeToHTML(item),\n )\n .join('');\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1000 1000\" width=\"${width}\" height=\"${height}\">${markup}</svg>`;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useBlock } from '../../react/useBlock.js';\nimport { useBlockClassName, useEditorStore } from '../../react/EditorProvider.jsx';\nimport { useOutsideClickAndEscape } from '../../react/useOutsideClickAndEscape.js';\nimport { updateBlockProps } from '../../store/operations.js';\nimport { genId } from '../../utils/idGen.js';\nimport { getStrokeOutlinePath, strokeBoundingBox } from './strokeOutline.js';\nimport { clientToLocal, boxesIntersect, localPixelScale, zoomAnchoredView, zoomCenteredView, clampViewOffset } from './canvasGeometry.js';\nimport {\n arrowheadPoints,\n normalizeRect,\n pointInRect,\n pointInEllipse,\n pointNearSegment,\n diamondPoints,\n trianglePoints,\n starPoints,\n pointInPolygon,\n rotatePoint,\n} from './shapeGeometry.js';\nimport { useDragResize } from '../shared/useDragResize.js';\nimport { DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT } from './createCanvasBlock.js';\nimport { buildCanvasSVGMarkup } from './exportSvg.js';\nimport { orderedDrawables, nextZIndex, minZIndex } from './zOrder.js';\nimport {\n PencilIcon,\n XIcon,\n SquareIcon,\n CircleIcon,\n ArrowDiagonalIcon,\n CursorIcon,\n DiamondIcon,\n TriangleIcon,\n StarIcon,\n ArrowUpIcon,\n ArrowDownIcon,\n TextIcon,\n MagnetIcon,\n DownloadIcon,\n EraserIcon,\n} from '../../react/icons.jsx';\n\n// The whole drawing surface is authored in this fixed logical space —\n// `props.width`/`props.height` only control the SVG's *rendered* pixel\n// size (the viewBox/rendered-size split below), never the coordinates\n// stroke data is stored in. This is what makes resizing the block a pure\n// \"change how big this is drawn\" operation that never touches `strokes`.\nconst VIEW_SIZE = 1000;\n\nconst DEFAULT_COLOR = '#1a1a1a';\nconst DEFAULT_STROKE_SIZE = 8;\n// A small fixed palette, same spirit as FloatingToolbar's own text-color\n// swatches — a pen stroke always needs a concrete color (no \"Default\"/null\n// option the way text color has, since ink has to render as *something*).\nconst COLOR_SWATCHES = ['#1a1a1a', '#e03131', '#2f9e44', '#1971c2', '#f08c00'];\nconst MIN_STROKE_SIZE = 2;\nconst MAX_STROKE_SIZE = 40;\n// Half-width of the eraser's own hit area, in the same fixed 0..1000\n// normalized space strokes are authored in. Two selectable eraser modes\n// (see the toolbar's own Eraser popover) share the exact same hit-test\n// logic (`hitTestEraserAt`, erasing whole strokes/shapes it touches, never\n// partial pixels) — they differ only in this radius: \"Object Eraser\" is\n// deliberately generous (bigger than a typical pen stroke), forgiving to\n// aim when you want to clear something out quickly; \"Precise Eraser\" uses\n// a much smaller radius, for working close to other ink without\n// accidentally sweeping up a neighboring stroke/shape. \"Forgiving to aim\"\n// is about REACH (how close you need to get to a stroke), not precision,\n// though — the actual hit-test (see `strokeNearPoint`) still only counts a\n// stroke as touched where the eraser is actually near its real path, not\n// merely somewhere inside its overall bounding box, regardless of mode.\nconst ERASER_RADIUS = 24;\nconst ERASER_RADIUS_PRECISE = 6;\nconst MIN_CANVAS_WIDTH = 160;\nconst MIN_CANVAS_HEIGHT = 120;\nconst MIN_ZOOM = 0.5;\nconst MAX_ZOOM = 4;\nconst ZOOM_STEP = 1.1;\n// Below this local-space drag distance (on either axis), a marquee drag is\n// treated as a plain click instead — see commitMarquee.\nconst MARQUEE_MIN_DRAG = 4;\n// How far a pasted/duplicated copy is offset from its source, in the same\n// fixed 0..1000 normalized space — enough to be visibly distinct from the\n// original without landing off a typically-visible canvas area.\nconst PASTE_OFFSET = 24;\n// Arrow-key nudge step for the selection, in the same fixed 0..1000\n// normalized space — Shift+arrow moves 10x further, the common \"fine vs.\n// coarse nudge\" convention.\nconst NUDGE_STEP = 1;\nconst NUDGE_STEP_LARGE = 10;\nconst NUDGE_DELTAS = { ArrowUp: [0, -1], ArrowDown: [0, 1], ArrowLeft: [-1, 0], ArrowRight: [1, 0] };\n// A freshly-placed text box's default size/font, in the same fixed\n// 0..1000 normalized space — no auto-grow-to-fit-content or a dedicated\n// font-size control in this pass (a deliberate v1 scope cut); the box can\n// still be resized afterward via the same corner-drag every other shape\n// already supports, since a text shape's `{x,y,width,height}` is the exact\n// same shape those generic helpers already operate on.\nconst DEFAULT_TEXT_WIDTH = 220;\nconst DEFAULT_TEXT_HEIGHT = 60;\nconst DEFAULT_TEXT_FONT_SIZE = 28;\nconst MIN_TEXT_FONT_SIZE = 12;\nconst MAX_TEXT_FONT_SIZE = 96;\n\n// Snapping (toggleable via the toolbar's magnet button, on by default): a\n// plain fixed grid in the same 0..1000 normalized space — not \"snap to\n// other shapes' edges/centers\" alignment guides, which is a substantially\n// bigger feature (computing candidate lines from every other shape,\n// rendering guide lines, etc.) explicitly out of scope for this pass.\n// Applies to pointer DRAGS (draw/move/resize/rotate), which are imprecise\n// by hand — not to arrow-key nudge, which is already exact.\nconst SNAP_GRID_SIZE = 10;\nconst SNAP_ROTATION_STEP = 15;\n// The visible grid-dot spacing is coarser than SNAP_GRID_SIZE itself (a\n// dot at every actual 10-unit snap line would be a dense, unhelpful wall\n// of dots at this space's scale) — purely a visual reference for \"this is\n// what snapping aligns to,\" not a 1:1 rendering of every snap position.\nconst SNAP_GRID_VISUAL_SPACING = SNAP_GRID_SIZE * 5;\n\nfunction snapValue(v) {\n return Math.round(v / SNAP_GRID_SIZE) * SNAP_GRID_SIZE;\n}\n\nfunction snapAngle(deg) {\n return Math.round(deg / SNAP_ROTATION_STEP) * SNAP_ROTATION_STEP;\n}\n\n/**\n * One stroke's outline path is pure/deterministic from its own `points`\n * (see strokeOutline.js) — cached by stroke object identity so committing a\n * NEW stroke (or resizing the block) never recomputes every other already-\n * drawn stroke's path, only whichever ones are new. Strokes are only ever\n * appended/replaced wholesale (never mutated in place — see\n * createCanvasBlock.js's doc comment), so identity-based caching is safe.\n *\n * A `WeakMap`, not a `Map` — a long editing session's erases/undo-redo\n * cycles replace/drop stroke objects constantly, and a plain `Map` would\n * hold every one of them (and its computed path string) forever, since\n * nothing ever deleted old entries: an unbounded memory leak that grows\n * with total strokes EVER drawn in the session, not just the current\n * count. A `WeakMap` holds its keys weakly, so once a stroke is no longer\n * referenced anywhere else (dropped from `props.strokes` AND far enough\n * out of undo/redo history), its cache entry becomes collectible\n * automatically — no manual pruning needed.\n */\nfunction useStrokePathCache() {\n const cacheRef = useRef(new WeakMap());\n return (stroke) => {\n const cache = cacheRef.current;\n let path = cache.get(stroke);\n if (path === undefined) {\n path = getStrokeOutlinePath(stroke.points, { size: stroke.size });\n cache.set(stroke, path);\n }\n return path;\n };\n}\n\nfunction pointBox(x, y, r) {\n return { minX: x - r, minY: y - r, maxX: x + r, maxY: y + r };\n}\n\n/** The average client position of every currently-down touch pointer — the anchor point a two-finger pan drag tracks (see touchPanRef in CanvasBlock). */\nfunction touchCentroid(pointsMap) {\n let sumX = 0;\n let sumY = 0;\n for (const point of pointsMap.values()) {\n sumX += point.x;\n sumY += point.y;\n }\n const count = pointsMap.size || 1;\n return { x: sumX / count, y: sumY / count };\n}\n\n/**\n * Whether `(x, y)` falls within `tolerance` of the ACTUAL stroke path — its\n * real polyline segments (or, for a single-point \"dot\" stroke, that one\n * point) — rather than just its bounding box. The eraser's own hit-test\n * uses this as the final decision (after `boxesIntersect` against\n * `strokeBoundingBox` as a cheap pre-filter, since this per-segment walk is\n * more expensive): a bounding box alone is only tight for a straight\n * stroke — an L-shaped or diagonal one has real empty space inside its own\n * box that the eraser shouldn't be able to trigger on, which is exactly\n * the \"eraser erases things it never actually touched\" imprecision this\n * replaces.\n */\nfunction strokeNearPoint(stroke, x, y, tolerance) {\n const points = stroke.points;\n if (points.length === 1) {\n const [px, py] = points[0];\n return Math.hypot(x - px, y - py) <= tolerance;\n }\n for (let i = 0; i < points.length - 1; i += 1) {\n const [x1, y1] = points[i];\n const [x2, y2] = points[i + 1];\n if (pointNearSegment(x, y, x1, y1, x2, y2, tolerance)) return true;\n }\n return false;\n}\n\nconst SHAPE_TOOLS = new Set(['rectangle', 'ellipse', 'arrow', 'diamond', 'triangle', 'star']);\n\n/** Maps a polygon-based shape type to its own vertex-generator function (see shapeGeometry.js) — the one place that association lives, reused by both rendering and hit-testing. */\nconst POLYGON_POINTS_BY_TYPE = { diamond: diamondPoints, triangle: trianglePoints, star: starPoints };\n\n/** The 6 shape tools, folded into one popover (see the toolbar JSX) rather than 6 always-visible buttons — Pen/Select stay individual buttons since those are used far more often; Eraser gets its own small popover too (see ERASER_MODE_LIST) since it now has 2 modes. */\nconst SHAPE_TOOL_LIST = [\n { type: 'rectangle', label: 'Rectangle', Icon: SquareIcon },\n { type: 'ellipse', label: 'Ellipse', Icon: CircleIcon },\n { type: 'arrow', label: 'Arrow', Icon: ArrowDiagonalIcon },\n { type: 'diamond', label: 'Diamond', Icon: DiamondIcon },\n { type: 'triangle', label: 'Triangle', Icon: TriangleIcon },\n { type: 'star', label: 'Star', Icon: StarIcon },\n];\n\n/**\n * The 2 eraser modes, folded into one popover (mirroring SHAPE_TOOL_LIST's\n * own pattern). Object Eraser removes whichever WHOLE stroke/shape it\n * touches, same as a real \"select and delete.\" Precise Eraser removes only\n * the individual POINTS of a stroke it actually passes over — like a real\n * pencil eraser, it can rub out just the middle of a line and leave the\n * two remaining ends behind as separate strokes (see `splitStrokePoints`\n * and `hitTestEraserAt`'s own doc comment) — plus uses a smaller hit\n * radius (ERASER_RADIUS_PRECISE vs ERASER_RADIUS) for working close to\n * other ink. Shapes have no per-point path to partially erase, so BOTH\n * modes remove a touched shape whole — Precise mode's only difference for\n * shapes is the smaller radius.\n */\nconst ERASER_MODE_LIST = [\n { mode: 'object', label: 'Object Eraser', Icon: EraserIcon },\n { mode: 'precise', label: 'Precise Eraser', Icon: XIcon },\n];\n\n/**\n * Turns an in-progress drag draft (`{ type, x1, y1, x2, y2 }`) into the same\n * shape-object shape `ShapeElement` and a committed `props.shapes` entry\n * both use — shared by the live preview and the final commit so they're\n * guaranteed to render identically (see `normalizeRect`'s own doc comment\n * for why rectangle/ellipse always come out non-negative regardless of\n * drag direction).\n */\nfunction buildDraftShape(draft, color, strokeWidth, fillColor) {\n if (draft.type === 'arrow') {\n return { type: 'arrow', x1: draft.x1, y1: draft.y1, x2: draft.x2, y2: draft.y2, color, strokeWidth };\n }\n return { type: draft.type, ...normalizeRect(draft.x1, draft.y1, draft.x2, draft.y2), color, strokeWidth, fillColor };\n}\n\n// Generous hit-test tolerance for the arrow tool (a thin line is otherwise\n// hard to click precisely), in the same fixed 0..1000 normalized space —\n// same spirit as the eraser's own deliberately-forgiving ERASER_RADIUS.\nconst ARROW_HIT_TOLERANCE = 16;\n\n/**\n * Which shape (if any) the select tool's pointerdown landed on — walked in\n * reverse (last-drawn/topmost first) so overlapping shapes resolve to\n * whichever one visually renders on top, matching how every other \"click\n * to select\" surface behaves. Rectangle/ellipse hit-test their whole\n * bounding box (see shapeGeometry.js's own doc comment on `pointInRect`/\n * `pointInEllipse` for why — a deliberate v1 simplification for unfilled\n * shapes); arrow hit-tests a tolerance band around its line segment.\n * Diamond/triangle/star hit-test their own precise polygon (see\n * shapeGeometry.js's `pointInPolygon`) rather than falling back to the\n * bounding box — unlike a rectangle, their box has substantial area\n * outside the actual shape (e.g. a diamond's 4 corner triangles) that a\n * bounding-box test would wrongly treat as \"inside.\"\n */\nfunction hitTestOneShape(shape, x, y) {\n if (shape.type === 'arrow') {\n return pointNearSegment(x, y, shape.x1, shape.y1, shape.x2, shape.y2, ARROW_HIT_TOLERANCE);\n }\n const rect = { x: shape.x, y: shape.y, width: shape.width, height: shape.height };\n // A rotated shape is rendered rotated (see ShapeElement) but stored in\n // its own unrotated `x/y/width/height` — map the click point back into\n // that unrotated local frame (inverse rotation around the shape's own\n // center) before running the ordinary tests below, rather than teaching\n // every one of those tests about rotation individually.\n let [testX, testY] = [x, y];\n if (shape.rotation) {\n const { cx, cy } = shapeCenter(shape);\n [testX, testY] = rotatePoint(x, y, cx, cy, -shape.rotation);\n }\n const pointsFn = POLYGON_POINTS_BY_TYPE[shape.type];\n if (pointsFn) return pointInPolygon(testX, testY, pointsFn(rect));\n return shape.type === 'ellipse' ? pointInEllipse(testX, testY, rect) : pointInRect(testX, testY, rect);\n}\n\nfunction hitTestShapeAt(x, y, shapes) {\n for (let i = shapes.length - 1; i >= 0; i -= 1) {\n if (hitTestOneShape(shapes[i], x, y)) return shapes[i].id;\n }\n return null;\n}\n\n/** Translates a shape by `(dx, dy)` — used both to commit a finished move and to render its live in-progress preview. */\nfunction applyShapeOffset(shape, dx, dy) {\n if (shape.type === 'arrow') {\n return { ...shape, x1: shape.x1 + dx, y1: shape.y1 + dy, x2: shape.x2 + dx, y2: shape.y2 + dy };\n }\n return { ...shape, x: shape.x + dx, y: shape.y + dy };\n}\n\n/** A shape's own bounding box, regardless of type — used to size the selection overlay. */\nfunction shapeBoundingBox(shape) {\n if (shape.type === 'arrow') {\n return {\n x: Math.min(shape.x1, shape.x2),\n y: Math.min(shape.y1, shape.y2),\n width: Math.abs(shape.x2 - shape.x1),\n height: Math.abs(shape.y2 - shape.y1),\n };\n }\n return { x: shape.x, y: shape.y, width: shape.width, height: shape.height };\n}\n\n/** A shape's own rotation center — the midpoint of its bounding box, the same pivot `ShapeElement`'s `rotate()` transform uses. Arrows are never rotated (see the component doc comment on rotation's scope), so this is only meaningful for rect/ellipse/diamond/triangle/star. */\nfunction shapeCenter(shape) {\n const box = shapeBoundingBox(shape);\n return { cx: box.x + box.width / 2, cy: box.y + box.height / 2 };\n}\n\n/** Translates a stroke's every point by `(dx, dy)` — the multi-select move drag's own analogue of `applyShapeOffset`, used both to commit a finished group move and to render its live preview. */\nfunction applyStrokeOffset(stroke, dx, dy) {\n return { ...stroke, points: stroke.points.map(([x, y, pressure]) => [x + dx, y + dy, pressure]) };\n}\n\n/**\n * The Precise Eraser's own commit step: splits a stroke's points AROUND\n * whichever indices were erased, into one run per surviving contiguous\n * group — a real pencil-eraser \"rub out just this part\" result, not a\n * whole-stroke delete. Returns an array of point arrays (each with >=1\n * point); an empty array means every point was erased, so the stroke\n * disappears entirely. `commitErase` gives the FIRST resulting run the\n * stroke's own original id (so an edit that doesn't actually split\n * anything — erasing only from one end — doesn't need a new id) and a\n * fresh id for every additional run a split in the MIDDLE produces.\n */\nfunction splitStrokePoints(points, erasedIndices) {\n const runs = [];\n let current = [];\n for (let i = 0; i < points.length; i += 1) {\n if (erasedIndices.has(i)) {\n if (current.length > 0) runs.push(current);\n current = [];\n } else {\n current.push(points[i]);\n }\n }\n if (current.length > 0) runs.push(current);\n return runs;\n}\n\n/** A stroke's own bounding box, in the same `{x,y,width,height}` shape `shapeBoundingBox` returns (rather than strokeOutline.js's own `{minX,minY,maxX,maxY}`), so both selectable kinds share one rendering/hit-test code path. */\nfunction strokeBoxRect(stroke) {\n const box = strokeBoundingBox(stroke.points);\n return { x: box.minX, y: box.minY, width: box.maxX - box.minX, height: box.maxY - box.minY };\n}\n\n/** Either selectable kind's own bounding box, in `{x,y,width,height}` form. */\nfunction selectableBoundingBox(kind, item) {\n return kind === 'stroke' ? strokeBoxRect(item) : shapeBoundingBox(item);\n}\n\n/**\n * Resolves a multi-select id to whichever of `strokes`/`shapes` it belongs\n * to — an id may be either, since multi-select spans both arrays (see the\n * component doc comment on the \"select\" tool below).\n */\nfunction findSelectable(block, selId) {\n const strokes = block?.props?.strokes ?? [];\n const shapes = block?.props?.shapes ?? [];\n const stroke = strokes.find((s) => s.id === selId);\n if (stroke) return { kind: 'stroke', item: stroke };\n const shape = shapes.find((s) => s.id === selId);\n if (shape) return { kind: 'shape', item: shape };\n return null;\n}\n\n/**\n * Which stroke or shape (if any) the select tool's pointerdown landed on —\n * walks the SAME merged bottom-to-top order rendering uses (`orderedDrawables`,\n * see zOrder.js), topmost first, so overlapping items resolve to whichever\n * one is actually visible on top, regardless of whether it's a stroke or a\n * shape. Strokes hit-test their own bounding box — the same deliberate v1\n * simplification rectangle/ellipse click-select already uses, not\n * per-point path distance.\n */\nfunction hitTestSelectableAt(x, y, strokes, shapes) {\n const ordered = orderedDrawables(strokes, shapes);\n for (let i = ordered.length - 1; i >= 0; i -= 1) {\n const { kind, item } = ordered[i];\n if (kind === 'shape') {\n if (hitTestOneShape(item, x, y)) return { kind: 'shape', id: item.id };\n } else if (pointInRect(x, y, strokeBoxRect(item))) {\n return { kind: 'stroke', id: item.id };\n }\n }\n return null;\n}\n\n// Generous hit radius for grabbing a resize/endpoint handle, and its own\n// visual size — both in the same fixed 0..1000 normalized space everything\n// else here uses (so handles scale naturally with zoom, same as stroke\n// widths already do).\nconst HANDLE_HIT_RADIUS = 24;\nconst HANDLE_VISUAL_SIZE = 14;\n\n/** The 4 corner points of a rectangle/ellipse shape's own bounding box, keyed by compass corner. */\nfunction rectCorners(shape) {\n return {\n nw: [shape.x, shape.y],\n ne: [shape.x + shape.width, shape.y],\n sw: [shape.x, shape.y + shape.height],\n se: [shape.x + shape.width, shape.y + shape.height],\n };\n}\n\nconst OPPOSITE_CORNER = { nw: 'se', ne: 'sw', sw: 'ne', se: 'nw' };\n\n// How far above the shape's own (unrotated) top edge the rotate handle\n// floats, in the same fixed 0..1000 normalized space as everything else.\nconst ROTATE_HANDLE_OFFSET = 32;\n\n/**\n * The rotate handle's own position — a fixed distance above the shape's\n * unrotated bounding-box top-center, then rotated around the shape's own\n * center by its current `rotation` so the handle visually stays attached\n * as the shape spins (same \"computed from stored state, not itself stored\"\n * principle as arrowheadPoints). Arrows are never rotated (see the\n * component doc comment on rotation's scope), so this is only meaningful\n * for rect/ellipse/diamond/triangle/star.\n */\nfunction rotateHandlePoint(shape) {\n const box = shapeBoundingBox(shape);\n const localX = box.x + box.width / 2;\n const localY = box.y - ROTATE_HANDLE_OFFSET;\n if (!shape.rotation) return [localX, localY];\n const { cx, cy } = shapeCenter(shape);\n return rotatePoint(localX, localY, cx, cy, shape.rotation);\n}\n\n/**\n * Which resize/endpoint/rotate handle (if any) `(x, y)` landed on, for the\n * CURRENTLY SELECTED shape only (handles for every other shape are neither\n * rendered nor hit-tested) — checked before the general\n * `hitTestShapeAt` body hit-test, so grabbing a handle always takes\n * priority over re-selecting/moving the shape it belongs to. The rotate\n * handle is checked first since it sits outside the shape's own bounding\n * box, never overlapping a corner handle. Corner resize handles are hidden\n * (and un-hit-testable) once a shape has any rotation — see the component\n * doc comment on rotation's scope: no rotated-resize math in this pass.\n */\nfunction hitTestHandle(x, y, shape) {\n if (!shape) return null;\n if (shape.type === 'arrow') {\n if (Math.hypot(x - shape.x1, y - shape.y1) <= HANDLE_HIT_RADIUS) return 'start';\n if (Math.hypot(x - shape.x2, y - shape.y2) <= HANDLE_HIT_RADIUS) return 'end';\n return null;\n }\n const [rhx, rhy] = rotateHandlePoint(shape);\n if (Math.hypot(x - rhx, y - rhy) <= HANDLE_HIT_RADIUS) return 'rotate';\n if (shape.rotation) return null;\n for (const [corner, [cx, cy]] of Object.entries(rectCorners(shape))) {\n if (Math.hypot(x - cx, y - cy) <= HANDLE_HIT_RADIUS) return corner;\n }\n return null;\n}\n\n/**\n * Builds the live (or final, at commit time) resized/endpoint-dragged/\n * rotated shape from an in-progress resize draft — `normalizeRect` (the\n * same function that turns a fresh rectangle/ellipse drag into a valid\n * box, see `buildDraftShape`) does the real work for the corner-drag case:\n * dragging ANY corner is just \"normalize a box between the fixed opposite\n * corner and wherever the pointer currently is,\" so no separate per-corner\n * math is needed. The rotate case just reuses whatever angle\n * `handlePointerMove` already computed onto the draft (see its own\n * 'rotate'-mode branch) — this function's only job there is picking it off\n * the draft into the shape.\n */\nfunction buildResizedShape(shape, draft) {\n if (draft.mode === 'arrow-endpoint') {\n return draft.endpoint === 'start' ? { ...shape, x1: draft.x, y1: draft.y } : { ...shape, x2: draft.x, y2: draft.y };\n }\n if (draft.mode === 'rotate') {\n return { ...shape, rotation: draft.rotation };\n }\n return { ...shape, ...normalizeRect(draft.fixedX, draft.fixedY, draft.x, draft.y) };\n}\n\n/**\n * Renders one shape (rectangle, ellipse, arrow, text, or a polygon type) —\n * reused for both a committed `props.shapes` entry and the in-progress\n * drag preview, so the live preview and the final render are guaranteed to\n * look identical (same component, same props shape). `fillColor` (rect/\n * ellipse/diamond/triangle/star only) defaults to `fill=\"none\"` when unset\n * — arrows have no fill of their own (their arrowhead polygon is always\n * solid-filled with the stroke color, not a separate fill), and text uses\n * `color` for its own text color rather than a fill. A non-zero `rotation`\n * (rect/ellipse/diamond/triangle/star/text — arrows are never rotated, see\n * the component doc comment on rotation's scope) wraps the shape in a `<g>`\n * with an SVG `rotate()` transform around its own bounding-box center — the\n * exact pivot `shapeCenter`/`rotatePoint`-based hit-testing and the rotate\n * handle's own position both use, so click-select and the handle stay\n * visually in sync with what this renders.\n */\nfunction ShapeElement({ shape, opacity = 1 }) {\n const strokeWidth = shape.strokeWidth ?? DEFAULT_STROKE_SIZE;\n let content;\n if (shape.type === 'rectangle') {\n content = (\n <rect\n x={shape.x}\n y={shape.y}\n width={shape.width}\n height={shape.height}\n fill={shape.fillColor ?? 'none'}\n stroke={shape.color}\n strokeWidth={strokeWidth}\n opacity={opacity}\n />\n );\n } else if (shape.type === 'ellipse') {\n content = (\n <ellipse\n cx={shape.x + shape.width / 2}\n cy={shape.y + shape.height / 2}\n rx={shape.width / 2}\n ry={shape.height / 2}\n fill={shape.fillColor ?? 'none'}\n stroke={shape.color}\n strokeWidth={strokeWidth}\n opacity={opacity}\n />\n );\n } else if (shape.type === 'arrow') {\n const headSize = Math.max(16, strokeWidth * 3);\n const head = arrowheadPoints(shape.x1, shape.y1, shape.x2, shape.y2, headSize);\n return (\n <g opacity={opacity}>\n <line x1={shape.x1} y1={shape.y1} x2={shape.x2} y2={shape.y2} stroke={shape.color} strokeWidth={strokeWidth} />\n <polygon points={head.map(([x, y]) => `${x},${y}`).join(' ')} fill={shape.color} />\n </g>\n );\n } else if (shape.type === 'text') {\n // A <foreignObject> + plain HTML <div> gets real browser text\n // wrapping/line-breaking for free — reimplementing that in raw SVG\n // <text>/<tspan> layout is a lot of work for no benefit here. No\n // auto-grow-to-fit: overflow is clipped to the box, same \"resize the\n // box yourself\" convention as every other shape's fixed bounding box.\n content = (\n <foreignObject x={shape.x} y={shape.y} width={shape.width} height={shape.height} opacity={opacity}>\n <div\n // eslint-disable-next-line react/no-unknown-property\n xmlns=\"http://www.w3.org/1999/xhtml\"\n style={{\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n color: shape.color,\n fontSize: shape.fontSize ?? DEFAULT_TEXT_FONT_SIZE,\n lineHeight: 1.3,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n fontFamily: 'inherit',\n }}\n >\n {shape.text}\n </div>\n </foreignObject>\n );\n } else {\n const pointsFn = POLYGON_POINTS_BY_TYPE[shape.type];\n if (!pointsFn) return null;\n const rect = { x: shape.x, y: shape.y, width: shape.width, height: shape.height };\n const points = pointsFn(rect)\n .map(([x, y]) => `${x},${y}`)\n .join(' ');\n content = (\n <polygon points={points} fill={shape.fillColor ?? 'none'} stroke={shape.color} strokeWidth={strokeWidth} opacity={opacity} />\n );\n }\n if (!shape.rotation) return content;\n const { cx, cy } = shapeCenter(shape);\n return <g transform={`rotate(${shape.rotation} ${cx} ${cy})`}>{content}</g>;\n}\n\n/**\n * A pure \"widget\" block — no runs/text at all (contentIds always []), same\n * shape as DividerBlock/EmbedBlock — so it participates in cross-block\n * select/copy/cut/delete for free via the exact same generic mechanisms\n * those already exercise (see `src/blocks/shared/contentless.js`): a\n * canvas block backspaced-into from a neighboring paragraph behaves exactly\n * like an image/divider would, with zero canvas-specific code needed for\n * that lifecycle.\n *\n * Renders every committed stroke as one filled `<path>` (see\n * strokeOutline.js) inside an SVG whose `viewBox` is the fixed logical\n * VIEW_SIZE space and whose `width`/`height` attributes are the block's own\n * rendered pixel size (`props.width`/`props.height`).\n *\n * Both tools below share the same \"local state/refs during the gesture,\n * exactly ONE store write on release\" discipline (mirroring EmbedBlock.jsx's\n * resize-drag convention, adapted to native Pointer Events +\n * `setPointerCapture` instead of document-level mouse listeners):\n *\n * - **Pen** (Phase 2): raw `[x, y, pressure]` points accumulate in\n * `pointsRef` on every `pointermove` — a plain ref mutation, never itself\n * a React state update or a store write. The in-progress stroke's visual\n * preview updates only via a `requestAnimationFrame`-throttled\n * `previewPath` state (capped at ~60 recomputes/sec regardless of\n * pointermove frequency). `pointerup` makes the one real commit: appends\n * the finished stroke via `updateBlockProps`.\n * - **Eraser** (Phase 3): whole-object removal (strokes AND shapes alike),\n * not pixel erasing — 2 selectable modes (see ERASER_MODE_LIST) share\n * this whole discipline and differ only in hit radius. Each pointermove\n * hit-tests the eraser's small local radius against every not-yet-erased\n * stroke's ACTUAL path (`strokeNearPoint`, walking its real segments —\n * not just its bounding box, which a diagonal or L-shaped stroke has real\n * empty space inside of) and every not-yet-erased shape's bounding box,\n * marking touched ids in `erasedStrokeIdsRef`/`erasedShapeIdsRef` (refs,\n * not store writes) — a cheap `boxesIntersect` bounding-box pre-filter\n * (see strokeOutline.js's `strokeBoundingBox`) skips the more expensive\n * per-segment walk for strokes nowhere near the eraser at all. The\n * rAF-throttled `erasingIds`/`erasingShapeIds` state only drives a live\n * fade-out preview. `pointerup` makes the one commit: `strokes` AND\n * `shapes` each filtered to drop every touched id, in a single\n * `updateBlockProps` call — a whole erase drag removing N objects is\n * still just one undo step, same discipline as pen.\n *\n * Pan/zoom (Phase 5) is plain LOCAL component state (`view`), never written\n * through `updateBlockProps` and never undo-tracked — it's a viewport\n * preference (\"where am I currently looking\"), not document content, the\n * same reasoning as why no block in this codebase persists a scroll\n * position. Applied purely via the `<svg>`'s own `viewBox` attribute, so\n * stroke coordinates themselves are never touched by panning/zooming.\n * Zoom is Ctrl/Cmd+wheel — also how a trackpad OR touchscreen pinch\n * gesture reports itself. Pan is: a middle-mouse-button drag (a plain,\n * always-available gesture that doesn't depend on which tool is currently\n * active or on keyboard focus, unlike a space-bar-held convention would);\n * a plain (non-ctrl) wheel, i.e. a trackpad's two-finger scroll; or two\n * fingers dragging on a touchscreen (see touchPanRef/cancelActiveSingleGesture) —\n * the latter takes over from whatever the first finger alone had already\n * started (drawing, erasing, ...) the instant a second finger touches down.\n */\nexport function CanvasBlock({ id }) {\n const store = useEditorStore();\n const block = useBlock(id);\n const className = useBlockClassName('be-canvas', block);\n const getStrokePath = useStrokePathCache();\n\n const [tool, setTool] = useState('pen'); // 'pen' | 'eraser' | 'select' | 'text' | one of SHAPE_TOOLS — ephemeral UI state, not persisted (same reasoning as pan/zoom: an authoring detail, not document content)\n // Which eraser mode is active (see ERASER_MODE_LIST/ERASER_RADIUS*'s own\n // doc comments) — remembered the same way `lastShapeTool` is, so the\n // Eraser popover's trigger button always shows a meaningful icon.\n const [eraserMode, setEraserMode] = useState('object');\n const [color, setColor] = useState(DEFAULT_COLOR);\n const [strokeSize, setStrokeSize] = useState(DEFAULT_STROKE_SIZE);\n // Fill color for NEW rect/ellipse/diamond/triangle/star shapes — `null`\n // means \"no fill\" (`fill=\"none\"`, today's only behavior before this\n // control existed, and still the default). Arrows have no fill (they're\n // inherently linear) and text uses `color` for its own text color, so\n // neither reads this. Same \"tool default, not retroactive to an already-\n // selected shape\" scope as `color`/`strokeSize` — changing it only\n // affects shapes drawn from then on.\n const [fill, setFill] = useState(null);\n // Grid snapping, on by default — toggled via the toolbar's magnet\n // button. Ephemeral UI state, not persisted, same reasoning as `tool`.\n const [snapEnabled, setSnapEnabled] = useState(true);\n // Font size for the text tool — same \"tool default for the NEXT new\n // box\" scope as color/strokeSize/fill, EXCEPT while a text box is\n // actively being edited (`textEditDraft` set): the size picker's\n // onChange then also live-updates that draft's own fontSize directly\n // (see its JSX below), since seeing the effect immediately while typing\n // is far more useful than only affecting boxes placed afterward.\n const [textFontSize, setTextFontSize] = useState(DEFAULT_TEXT_FONT_SIZE);\n // Remembers whichever shape tool was picked most recently, so the shape\n // popover's own trigger button can show a meaningful icon (and so\n // re-clicking a would-be \"repeat last shape\" affordance would have\n // something to repeat) even while Pen/Eraser/Select is the active tool.\n const [lastShapeTool, setLastShapeTool] = useState('rectangle');\n\n // Color/size/shape pickers: small inline popovers (position:relative\n // wrapper + position:absolute popover, same convention as\n // FloatingToolbar's own text-color/highlight pickers) rather than a\n // portaled menu — these are small pickers anchored to a toolbar that's\n // always already inside the document's normal flow, not a standalone\n // floating menu that needs viewport-overflow handling of its own.\n const [isColorPickerOpen, setIsColorPickerOpen] = useState(false);\n const [isFillPickerOpen, setIsFillPickerOpen] = useState(false);\n const [isSizePickerOpen, setIsSizePickerOpen] = useState(false);\n const [isShapePickerOpen, setIsShapePickerOpen] = useState(false);\n const [isFontSizePickerOpen, setIsFontSizePickerOpen] = useState(false);\n const [isEraserPickerOpen, setIsEraserPickerOpen] = useState(false);\n const colorTriggerRef = useRef(null);\n const colorPopoverRef = useRef(null);\n const fillTriggerRef = useRef(null);\n const fillPopoverRef = useRef(null);\n const sizeTriggerRef = useRef(null);\n const sizePopoverRef = useRef(null);\n const shapeTriggerRef = useRef(null);\n const shapePopoverRef = useRef(null);\n const fontSizeTriggerRef = useRef(null);\n const fontSizePopoverRef = useRef(null);\n const eraserTriggerRef = useRef(null);\n const eraserPopoverRef = useRef(null);\n const colorRefs = useMemo(() => [colorTriggerRef, colorPopoverRef], []);\n const fillRefs = useMemo(() => [fillTriggerRef, fillPopoverRef], []);\n const sizeRefs = useMemo(() => [sizeTriggerRef, sizePopoverRef], []);\n const shapeRefs = useMemo(() => [shapeTriggerRef, shapePopoverRef], []);\n const fontSizeRefs = useMemo(() => [fontSizeTriggerRef, fontSizePopoverRef], []);\n const eraserRefs = useMemo(() => [eraserTriggerRef, eraserPopoverRef], []);\n const closeColorPicker = useCallback(() => setIsColorPickerOpen(false), []);\n const closeFillPicker = useCallback(() => setIsFillPickerOpen(false), []);\n const closeSizePicker = useCallback(() => setIsSizePickerOpen(false), []);\n const closeShapePicker = useCallback(() => setIsShapePickerOpen(false), []);\n const closeFontSizePicker = useCallback(() => setIsFontSizePickerOpen(false), []);\n const closeEraserPicker = useCallback(() => setIsEraserPickerOpen(false), []);\n useOutsideClickAndEscape(colorRefs, isColorPickerOpen, closeColorPicker);\n useOutsideClickAndEscape(fillRefs, isFillPickerOpen, closeFillPicker);\n useOutsideClickAndEscape(sizeRefs, isSizePickerOpen, closeSizePicker);\n useOutsideClickAndEscape(shapeRefs, isShapePickerOpen, closeShapePicker);\n useOutsideClickAndEscape(fontSizeRefs, isFontSizePickerOpen, closeFontSizePicker);\n useOutsideClickAndEscape(eraserRefs, isEraserPickerOpen, closeEraserPicker);\n\n const svgRef = useRef(null);\n const pointsRef = useRef([]);\n const drawingRef = useRef(false);\n const rafRef = useRef(null);\n const [previewPath, setPreviewPath] = useState(null);\n\n // Separate sets for strokes vs. shapes — both kinds are erasable (in\n // either mode), but live in different `props` arrays, so touched ids\n // need to be tracked (and later filtered out) per kind.\n const erasedStrokeIdsRef = useRef(new Set());\n const erasedShapeIdsRef = useRef(new Set());\n // Precise Eraser only: which POINT INDICES within each touched stroke\n // were erased — Object Eraser never touches this, it only ever removes\n // whole strokes/shapes via the two Sets above. Shapes have no per-point\n // path to partially erase, so Precise mode still removes a touched shape\n // whole (via erasedShapeIdsRef, just with the smaller radius) — a\n // deliberate, unavoidable-given-the-data-model scope decision.\n const erasedPointIndicesRef = useRef(new Map());\n const erasingRef = useRef(false);\n const eraseRafRef = useRef(null);\n const [erasingIds, setErasingIds] = useState(() => new Set());\n const [erasingShapeIds, setErasingShapeIds] = useState(() => new Set());\n\n // Shape tools (rectangle/ellipse/arrow): same \"ref buffer during the\n // drag, one commit on pointerup\" discipline as the pen tool, but no rAF\n // throttling is needed here — a shape's live preview is 4-6 numbers, not\n // hundreds of accumulated points, cheap enough to update on every\n // pointermove directly.\n const shapeDraftRef = useRef(null); // { type, x1, y1, x2, y2 } | null\n const [shapeDraftPreview, setShapeDraftPreview] = useState(null);\n\n // Select tool: which strokes/shapes are selected is local, ephemeral UI\n // state, not persisted (same reasoning as `tool`/`view` — an authoring\n // detail, not document content). An id may resolve to either\n // `props.strokes` or `props.shapes` — see `findSelectable` above.\n // `moveDraftRef` mirrors every other gesture's own \"authoritative ref,\n // state only for the visual preview\" split — `dx`/`dy` are mutated\n // directly on every pointermove so `commitMove` always reads the\n // up-to-date total offset synchronously, without waiting on React state\n // to flush.\n const [selectedIds, setSelectedIds] = useState(() => new Set());\n const moveDraftRef = useRef(null); // { ids: string[], startX, startY, dx, dy } | null\n const [moveOverride, setMoveOverride] = useState(null); // { ids: string[], dx, dy } | null\n\n // Marquee (rubber-band) drag: starting a click-drag on empty space\n // selects every stroke/shape whose bounding box intersects the dragged\n // rectangle, replacing the previous selection — an empty-result marquee\n // (e.g. a near-zero-drag click) clears the selection, which is how\n // \"click empty space to deselect\" falls out of this as a special case\n // rather than a separate code path.\n const marqueeDraftRef = useRef(null); // { startX, startY, x, y } | null (local space)\n const [marqueeRect, setMarqueeRect] = useState(null); // {x,y,width,height} | null, local space\n\n // Copy/paste/duplicate (Ctrl/Cmd+C / Ctrl/Cmd+V / Ctrl/Cmd+D): an\n // in-memory clipboard, not the OS clipboard — this editor has no other\n // block that round-trips through the system clipboard for its own\n // internal structured data either (see useClipboardHandlers.js's own\n // text/HTML-only scope), and an internal ref avoids needing\n // `navigator.clipboard` permissions for what's purely an in-block\n // operation. Holds the ORIGINAL (unshifted) items so every repeated paste\n // offsets from the same source, not cumulatively from the last paste.\n const clipboardRef = useRef([]); // Array<{ kind: 'stroke'|'shape', item }>\n\n // Text tool: unlike every other shape, a text box needs a live text-input\n // surface, not just a drag gesture — this local draft holds whatever's\n // currently being typed (a NEW box, or re-editing an EXISTING committed\n // one), rendered as its own <foreignObject><textarea> overlay (see the\n // JSX below), completely separate from the plain, non-editable\n // `<foreignObject><div>` `ShapeElement` renders for every already-\n // committed text shape. Nothing is written to the store until the\n // textarea blurs/commits — same \"local draft, one commit\" discipline as\n // every other tool here.\n const [textEditDraft, setTextEditDraft] = useState(null); // { id: string|null, x, y, width, height, text, color, fontSize } | null — id is null for a brand-new (not-yet-committed) box\n\n // Resize (rectangle/ellipse corner drag) + endpoint-drag (arrow) — same\n // ref-is-authoritative/state-is-preview split as move. `resizeDraftRef`'s\n // `mode` is `'rect-corner'` (`fixedX`/`fixedY` pin the OPPOSITE corner,\n // `x`/`y` track the pointer) or `'arrow-endpoint'` (`endpoint` says which\n // of the two points is being dragged).\n const resizeDraftRef = useRef(null);\n const [resizePreviewShape, setResizePreviewShape] = useState(null);\n\n // Pan/zoom (Phase 5): local view-only state, see the doc comment above —\n // never touches block.props or the store.\n const [view, setView] = useState({ x: 0, y: 0, zoom: 1 });\n const viewSize = VIEW_SIZE / view.zoom;\n const panRef = useRef(null); // { startClientX, startClientY, startViewX, startViewY } | null\n // Two-finger touch pan: every currently-down TOUCH pointer, keyed by its\n // own pointerId -> last known client position — tracked so a second\n // finger landing mid-gesture can compute the two-touch centroid right\n // away, and so a still-down finger's position stays current while the\n // OTHER finger is the one moving. `touchPanRef` (set once 2+ fingers are\n // down) mirrors `panRef` above almost exactly — same view-delta math,\n // just anchored to the two-touch centroid instead of one mouse position\n // — so a two-finger drag pans the exact same `view` state the middle-\n // mouse-drag pan and Ctrl/Cmd+wheel zoom already share. Pinch-zoom itself\n // stays entirely on the existing `handleWheel` path (trackpad AND\n // touchscreen pinch both reach it as a synthesized ctrl+wheel event) —\n // this only adds the PAN gesture that path has no way to express.\n const touchPointsRef = useRef(new Map()); // pointerId -> { x, y } (client coords)\n const touchPanRef = useRef(null); // { startCenterX, startCenterY, startViewX, startViewY } | null\n\n // Resize (Phase 4): existing strokes never need rescaling here — they're\n // authored in the fixed 0..1000 normalized space (see VIEW_SIZE above),\n // completely decoupled from the SVG's own rendered pixel size, so\n // dragging the handle is purely \"change how big this is drawn.\"\n const { dragValue: dragSize, startDrag: startResize } = useDragResize({\n compute: (event, start) => ({\n width: Math.max(MIN_CANVAS_WIDTH, Math.round(start.startWidth + (event.clientX - start.startX))),\n height: Math.max(MIN_CANVAS_HEIGHT, Math.round(start.startHeight + (event.clientY - start.startY))),\n }),\n onCommit: (size) => store.applyOperation(updateBlockProps(id, size)),\n });\n\n const schedulePreviewUpdate = useCallback((size) => {\n if (rafRef.current != null) return; // already scheduled for this frame — pointermove just adds more points to the same buffer\n rafRef.current = requestAnimationFrame(() => {\n rafRef.current = null;\n setPreviewPath(getStrokeOutlinePath(pointsRef.current, { size }));\n });\n }, []);\n\n const stopDrawing = useCallback(() => {\n drawingRef.current = false;\n if (rafRef.current != null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n pointsRef.current = [];\n setPreviewPath(null);\n }, []);\n\n const commitStroke = useCallback(() => {\n const points = pointsRef.current;\n if (points.length === 0) return;\n // A tap-without-drag still commits a single-point stroke — getStrokeOutlinePath\n // itself renders a single point as a small filled \"dot\", so no special-casing\n // is needed here beyond just storing whatever points were captured.\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n const newStroke = { id: genId(), points, color, size: strokeSize, z: nextZIndex(currentStrokes, currentShapes) };\n store.applyOperation(updateBlockProps(id, { strokes: [...currentStrokes, newStroke] }));\n }, [store, id, block, color, strokeSize]);\n\n const scheduleErasingPreview = useCallback(() => {\n if (eraseRafRef.current != null) return;\n eraseRafRef.current = requestAnimationFrame(() => {\n eraseRafRef.current = null;\n setErasingIds(new Set(erasedStrokeIdsRef.current));\n setErasingShapeIds(new Set(erasedShapeIdsRef.current));\n });\n }, []);\n\n /**\n * Erases whatever the eraser (radius set by `eraserMode` — see\n * ERASER_RADIUS/ERASER_RADIUS_PRECISE's doc comment) touches. Shapes are\n * always whole-object (a plain bounding-box-vs-eraser-circle test for\n * every type — the same \"click anywhere in the box\" simplification\n * rectangle/ellipse click-select already uses). Strokes differ by mode:\n * Object Eraser marks the WHOLE stroke touched (via the precise\n * per-segment `strokeNearPoint` check, after a cheap bounding-box\n * pre-filter) for a later whole-stroke removal in `commitErase`; Precise\n * Eraser instead marks just the individual POINT INDICES that fall\n * within its (smaller) radius, for a later partial split.\n */\n const hitTestEraserAt = useCallback(\n (x, y) => {\n const radius = eraserMode === 'precise' ? ERASER_RADIUS_PRECISE : ERASER_RADIUS;\n const eraserBox = pointBox(x, y, radius);\n const strokes = block?.props?.strokes ?? [];\n for (const stroke of strokes) {\n if (eraserMode === 'precise') {\n const box = strokeBoundingBox(stroke.points);\n if (!boxesIntersect(box, eraserBox, stroke.size / 2)) continue; // cheap reject before the per-point walk\n let indices = erasedPointIndicesRef.current.get(stroke.id);\n stroke.points.forEach(([px, py], i) => {\n if (indices?.has(i)) return;\n if (Math.hypot(px - x, py - y) > radius) return;\n if (!indices) {\n indices = new Set();\n erasedPointIndicesRef.current.set(stroke.id, indices);\n }\n indices.add(i);\n });\n if (indices?.size) erasedStrokeIdsRef.current.add(stroke.id); // preview-only flag, not a whole-stroke delete in this mode\n continue;\n }\n if (erasedStrokeIdsRef.current.has(stroke.id)) continue;\n const padding = stroke.size / 2;\n const box = strokeBoundingBox(stroke.points);\n if (!boxesIntersect(box, eraserBox, padding)) continue; // cheap reject before the precise per-segment check\n if (strokeNearPoint(stroke, x, y, radius + padding)) erasedStrokeIdsRef.current.add(stroke.id);\n }\n const shapes = block?.props?.shapes ?? [];\n for (const shape of shapes) {\n if (erasedShapeIdsRef.current.has(shape.id)) continue;\n const box = shapeBoundingBox(shape);\n const shapeBox = { minX: box.x, minY: box.y, maxX: box.x + box.width, maxY: box.y + box.height };\n if (boxesIntersect(shapeBox, eraserBox)) erasedShapeIdsRef.current.add(shape.id);\n }\n scheduleErasingPreview();\n },\n [block, eraserMode, scheduleErasingPreview],\n );\n\n const stopErasing = useCallback(() => {\n erasingRef.current = false;\n if (eraseRafRef.current != null) {\n cancelAnimationFrame(eraseRafRef.current);\n eraseRafRef.current = null;\n }\n erasedStrokeIdsRef.current = new Set();\n erasedShapeIdsRef.current = new Set();\n erasedPointIndicesRef.current = new Map();\n setErasingIds(new Set());\n setErasingShapeIds(new Set());\n }, []);\n\n const commitErase = useCallback(() => {\n const hasWholeStrokeErase = eraserMode !== 'precise' && erasedStrokeIdsRef.current.size > 0;\n const hasPartialErase = eraserMode === 'precise' && erasedPointIndicesRef.current.size > 0;\n if (!hasWholeStrokeErase && !hasPartialErase && erasedShapeIdsRef.current.size === 0) return;\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n let nextStrokes;\n if (hasWholeStrokeErase) {\n nextStrokes = currentStrokes.filter((stroke) => !erasedStrokeIdsRef.current.has(stroke.id));\n } else if (hasPartialErase) {\n nextStrokes = [];\n for (const stroke of currentStrokes) {\n const erasedIndices = erasedPointIndicesRef.current.get(stroke.id);\n if (!erasedIndices || erasedIndices.size === 0) {\n nextStrokes.push(stroke);\n continue;\n }\n splitStrokePoints(stroke.points, erasedIndices).forEach((points, i) => {\n nextStrokes.push({ ...stroke, id: i === 0 ? stroke.id : genId(), points });\n });\n }\n } else {\n nextStrokes = currentStrokes;\n }\n // Touching both arrays together (an erase drag can sweep up strokes\n // and shapes alike) is still exactly one undo step.\n store.applyOperation(\n updateBlockProps(id, {\n strokes: nextStrokes,\n shapes: currentShapes.filter((shape) => !erasedShapeIdsRef.current.has(shape.id)),\n }),\n );\n }, [store, id, block, eraserMode]);\n\n const stopShapeDraft = useCallback(() => {\n shapeDraftRef.current = null;\n setShapeDraftPreview(null);\n }, []);\n\n const commitShapeDraft = useCallback(() => {\n const draft = shapeDraftRef.current;\n if (!draft) return;\n // A click-without-drag draws nothing (a zero-size rectangle/ellipse or a\n // zero-length arrow is a pointless, invisible shape) — same \"no-op is\n // fine\" choice the resize handle makes for a non-drag click, distinct\n // from the pen tool's own tap-still-draws-a-dot behavior, since a dot\n // is a real intentional mark and a degenerate shape is not.\n if (draft.type === 'arrow') {\n if (draft.x1 === draft.x2 && draft.y1 === draft.y2) return;\n } else {\n const rect = normalizeRect(draft.x1, draft.y1, draft.x2, draft.y2);\n if (rect.width === 0 || rect.height === 0) return;\n }\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n const newShape = {\n id: genId(),\n ...buildDraftShape(draft, color, strokeSize, fill),\n z: nextZIndex(currentStrokes, currentShapes),\n };\n store.applyOperation(updateBlockProps(id, { shapes: [...currentShapes, newShape] }));\n }, [store, id, block, color, strokeSize, fill]);\n\n const stopMove = useCallback(() => {\n moveDraftRef.current = null;\n setMoveOverride(null);\n }, []);\n\n const commitMove = useCallback(() => {\n const draft = moveDraftRef.current;\n if (!draft) return;\n if (draft.dx === 0 && draft.dy === 0) return; // a click-without-drag on an already-selected item is just a (re-)selection, nothing to commit\n const idSet = new Set(draft.ids);\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n const nextStrokes = currentStrokes.map((stroke) =>\n idSet.has(stroke.id) ? applyStrokeOffset(stroke, draft.dx, draft.dy) : stroke,\n );\n const nextShapes = currentShapes.map((shape) =>\n idSet.has(shape.id) ? applyShapeOffset(shape, draft.dx, draft.dy) : shape,\n );\n // Touching both arrays together (a selection can span strokes and\n // shapes) is still exactly one undo step — updateBlockProps already\n // shallow-merges multiple prop keys from a single op.\n store.applyOperation(updateBlockProps(id, { strokes: nextStrokes, shapes: nextShapes }));\n }, [store, id, block]);\n\n const stopMarquee = useCallback(() => {\n marqueeDraftRef.current = null;\n setMarqueeRect(null);\n }, []);\n\n const commitMarquee = useCallback(() => {\n const draft = marqueeDraftRef.current;\n if (!draft) return;\n const rect = normalizeRect(draft.startX, draft.startY, draft.x, draft.y);\n // A near-zero drag is a plain click, not a rubber-band selection — treat\n // it as \"clicked empty space\" (clear the selection) rather than running\n // a bounding-box intersection test, which would wrongly catch whatever\n // bounding box the click point happens to fall inside even when the\n // precise click-select hit-test (hitTestSelectableAt) already said no\n // (e.g. inside a diamond's bounding box corner but outside the diamond\n // itself).\n if (rect.width < MARQUEE_MIN_DRAG && rect.height < MARQUEE_MIN_DRAG) {\n setSelectedIds(new Set());\n return;\n }\n const marqueeBox = { minX: rect.x, minY: rect.y, maxX: rect.x + rect.width, maxY: rect.y + rect.height };\n const strokes = block?.props?.strokes ?? [];\n const shapes = block?.props?.shapes ?? [];\n const hitIds = [];\n for (const stroke of strokes) {\n if (boxesIntersect(strokeBoundingBox(stroke.points), marqueeBox)) hitIds.push(stroke.id);\n }\n for (const shape of shapes) {\n const box = shapeBoundingBox(shape);\n const shapeBox = { minX: box.x, minY: box.y, maxX: box.x + box.width, maxY: box.y + box.height };\n if (boxesIntersect(shapeBox, marqueeBox)) hitIds.push(shape.id);\n }\n setSelectedIds(new Set(hitIds)); // replaces the previous selection; an empty result clears it\n }, [block]);\n\n const copySelection = useCallback(() => {\n if (selectedIds.size === 0) return;\n clipboardRef.current = [...selectedIds].map((selId) => findSelectable(block, selId)).filter(Boolean);\n }, [block, selectedIds]);\n\n /**\n * Inserts one fresh (regenerated-id, offset-by-PASTE_OFFSET) copy of\n * every clipboard entry, in one `updateBlockProps` call spanning both\n * arrays — a paste of a mixed stroke+shape selection is still one undo\n * step, same discipline as group move/delete. The new copies become the\n * selection, so an immediate drag can reposition them, and the tool\n * switches to `select` so that drag is available regardless of whichever\n * tool was active when paste/duplicate was pressed.\n */\n const pasteClipboard = useCallback(() => {\n const items = clipboardRef.current;\n if (items.length === 0) return;\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n // Pasted copies always land on top of everything already on the canvas\n // (nextZIndex, bumped once per item so the pasted group also keeps its\n // OWN relative stacking order among each other).\n let nextZ = nextZIndex(currentStrokes, currentShapes);\n const newStrokes = [];\n const newShapes = [];\n const newIds = [];\n for (const { kind, item } of items) {\n const newId = genId();\n newIds.push(newId);\n const z = nextZ;\n nextZ += 1;\n if (kind === 'stroke') {\n newStrokes.push({ ...applyStrokeOffset(item, PASTE_OFFSET, PASTE_OFFSET), id: newId, z });\n } else {\n newShapes.push({ ...applyShapeOffset(item, PASTE_OFFSET, PASTE_OFFSET), id: newId, z });\n }\n }\n store.applyOperation(\n updateBlockProps(id, { strokes: [...currentStrokes, ...newStrokes], shapes: [...currentShapes, ...newShapes] }),\n );\n setSelectedIds(new Set(newIds));\n setTool('select');\n }, [store, id, block]);\n\n /**\n * Z-order (front/back): strokes and shapes share one interleaved stacking\n * order (see zOrder.js) — this stamps a fresh, consecutive `z` on every\n * selected item, all above (front) or below (back) everything else on the\n * canvas, in whatever bottom-to-top order the selected items themselves\n * were already in — the standard \"bring to front\"/\"send to back\"\n * behavior for a multi-item selection, now spanning strokes and shapes\n * alike instead of each kind's own array independently.\n */\n const reorderSelection = useCallback(\n (toFront) => {\n if (selectedIds.size === 0) return;\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n const selectedStrokes = currentStrokes.filter((item) => selectedIds.has(item.id));\n const selectedShapes = currentShapes.filter((item) => selectedIds.has(item.id));\n const selectedOrdered = orderedDrawables(selectedStrokes, selectedShapes);\n if (selectedOrdered.length === 0) return;\n const baseZ = toFront\n ? nextZIndex(currentStrokes, currentShapes)\n : minZIndex(currentStrokes, currentShapes) - selectedOrdered.length;\n const zById = new Map(selectedOrdered.map(({ item }, i) => [item.id, baseZ + i]));\n const stampZ = (item) => (zById.has(item.id) ? { ...item, z: zById.get(item.id) } : item);\n store.applyOperation(\n updateBlockProps(id, { strokes: currentStrokes.map(stampZ), shapes: currentShapes.map(stampZ) }),\n );\n },\n [store, id, block, selectedIds],\n );\n\n const handleBringToFront = useCallback(() => reorderSelection(true), [reorderSelection]);\n const handleSendToBack = useCallback(() => reorderSelection(false), [reorderSelection]);\n\n /** Opens the text-edit overlay for a brand-new box at `(x, y)`. */\n const startNewTextEdit = useCallback(\n (x, y) => {\n setTextEditDraft({\n id: null,\n x,\n y,\n width: DEFAULT_TEXT_WIDTH,\n height: DEFAULT_TEXT_HEIGHT,\n text: '',\n color,\n fontSize: textFontSize,\n });\n },\n [color, textFontSize],\n );\n\n /** Re-opens the text-edit overlay for an already-committed text shape, preserving its box/color/font. */\n const startExistingTextEdit = useCallback((shape) => {\n setTextEditDraft({\n id: shape.id,\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n text: shape.text,\n color: shape.color,\n fontSize: shape.fontSize ?? DEFAULT_TEXT_FONT_SIZE,\n });\n }, []);\n\n const cancelTextEdit = useCallback(() => {\n setTextEditDraft(null);\n }, []);\n\n /**\n * Commits the current text draft: empty text is treated as \"nothing to\n * keep\" — a brand-new box is simply discarded (same \"a click-without-\n * content draws nothing\" convention every other shape tool uses for a\n * degenerate result), and an existing box that's been fully cleared is\n * DELETED rather than left behind as an empty husk. Non-empty text\n * upserts one shape (new id for a new box, same id + unchanged box/color\n * for an edit) in one `updateBlockProps` call, selects it, and returns to\n * the select tool — same \"the result becomes the selection, tool reverts\n * to select\" convention paste/duplicate already use.\n */\n const commitTextEdit = useCallback(() => {\n const draft = textEditDraft;\n if (!draft) return;\n setTextEditDraft(null);\n const currentShapes = block?.props?.shapes ?? [];\n const text = draft.text;\n if (!text.trim()) {\n if (draft.id) {\n store.applyOperation(updateBlockProps(id, { shapes: currentShapes.filter((shape) => shape.id !== draft.id) }));\n setSelectedIds(new Set());\n }\n // Restores real DOM focus to the <svg> now that the textarea (which\n // held it) is about to unmount — without this, Delete/nudge/Enter-\n // to-re-edit/... would all silently do nothing right after finishing\n // a text edit, since none of those keydown handlers fire unless the\n // svg itself has focus.\n svgRef.current?.focus();\n return;\n }\n const shapeId = draft.id ?? genId();\n const nextShape = {\n id: shapeId,\n type: 'text',\n x: draft.x,\n y: draft.y,\n width: draft.width,\n height: draft.height,\n text,\n color: draft.color,\n fontSize: draft.fontSize,\n };\n const nextShapes = draft.id\n ? currentShapes.map((shape) => (shape.id === draft.id ? nextShape : shape))\n : [...currentShapes, nextShape];\n store.applyOperation(updateBlockProps(id, { shapes: nextShapes }));\n setSelectedIds(new Set([shapeId]));\n // handlePointerDown's own \"clicked away while still in the text tool\"\n // guard sets `tool` straight back to 'text' right after triggering\n // this (via blur) when it wants to keep placing more boxes — since\n // both updates land in the same batch, that later call simply wins.\n setTool('select');\n svgRef.current?.focus(); // see the doc comment on the early-return branch above\n }, [store, id, block, textEditDraft]);\n\n const stopResize = useCallback(() => {\n resizeDraftRef.current = null;\n setResizePreviewShape(null);\n }, []);\n\n const commitResize = useCallback(() => {\n const draft = resizeDraftRef.current;\n if (!draft) return;\n const currentShapes = block?.props?.shapes ?? [];\n const original = currentShapes.find((shape) => shape.id === draft.shapeId);\n if (!original) return;\n const resized = buildResizedShape(original, draft);\n // Dragging a rectangle/ellipse corner onto (or past) its opposite\n // corner would otherwise commit a degenerate zero-size shape — skip,\n // same \"no-op is fine\" choice a zero-drag draw already makes.\n if (resized.type !== 'arrow' && (resized.width === 0 || resized.height === 0)) return;\n const nextShapes = currentShapes.map((shape) => (shape.id === draft.shapeId ? resized : shape));\n store.applyOperation(updateBlockProps(id, { shapes: nextShapes }));\n }, [store, id, block]);\n\n /**\n * Discards whichever single-pointer gesture (draw/erase/shape-draft/move/\n * marquee/resize) the given (first) touch pointer had already started,\n * without committing it — called the instant a SECOND finger touches\n * down mid-gesture, so touch transitions straight into a two-finger pan\n * instead of also leaving behind a stray in-progress stroke/drag from\n * the first finger alone.\n */\n const cancelActiveSingleGesture = useCallback(\n (pointerId) => {\n const svg = svgRef.current;\n if (svg?.hasPointerCapture?.(pointerId)) svg.releasePointerCapture(pointerId);\n if (shapeDraftRef.current) {\n stopShapeDraft();\n return;\n }\n if (moveDraftRef.current) {\n stopMove();\n return;\n }\n if (marqueeDraftRef.current) {\n stopMarquee();\n return;\n }\n if (resizeDraftRef.current) {\n stopResize();\n return;\n }\n if (drawingRef.current) {\n stopDrawing();\n return;\n }\n if (erasingRef.current) {\n stopErasing();\n }\n },\n [stopShapeDraft, stopMove, stopMarquee, stopResize, stopDrawing, stopErasing],\n );\n\n // Delete/Backspace removes the selection; arrow keys nudge it by\n // NUDGE_STEP (Shift+arrow by NUDGE_STEP_LARGE); Enter re-opens the\n // text-edit overlay for a selected text shape; Ctrl/Cmd+C/V copy/paste\n // the selection through an in-block clipboard (see clipboardRef above);\n // Ctrl/Cmd+D duplicates it directly (copy + paste in one keystroke, no\n // separate clipboard step); Ctrl/Cmd+Shift+]/[ bring the selection to\n // front/send it to back. Verified against\n // src/react/useEditorKeyboardShortcuts.js: its global native keydown\n // handler only acts on Backspace/Delete when a whole BLOCK is selected\n // (getSelectedBlockId(), which this canvas never sets) or a real\n // cross-block *text* selection resolves (resolveCrossBlockSelection,\n // which an SVG has none of), and never inspects 'c'/'v'/'d'/']'/'[' at\n // all — with neither true, that handler does nothing, so this plain\n // keydown scoped to the <svg> itself is safe without any\n // stopPropagation/interference concerns. The <svg> needs real DOM focus\n // for this to fire at all — see handlePointerDown's select-tool branch,\n // which calls `.focus()` the moment an item becomes selected.\n const handleKeyDown = useCallback(\n (event) => {\n if (event.key === 'Backspace' || event.key === 'Delete') {\n if (selectedIds.size === 0) return;\n event.preventDefault();\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n // A selection can span both kinds — removing both arrays' matches in\n // one op keeps the whole delete a single undo step.\n store.applyOperation(\n updateBlockProps(id, {\n strokes: currentStrokes.filter((stroke) => !selectedIds.has(stroke.id)),\n shapes: currentShapes.filter((shape) => !selectedIds.has(shape.id)),\n }),\n );\n setSelectedIds(new Set());\n return;\n }\n if (NUDGE_DELTAS[event.key] && !event.ctrlKey && !event.metaKey) {\n if (selectedIds.size === 0) return;\n event.preventDefault();\n const step = event.shiftKey ? NUDGE_STEP_LARGE : NUDGE_STEP;\n const [dirX, dirY] = NUDGE_DELTAS[event.key];\n const dx = dirX * step;\n const dy = dirY * step;\n const currentStrokes = block?.props?.strokes ?? [];\n const currentShapes = block?.props?.shapes ?? [];\n store.applyOperation(\n updateBlockProps(id, {\n strokes: currentStrokes.map((stroke) => (selectedIds.has(stroke.id) ? applyStrokeOffset(stroke, dx, dy) : stroke)),\n shapes: currentShapes.map((shape) => (selectedIds.has(shape.id) ? applyShapeOffset(shape, dx, dy) : shape)),\n }),\n );\n return;\n }\n if (event.key === 'Enter' && !event.ctrlKey && !event.metaKey) {\n // Re-opens the text-edit overlay for a selected text shape — the\n // \"select it, press Enter to edit\" convention (same one Figma\n // uses), since there's no double-click detection in this pass.\n if (selectedIds.size !== 1) return;\n const [selId] = selectedIds;\n const shape = (block?.props?.shapes ?? []).find((s) => s.id === selId && s.type === 'text');\n if (!shape) return;\n event.preventDefault();\n startExistingTextEdit(shape);\n return;\n }\n const mod = event.ctrlKey || event.metaKey;\n if (!mod) return;\n const key = event.key.toLowerCase();\n if (key === 'c') {\n if (selectedIds.size === 0) return;\n event.preventDefault();\n copySelection();\n } else if (key === 'v') {\n if (clipboardRef.current.length === 0) return;\n event.preventDefault();\n pasteClipboard();\n } else if (key === 'd') {\n if (selectedIds.size === 0) return;\n event.preventDefault();\n copySelection();\n pasteClipboard();\n } else if (event.shiftKey && (key === ']' || key === '[')) {\n // Ctrl/Cmd+Shift+]/[ — the common \"bring to front\"/\"send to back\"\n // shortcut convention (Figma, Illustrator, ...); also reachable via\n // the toolbar's own buttons.\n if (selectedIds.size === 0) return;\n event.preventDefault();\n reorderSelection(key === ']');\n }\n },\n [store, id, block, selectedIds, copySelection, pasteClipboard, reorderSelection, startExistingTextEdit],\n );\n\n const currentView = { x: view.x, y: view.y, size: viewSize };\n\n const handleWheel = useCallback(\n (event) => {\n const svg = svgRef.current;\n if (!svg) return;\n event.preventDefault();\n if (event.ctrlKey || event.metaKey) {\n // Ctrl/Cmd+wheel — also how a trackpad OR touchscreen pinch gesture\n // reports itself — zooms the canvas.\n setView((prev) => {\n const zoomFactor = event.deltaY < 0 ? ZOOM_STEP : 1 / ZOOM_STEP;\n const nextZoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, prev.zoom * zoomFactor));\n const nextSize = VIEW_SIZE / nextZoom;\n // keep the point under the cursor fixed on screen as the zoom changes\n const { x, y } = zoomAnchoredView(event, svg, { x: prev.x, y: prev.y, size: VIEW_SIZE / prev.zoom }, nextSize);\n return { ...clampViewOffset(x, y, nextSize, VIEW_SIZE), zoom: nextZoom };\n });\n return;\n }\n // A plain wheel (no ctrl/meta) is most commonly a trackpad's\n // two-finger scroll gesture (deltaX/deltaY) — pan the canvas view\n // with it instead of letting it scroll the surrounding page, the\n // same \"this block owns wheel input\" choice the zoom branch above\n // already makes.\n const scale = localPixelScale(svg, viewSize);\n setView((prev) => ({\n ...prev,\n ...clampViewOffset(prev.x + event.deltaX / scale, prev.y + event.deltaY / scale, viewSize, VIEW_SIZE),\n }));\n },\n [viewSize],\n );\n\n // React registers `wheel` (like `touchstart`/`touchmove`) as a PASSIVE\n // listener at the root by default, a deliberate perf decision so\n // scrolling is never blocked by JS — `event.preventDefault()` inside a\n // passive listener is silently a no-op. That meant Ctrl/Cmd+wheel here\n // was zooming the canvas but ALSO zooming the whole browser page, since\n // the JSX `onWheel` prop's preventDefault never actually took effect. A\n // real native listener (added imperatively, same pattern as\n // EditableBlockContent.jsx's own `beforeinput` listener, for the same\n // \"React's synthetic system doesn't give the needed control\" reason)\n // isn't forced passive by the browser for `wheel` — only `touchstart`/\n // `touchmove` get that browser-level default — so this fixes it.\n useEffect(() => {\n const svg = svgRef.current;\n if (!svg) return undefined;\n svg.addEventListener('wheel', handleWheel, { passive: false });\n return () => svg.removeEventListener('wheel', handleWheel);\n }, [handleWheel]);\n\n const handleZoomIn = useCallback(() => {\n setView((prev) => {\n const nextZoom = Math.min(MAX_ZOOM, prev.zoom * ZOOM_STEP);\n const nextSize = VIEW_SIZE / nextZoom;\n const { x, y } = zoomCenteredView({ x: prev.x, y: prev.y, size: VIEW_SIZE / prev.zoom }, nextSize);\n return { ...clampViewOffset(x, y, nextSize, VIEW_SIZE), zoom: nextZoom };\n });\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setView((prev) => {\n const nextZoom = Math.max(MIN_ZOOM, prev.zoom / ZOOM_STEP);\n const nextSize = VIEW_SIZE / nextZoom;\n const { x, y } = zoomCenteredView({ x: prev.x, y: prev.y, size: VIEW_SIZE / prev.zoom }, nextSize);\n return { ...clampViewOffset(x, y, nextSize, VIEW_SIZE), zoom: nextZoom };\n });\n }, []);\n\n const handleZoomReset = useCallback(() => {\n setView({ x: 0, y: 0, zoom: 1 });\n }, []);\n\n /**\n * Exports the current drawing as a downloaded PNG file — rasterizes\n * `buildCanvasSVGMarkup`'s own output (the exact same markup `toHTML`\n * embeds into exported document HTML, see exportSvg.js) by loading it\n * into an `Image` and drawing that onto an offscreen `<canvas>`, at the\n * block's own `width`/`height` (not the fixed 1000x1000 logical space —\n * that's just the SVG's `viewBox`, scaled to fit `width`/`height` exactly\n * like the live component already renders it).\n *\n * Deliberately avoids `Blob`/`URL.createObjectURL` for the SVG-to-Image\n * step — a plain `data:image/svg+xml,...` URI (built with\n * `encodeURIComponent`, which is UTF-8 safe, unlike `btoa` which throws\n * on any non-Latin1 character a typed text box could easily contain) has\n * fewer moving parts and is supported essentially everywhere, including\n * environments where `URL.createObjectURL` might not be. Likewise uses\n * `canvas.toDataURL` (synchronous, universally supported) rather than\n * the async `canvas.toBlob`, and appends the download `<a>` to the\n * document before calling `.click()` — some browsers (notably Firefox)\n * don't reliably trigger a `download`-attribute save from a detached,\n * never-inserted anchor.\n *\n * This whole pipeline is genuinely browser-only: jsdom (the test\n * environment) has no real `<canvas>` 2D context, so `ctx` below comes\n * back null there, and no real `Image` decoding, so `onload` never\n * fires — both make a test that clicks this button a safe no-op rather\n * than a crash, at the cost of the actual rasterization itself not being\n * exercised by the test suite (the pure `buildCanvasSVGMarkup`\n * markup-building logic is what's unit-tested instead).\n */\n const handleExportPNG = useCallback(() => {\n if (!block) return;\n const svgMarkup = buildCanvasSVGMarkup(block);\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgMarkup)}`;\n const img = new Image();\n img.onload = () => {\n const exportCanvas = document.createElement('canvas');\n exportCanvas.width = block.props.width;\n exportCanvas.height = block.props.height;\n const ctx = exportCanvas.getContext('2d');\n if (!ctx) return;\n ctx.drawImage(img, 0, 0, exportCanvas.width, exportCanvas.height);\n const link = document.createElement('a');\n link.href = exportCanvas.toDataURL('image/png');\n link.download = 'canvas.png';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n };\n img.src = svgDataUrl;\n }, [block]);\n\n /**\n * Double-clicking a text shape re-opens its edit overlay — the standard,\n * discoverable way most editors expect (Enter-on-a-selected-text-shape,\n * wired in handleKeyDown, still works too, as a keyboard-only\n * alternative). Uses the native `dblclick` event rather than manually\n * tracking click timing/position — the browser already does that\n * correctly, including canceling itself on drags, and there's no\n * meaningful risk of firing this by accident during any of this\n * component's own drag gestures, all of which are driven by\n * pointerdown/pointermove/pointerup rather than click/dblclick.\n */\n const handleDoubleClick = useCallback(\n (event) => {\n if (tool !== 'select') return;\n const svg = svgRef.current;\n if (!svg) return;\n const [x, y] = clientToLocal(event, svg, { x: view.x, y: view.y, size: viewSize });\n const shapes = block?.props?.shapes ?? [];\n const hitId = hitTestShapeAt(x, y, shapes);\n const shape = shapes.find((s) => s.id === hitId);\n if (shape?.type !== 'text') return;\n setSelectedIds(new Set([shape.id]));\n startExistingTextEdit(shape);\n },\n [tool, view.x, view.y, viewSize, block, startExistingTextEdit],\n );\n\n const handlePointerDown = useCallback(\n (event) => {\n const svg = svgRef.current;\n if (!svg) return;\n\n if (event.pointerType === 'touch') {\n touchPointsRef.current.set(event.pointerId, { x: event.clientX, y: event.clientY });\n if (touchPointsRef.current.size >= 2) {\n // A second finger landing mid-gesture: switch straight into a\n // two-finger pan, discarding whatever the first finger alone had\n // already started (see cancelActiveSingleGesture).\n event.preventDefault();\n svg.setPointerCapture?.(event.pointerId);\n if (!touchPanRef.current) {\n for (const pointerId of touchPointsRef.current.keys()) {\n if (pointerId !== event.pointerId) cancelActiveSingleGesture(pointerId);\n }\n const center = touchCentroid(touchPointsRef.current);\n touchPanRef.current = { startCenterX: center.x, startCenterY: center.y, startViewX: view.x, startViewY: view.y };\n }\n return;\n }\n }\n\n if (textEditDraft) {\n // A pointerdown landing on the textarea ITSELF (repositioning the\n // cursor, selecting text while typing) is normal editing\n // interaction, not \"clicked away\" — let the browser handle it,\n // skip all tool logic below entirely.\n if (event.target?.closest?.('.be-canvas-text-editor')) return;\n // Anything else landing on this <svg> means the user clicked away\n // from an in-progress text edit. This can't be left to the\n // textarea's own onBlur to happen naturally on its own timing:\n // `pointerdown` (and this handler) fires BEFORE the browser's\n // mousedown-triggered blur/focus-change default action, so without\n // forcing the blur here FIRST, whatever this pointerdown is about\n // to do below (start a new text box, select a shape, start\n // drawing, ...) would run first and the in-progress edit's typed\n // text would be silently discarded instead of committed — the bug\n // this guard exists to prevent. Blurring synchronously (rather\n // than calling commitTextEdit directly here too) routes through\n // the textarea's own onBlur so there's exactly one commit path,\n // not two that could double-fire and create a duplicate shape.\n document.activeElement?.blur?.();\n if (tool === 'text') {\n // Immediately place the next box at this same click rather than\n // falling through to the branches below, which would otherwise\n // still be dispatching this same pointerdown against the OLD\n // (pre-commit) state. The blur above already committed the\n // previous box and set `tool` to 'select' (see commitTextEdit) —\n // setting it back to 'text' keeps the tool active for placing\n // further boxes in one continuous flow.\n let [textX, textY] = clientToLocal(event, svg, currentView);\n if (snapEnabled) [textX, textY] = [snapValue(textX), snapValue(textY)];\n startNewTextEdit(textX, textY);\n setTool('text');\n return;\n }\n }\n\n if (event.button === 1) {\n // Middle-mouse-button drag pans, regardless of the currently active\n // tool — a plain, always-available gesture (see the component doc\n // comment for why this was chosen over a space-bar-held convention).\n event.preventDefault();\n svg.setPointerCapture?.(event.pointerId);\n panRef.current = { startClientX: event.clientX, startClientY: event.clientY, startViewX: view.x, startViewY: view.y };\n return;\n }\n if (!event.isPrimary || (event.button !== undefined && event.button !== 0)) return;\n\n event.preventDefault();\n // Optional chaining: SVG pointer capture isn't universally implemented\n // (notably missing in jsdom, and historically inconsistent in some\n // browsers) — drawing/erasing still works without it, just without the\n // \"keeps tracking outside the element bounds\" guarantee.\n svg.setPointerCapture?.(event.pointerId);\n const [x, y] = clientToLocal(event, svg, currentView);\n\n if (tool === 'eraser') {\n erasedStrokeIdsRef.current = new Set();\n erasedShapeIdsRef.current = new Set();\n erasedPointIndicesRef.current = new Map();\n erasingRef.current = true;\n hitTestEraserAt(x, y); // a click-without-drag still erases whatever's right under it\n } else if (SHAPE_TOOLS.has(tool)) {\n const startX = snapEnabled ? snapValue(x) : x;\n const startY = snapEnabled ? snapValue(y) : y;\n shapeDraftRef.current = { type: tool, x1: startX, y1: startY, x2: startX, y2: startY };\n setShapeDraftPreview(buildDraftShape(shapeDraftRef.current, color, strokeSize, fill));\n } else if (tool === 'select') {\n const strokesList = block?.props?.strokes ?? [];\n const shapesList = block?.props?.shapes ?? [];\n // Resize/endpoint handles are single-selection-only, and only for a\n // shape (strokes were never resizable) — see the component doc\n // comment.\n const singleSelectedShape =\n selectedIds.size === 1 ? shapesList.find((shape) => selectedIds.has(shape.id)) ?? null : null;\n const handle = hitTestHandle(x, y, singleSelectedShape);\n if (handle) {\n // Grabbing a handle always takes priority over re-selecting/moving\n // the shape it belongs to.\n if (handle === 'rotate') {\n const { cx, cy } = shapeCenter(singleSelectedShape);\n // The pointer's own angle from the shape's center, at drag\n // start — every subsequent pointermove compares its own angle\n // against this to get a rotation DELTA, added onto the\n // shape's rotation at drag start (not overwritten), so\n // starting a new rotate drag from an already-rotated shape\n // continues from there rather than snapping.\n const startAngle = (Math.atan2(y - cy, x - cx) * 180) / Math.PI;\n resizeDraftRef.current = {\n mode: 'rotate',\n shapeId: singleSelectedShape.id,\n cx,\n cy,\n startAngle,\n startRotation: singleSelectedShape.rotation ?? 0,\n rotation: singleSelectedShape.rotation ?? 0,\n };\n } else if (singleSelectedShape.type === 'arrow') {\n resizeDraftRef.current = { mode: 'arrow-endpoint', shapeId: singleSelectedShape.id, endpoint: handle, x, y };\n } else {\n const [fixedX, fixedY] = rectCorners(singleSelectedShape)[OPPOSITE_CORNER[handle]];\n resizeDraftRef.current = { mode: 'rect-corner', shapeId: singleSelectedShape.id, fixedX, fixedY, x, y };\n }\n setResizePreviewShape(buildResizedShape(singleSelectedShape, resizeDraftRef.current));\n return;\n }\n const hit = hitTestSelectableAt(x, y, strokesList, shapesList);\n if (hit) {\n if (event.shiftKey) {\n // Shift+click only toggles membership — a deliberate plain\n // click-drag afterward is needed to move the adjusted selection.\n setSelectedIds((prev) => {\n const next = new Set(prev);\n if (next.has(hit.id)) next.delete(hit.id);\n else next.add(hit.id);\n return next;\n });\n return;\n }\n // Clicking an already-selected item starts a group move of the\n // WHOLE current selection; clicking a not-yet-selected item\n // collapses selection to just that one first — group-move-of-1 is\n // the same code path. Either way this both selects AND\n // immediately starts a move drag in the same gesture, the\n // standard \"click-drag to move\" convention.\n const nextIds = selectedIds.has(hit.id) ? selectedIds : new Set([hit.id]);\n setSelectedIds(nextIds);\n moveDraftRef.current = { ids: [...nextIds], startX: x, startY: y, dx: 0, dy: 0 };\n svg.focus(); // real DOM focus so handleKeyDown's own Delete/Backspace can fire\n } else {\n // Empty space: start a marquee drag instead of immediately\n // clearing the selection — an empty-result marquee clears it on\n // release (see commitMarquee), preserving that behavior as a\n // special case.\n marqueeDraftRef.current = { startX: x, startY: y, x, y };\n }\n } else if (tool === 'text') {\n // A click-drag isn't needed to size a text box (unlike the other\n // shape tools) — it starts at a fixed default size, resizable\n // afterward like any other shape — so pointerdown alone is enough\n // to open the edit overlay; there's no shapeDraftRef drag to track.\n startNewTextEdit(snapEnabled ? snapValue(x) : x, snapEnabled ? snapValue(y) : y);\n } else if (tool === 'pen') {\n pointsRef.current = [[x, y, event.pressure || 0.5]];\n drawingRef.current = true;\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n tool,\n hitTestEraserAt,\n view.x,\n view.y,\n viewSize,\n color,\n strokeSize,\n fill,\n snapEnabled,\n block,\n selectedIds,\n startNewTextEdit,\n textEditDraft,\n cancelActiveSingleGesture,\n ],\n );\n\n const handlePointerMove = useCallback(\n (event) => {\n const svg = svgRef.current;\n if (!svg) return;\n\n if (event.pointerType === 'touch' && touchPointsRef.current.has(event.pointerId)) {\n touchPointsRef.current.set(event.pointerId, { x: event.clientX, y: event.clientY });\n if (touchPanRef.current) {\n event.preventDefault();\n const scale = localPixelScale(svg, viewSize);\n const center = touchCentroid(touchPointsRef.current);\n const { startCenterX, startCenterY, startViewX, startViewY } = touchPanRef.current;\n const dx = (center.x - startCenterX) / scale;\n const dy = (center.y - startCenterY) / scale;\n // startViewX/startViewY are captured above (not read from the ref\n // inside this updater) — several of these events can be queued\n // within the same React batch, and touchPanRef.current may\n // already have been reset to null by a LATER pointerup/pointer-\n // cancel by the time this updater actually runs.\n setView((prev) => ({ ...prev, ...clampViewOffset(startViewX - dx, startViewY - dy, viewSize, VIEW_SIZE) }));\n return;\n }\n }\n\n if (panRef.current) {\n // Same letterbox-aware scale clientToLocal uses (see canvasGeometry.js) —\n // a delta only needs the shared scale factor, not the absolute view.x/y offset.\n const scale = localPixelScale(svg, viewSize);\n const { startClientX, startClientY, startViewX, startViewY } = panRef.current;\n const dx = (event.clientX - startClientX) / scale;\n const dy = (event.clientY - startClientY) / scale;\n // startViewX/startViewY are captured above rather than read from\n // the ref inside this updater — a queued functional setView update\n // runs later, by which point panRef.current could already have\n // been reset to null by a subsequent pointerup/pointercancel\n // dispatched within the same batch (see the identical touch-pan\n // fix above, where this exact lazy-read pattern crashed).\n setView((prev) => ({ ...prev, ...clampViewOffset(startViewX - dx, startViewY - dy, viewSize, VIEW_SIZE) }));\n return;\n }\n if (shapeDraftRef.current) {\n let [x, y] = clientToLocal(event, svg, currentView);\n if (snapEnabled) [x, y] = [snapValue(x), snapValue(y)];\n shapeDraftRef.current = { ...shapeDraftRef.current, x2: x, y2: y };\n setShapeDraftPreview(buildDraftShape(shapeDraftRef.current, color, strokeSize, fill));\n return;\n }\n if (moveDraftRef.current) {\n const [x, y] = clientToLocal(event, svg, currentView);\n const draft = moveDraftRef.current;\n // Snaps the DELTA itself (not an absolute position — ambiguous for\n // a multi-item group, each with its own origin) to the grid, so a\n // drag's movement is quantized to grid-sized steps rather than\n // landing any particular item exactly on a grid line.\n draft.dx = snapEnabled ? snapValue(x - draft.startX) : x - draft.startX;\n draft.dy = snapEnabled ? snapValue(y - draft.startY) : y - draft.startY;\n setMoveOverride({ ids: draft.ids, dx: draft.dx, dy: draft.dy });\n return;\n }\n if (marqueeDraftRef.current) {\n const [x, y] = clientToLocal(event, svg, currentView);\n const draft = marqueeDraftRef.current;\n draft.x = x;\n draft.y = y;\n setMarqueeRect(normalizeRect(draft.startX, draft.startY, draft.x, draft.y));\n return;\n }\n if (resizeDraftRef.current) {\n let [x, y] = clientToLocal(event, svg, currentView);\n const draft = resizeDraftRef.current;\n if (draft.mode === 'rotate') {\n const currentAngle = (Math.atan2(y - draft.cy, x - draft.cx) * 180) / Math.PI;\n const rawRotation = draft.startRotation + (currentAngle - draft.startAngle);\n draft.rotation = snapEnabled ? snapAngle(rawRotation) : rawRotation;\n } else {\n // A single point (a resize corner or arrow endpoint) snapping to\n // the grid, unlike a group move's delta, unambiguously means\n // \"land exactly on a grid line.\"\n if (snapEnabled) [x, y] = [snapValue(x), snapValue(y)];\n draft.x = x;\n draft.y = y;\n }\n const shapes = block?.props?.shapes ?? [];\n const original = shapes.find((shape) => shape.id === draft.shapeId);\n if (original) setResizePreviewShape(buildResizedShape(original, draft));\n return;\n }\n if (drawingRef.current) {\n const [x, y] = clientToLocal(event, svg, currentView);\n pointsRef.current.push([x, y, event.pressure || 0.5]);\n schedulePreviewUpdate(strokeSize);\n } else if (erasingRef.current) {\n const [x, y] = clientToLocal(event, svg, currentView);\n hitTestEraserAt(x, y);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [schedulePreviewUpdate, hitTestEraserAt, view.x, view.y, viewSize, strokeSize, color, fill, snapEnabled, block],\n );\n\n const releaseCapture = useCallback((event) => {\n const svg = svgRef.current;\n if (svg?.hasPointerCapture?.(event.pointerId)) svg.releasePointerCapture(event.pointerId);\n }, []);\n\n const handlePointerUp = useCallback(\n (event) => {\n if (event.pointerType === 'touch') {\n touchPointsRef.current.delete(event.pointerId);\n if (touchPanRef.current) {\n releaseCapture(event);\n if (touchPointsRef.current.size < 2) touchPanRef.current = null;\n return;\n }\n }\n if (panRef.current) {\n releaseCapture(event);\n panRef.current = null;\n return;\n }\n if (shapeDraftRef.current) {\n releaseCapture(event);\n commitShapeDraft();\n stopShapeDraft();\n return;\n }\n if (moveDraftRef.current) {\n releaseCapture(event);\n commitMove();\n stopMove();\n return;\n }\n if (marqueeDraftRef.current) {\n releaseCapture(event);\n commitMarquee();\n stopMarquee();\n return;\n }\n if (resizeDraftRef.current) {\n releaseCapture(event);\n commitResize();\n stopResize();\n return;\n }\n if (drawingRef.current) {\n releaseCapture(event);\n commitStroke();\n stopDrawing();\n } else if (erasingRef.current) {\n releaseCapture(event);\n commitErase();\n stopErasing();\n }\n },\n [\n releaseCapture,\n commitShapeDraft,\n stopShapeDraft,\n commitMove,\n stopMove,\n commitMarquee,\n stopMarquee,\n commitResize,\n stopResize,\n commitStroke,\n stopDrawing,\n commitErase,\n stopErasing,\n ],\n );\n\n // A pointercancel (palm rejection, an OS gesture taking over, ...) means\n // the interaction was aborted, not finished — discard rather than commit,\n // unlike pointerup.\n const handlePointerCancel = useCallback(\n (event) => {\n if (event.pointerType === 'touch') {\n touchPointsRef.current.delete(event.pointerId);\n if (touchPanRef.current) {\n releaseCapture(event);\n if (touchPointsRef.current.size < 2) touchPanRef.current = null;\n return;\n }\n }\n if (panRef.current) {\n releaseCapture(event);\n panRef.current = null;\n return;\n }\n if (shapeDraftRef.current) {\n releaseCapture(event);\n stopShapeDraft();\n return;\n }\n if (moveDraftRef.current) {\n releaseCapture(event);\n stopMove();\n return;\n }\n if (marqueeDraftRef.current) {\n releaseCapture(event);\n stopMarquee();\n return;\n }\n if (resizeDraftRef.current) {\n releaseCapture(event);\n stopResize();\n return;\n }\n if (drawingRef.current) {\n releaseCapture(event);\n stopDrawing();\n } else if (erasingRef.current) {\n releaseCapture(event);\n stopErasing();\n }\n },\n [releaseCapture, stopShapeDraft, stopMove, stopMarquee, stopResize, stopDrawing, stopErasing],\n );\n\n const handleResizeStart = useCallback(\n (event) => {\n startResize(event, {\n startX: event.clientX,\n startY: event.clientY,\n startWidth: block?.props?.width ?? DEFAULT_CANVAS_WIDTH,\n startHeight: block?.props?.height ?? DEFAULT_CANVAS_HEIGHT,\n });\n },\n [startResize, block],\n );\n\n if (!block) return null;\n const { strokes = [], shapes = [], width, height } = block.props;\n const effectiveWidth = dragSize?.width ?? width;\n const effectiveHeight = dragSize?.height ?? height;\n\n const SELECTION_PADDING = 6;\n // One dashed box per selected item (strokes and shapes alike), reflecting\n // an in-progress group move's live offset — 2+ selected renders one box\n // each, no union/group bounding box in this pass.\n const selectionBoxes = [...selectedIds]\n .map((selId) => {\n const found = findSelectable(block, selId);\n if (!found) return null;\n let { kind, item } = found;\n if (moveOverride?.ids?.includes(selId)) {\n item =\n kind === 'stroke'\n ? applyStrokeOffset(item, moveOverride.dx, moveOverride.dy)\n : applyShapeOffset(item, moveOverride.dx, moveOverride.dy);\n } else if (kind === 'shape' && resizePreviewShape?.id === selId) {\n item = resizePreviewShape;\n }\n return { id: selId, kind, item, box: selectableBoundingBox(kind, item), rotation: kind === 'shape' ? item.rotation : 0 };\n })\n .filter(Boolean);\n\n // Resize/endpoint/rotate handles are shown only for exactly 1 selected\n // item, and only when it's a shape (strokes were never resizable) — no\n // group-resize/rotate in this pass.\n const singleSelectedShapeEntry =\n selectionBoxes.length === 1 && selectionBoxes[0].kind === 'shape' ? selectionBoxes[0] : null;\n const selectedDisplayShape = singleSelectedShapeEntry?.item ?? null;\n // Corner resize handles are hidden once the shape has any rotation — see\n // the component doc comment on rotation's scope (no rotated-resize math\n // in this pass); the rotate handle itself is unaffected by that and shown\n // for any non-arrow single selection, rotated or not.\n const selectionHandlePoints =\n selectedDisplayShape && selectedDisplayShape.type === 'arrow'\n ? [\n ['start', selectedDisplayShape.x1, selectedDisplayShape.y1],\n ['end', selectedDisplayShape.x2, selectedDisplayShape.y2],\n ]\n : selectedDisplayShape && !selectedDisplayShape.rotation\n ? Object.entries(rectCorners(selectedDisplayShape)).map(([corner, [cx, cy]]) => [corner, cx, cy])\n : [];\n const rotateHandle =\n selectedDisplayShape && selectedDisplayShape.type !== 'arrow' ? rotateHandlePoint(selectedDisplayShape) : null;\n\n return (\n <div className={className} data-block-id={id} data-tool={tool} contentEditable={false} tabIndex={-1}>\n <div className=\"be-canvas-toolbar\" contentEditable={false}>\n <button\n type=\"button\"\n className={`be-canvas-toolbar-btn${tool === 'pen' ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === 'pen'}\n aria-label=\"Pen\"\n title=\"Pen\"\n onClick={() => setTool('pen')}\n >\n <PencilIcon size={14} />\n </button>\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={eraserTriggerRef}\n type=\"button\"\n className={`be-canvas-toolbar-btn${tool === 'eraser' ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-haspopup=\"true\"\n aria-expanded={isEraserPickerOpen}\n aria-pressed={tool === 'eraser'}\n aria-label=\"Eraser\"\n title=\"Eraser\"\n onClick={() => setIsEraserPickerOpen((open) => !open)}\n >\n {(() => {\n const ActiveEraserIcon = ERASER_MODE_LIST.find((e) => e.mode === eraserMode)?.Icon ?? EraserIcon;\n return <ActiveEraserIcon size={14} />;\n })()}\n </button>\n {isEraserPickerOpen && (\n <div ref={eraserPopoverRef} className=\"be-canvas-picker be-canvas-shape-picker\" role=\"menu\" aria-label=\"Eraser\">\n {ERASER_MODE_LIST.map(({ mode, label, Icon }) => (\n <button\n key={mode}\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-btn${tool === 'eraser' && eraserMode === mode ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === 'eraser' && eraserMode === mode}\n aria-label={label}\n title={label}\n onClick={() => {\n setTool('eraser');\n setEraserMode(mode);\n closeEraserPicker();\n }}\n >\n <Icon size={14} />\n </button>\n ))}\n </div>\n )}\n </div>\n <button\n type=\"button\"\n className={`be-canvas-toolbar-btn${tool === 'select' ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === 'select'}\n aria-label=\"Select\"\n title=\"Select\"\n onClick={() => setTool('select')}\n >\n <CursorIcon size={14} />\n </button>\n <button\n type=\"button\"\n className={`be-canvas-toolbar-btn${tool === 'text' ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === 'text'}\n aria-label=\"Text\"\n title=\"Text\"\n onClick={() => setTool('text')}\n >\n <TextIcon size={14} />\n </button>\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={fontSizeTriggerRef}\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-haspopup=\"true\"\n aria-expanded={isFontSizePickerOpen}\n aria-label={`Font size: ${textEditDraft ? textEditDraft.fontSize : textFontSize}`}\n title=\"Font size\"\n onClick={() => setIsFontSizePickerOpen((open) => !open)}\n >\n <span className=\"be-canvas-font-size-trigger\">A</span>\n </button>\n {isFontSizePickerOpen && (\n <div\n ref={fontSizePopoverRef}\n className=\"be-canvas-picker be-canvas-size-picker\"\n role=\"dialog\"\n aria-label=\"Font size\"\n >\n <span className=\"be-canvas-size-preview\" aria-hidden=\"true\">\n <span\n className=\"be-canvas-font-size-preview-letter\"\n style={{ fontSize: textEditDraft ? textEditDraft.fontSize : textFontSize }}\n >\n A\n </span>\n </span>\n <input\n type=\"range\"\n className=\"be-canvas-size-slider\"\n min={MIN_TEXT_FONT_SIZE}\n max={MAX_TEXT_FONT_SIZE}\n value={textEditDraft ? textEditDraft.fontSize : textFontSize}\n onChange={(event) => {\n const value = Number(event.target.value);\n setTextFontSize(value);\n // Live-updates the box actively being typed into, if any\n // — see textFontSize's own doc comment above for why.\n if (textEditDraft) setTextEditDraft((prev) => (prev ? { ...prev, fontSize: value } : prev));\n }}\n aria-label=\"Font size\"\n />\n <span className=\"be-canvas-size-value\">{textEditDraft ? textEditDraft.fontSize : textFontSize}px</span>\n </div>\n )}\n </div>\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Bring to front\"\n title=\"Bring to front\"\n onClick={handleBringToFront}\n disabled={selectedIds.size === 0}\n >\n <ArrowUpIcon size={14} />\n </button>\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Send to back\"\n title=\"Send to back\"\n onClick={handleSendToBack}\n disabled={selectedIds.size === 0}\n >\n <ArrowDownIcon size={14} />\n </button>\n <span className=\"be-canvas-toolbar-divider\" />\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={shapeTriggerRef}\n type=\"button\"\n className={`be-canvas-toolbar-btn${SHAPE_TOOLS.has(tool) ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-haspopup=\"true\"\n aria-expanded={isShapePickerOpen}\n aria-label=\"Shape\"\n title=\"Shape\"\n onClick={() => setIsShapePickerOpen((open) => !open)}\n >\n {(() => {\n const ActiveShapeIcon =\n SHAPE_TOOL_LIST.find((s) => s.type === (SHAPE_TOOLS.has(tool) ? tool : lastShapeTool))?.Icon ?? SquareIcon;\n return <ActiveShapeIcon size={14} />;\n })()}\n </button>\n {isShapePickerOpen && (\n <div ref={shapePopoverRef} className=\"be-canvas-picker be-canvas-shape-picker\" role=\"menu\" aria-label=\"Shape\">\n {SHAPE_TOOL_LIST.map(({ type, label, Icon }) => (\n <button\n key={type}\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-btn${tool === type ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={tool === type}\n aria-label={label}\n title={label}\n onClick={() => {\n setTool(type);\n setLastShapeTool(type);\n closeShapePicker();\n }}\n >\n <Icon size={14} />\n </button>\n ))}\n </div>\n )}\n </div>\n <span className=\"be-canvas-toolbar-divider\" />\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={colorTriggerRef}\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-haspopup=\"true\"\n aria-expanded={isColorPickerOpen}\n aria-label={`Color: ${color}`}\n title=\"Color\"\n onClick={() => setIsColorPickerOpen((open) => !open)}\n >\n <span className=\"be-canvas-color-trigger-dot\" style={{ backgroundColor: color }} />\n </button>\n {isColorPickerOpen && (\n <div ref={colorPopoverRef} className=\"be-canvas-picker be-canvas-color-picker\" role=\"menu\" aria-label=\"Pen color\">\n {COLOR_SWATCHES.map((swatch) => (\n <button\n key={swatch}\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-swatch${color === swatch ? ' be-canvas-toolbar-swatch-active' : ''}`}\n style={{ backgroundColor: swatch }}\n aria-pressed={color === swatch}\n aria-label={`Color ${swatch}`}\n title={`Color ${swatch}`}\n onClick={() => {\n setColor(swatch);\n closeColorPicker();\n }}\n />\n ))}\n <label className=\"be-canvas-custom-swatch\" title=\"Custom color\" aria-label=\"Custom color\">\n <input type=\"color\" value={color} onChange={(event) => setColor(event.target.value)} />\n </label>\n </div>\n )}\n </div>\n <span className=\"be-canvas-toolbar-divider\" />\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={fillTriggerRef}\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-haspopup=\"true\"\n aria-expanded={isFillPickerOpen}\n aria-label={`Fill: ${fill ?? 'none'}`}\n title=\"Fill\"\n onClick={() => setIsFillPickerOpen((open) => !open)}\n >\n <span\n className={`be-canvas-fill-trigger-dot${fill ? '' : ' be-canvas-fill-trigger-dot-none'}`}\n style={fill ? { backgroundColor: fill } : undefined}\n />\n </button>\n {isFillPickerOpen && (\n <div ref={fillPopoverRef} className=\"be-canvas-picker be-canvas-color-picker\" role=\"menu\" aria-label=\"Shape fill\">\n <button\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-swatch be-canvas-fill-swatch-none${fill === null ? ' be-canvas-toolbar-swatch-active' : ''}`}\n aria-pressed={fill === null}\n aria-label=\"No fill\"\n title=\"No fill\"\n onClick={() => {\n setFill(null);\n closeFillPicker();\n }}\n />\n {COLOR_SWATCHES.map((swatch) => (\n <button\n key={swatch}\n type=\"button\"\n role=\"menuitem\"\n className={`be-canvas-toolbar-swatch${fill === swatch ? ' be-canvas-toolbar-swatch-active' : ''}`}\n style={{ backgroundColor: swatch }}\n aria-pressed={fill === swatch}\n aria-label={`Fill ${swatch}`}\n title={`Fill ${swatch}`}\n onClick={() => {\n setFill(swatch);\n closeFillPicker();\n }}\n />\n ))}\n <label className=\"be-canvas-custom-swatch\" title=\"Custom fill\" aria-label=\"Custom fill\">\n <input type=\"color\" value={fill ?? DEFAULT_COLOR} onChange={(event) => setFill(event.target.value)} />\n </label>\n </div>\n )}\n </div>\n <span className=\"be-canvas-toolbar-divider\" />\n <div className=\"be-canvas-picker-wrap\">\n <button\n ref={sizeTriggerRef}\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-haspopup=\"true\"\n aria-expanded={isSizePickerOpen}\n aria-label={`Stroke size: ${strokeSize}`}\n title=\"Stroke size\"\n onClick={() => setIsSizePickerOpen((open) => !open)}\n >\n <span\n className=\"be-canvas-size-trigger-dot\"\n style={{ width: Math.min(strokeSize, 16), height: Math.min(strokeSize, 16) }}\n />\n </button>\n {isSizePickerOpen && (\n <div ref={sizePopoverRef} className=\"be-canvas-picker be-canvas-size-picker\" role=\"dialog\" aria-label=\"Stroke size\">\n <span className=\"be-canvas-size-preview\" aria-hidden=\"true\">\n <span className=\"be-canvas-size-preview-dot\" style={{ width: strokeSize, height: strokeSize }} />\n </span>\n <input\n type=\"range\"\n className=\"be-canvas-size-slider\"\n min={MIN_STROKE_SIZE}\n max={MAX_STROKE_SIZE}\n value={strokeSize}\n onChange={(event) => setStrokeSize(Number(event.target.value))}\n aria-label=\"Stroke size\"\n />\n <span className=\"be-canvas-size-value\">{strokeSize}px</span>\n </div>\n )}\n </div>\n <span className=\"be-canvas-toolbar-divider\" />\n <button\n type=\"button\"\n className={`be-canvas-toolbar-btn${snapEnabled ? ' be-canvas-toolbar-btn-active' : ''}`}\n aria-pressed={snapEnabled}\n aria-label=\"Snap to grid\"\n title={\n snapEnabled\n ? 'Snap to grid: ON — drawing, moving, resizing and rotating align to the dotted grid. Click to turn off.'\n : 'Snap to grid: OFF — click to turn on (aligns drawing, moving, resizing and rotating to a grid)'\n }\n onClick={() => setSnapEnabled((prev) => !prev)}\n >\n <MagnetIcon size={14} />\n </button>\n <span className=\"be-canvas-toolbar-divider\" />\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n onClick={handleZoomOut}\n disabled={view.zoom <= MIN_ZOOM}\n >\n −\n </button>\n <button\n type=\"button\"\n className=\"be-canvas-zoom-label\"\n aria-label={`Zoom: ${Math.round(view.zoom * 100)}%. Click to reset to 100%.`}\n title=\"Reset zoom to 100%\"\n onClick={handleZoomReset}\n >\n {Math.round(view.zoom * 100)}%\n </button>\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Zoom in\"\n title=\"Zoom in\"\n onClick={handleZoomIn}\n disabled={view.zoom >= MAX_ZOOM}\n >\n +\n </button>\n <span className=\"be-canvas-toolbar-divider\" />\n <button\n type=\"button\"\n className=\"be-canvas-toolbar-btn\"\n aria-label=\"Export PNG\"\n title=\"Export as PNG\"\n onClick={handleExportPNG}\n disabled={strokes.length === 0 && shapes.length === 0}\n >\n <DownloadIcon size={14} />\n </button>\n </div>\n <svg\n ref={svgRef}\n className=\"be-canvas-surface\"\n viewBox={`${view.x} ${view.y} ${viewSize} ${viewSize}`}\n width={effectiveWidth}\n height={effectiveHeight}\n tabIndex={-1}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerCancel}\n onDoubleClick={handleDoubleClick}\n onKeyDown={handleKeyDown}\n >\n {snapEnabled && (\n <>\n {/* A dot grid at a coarser spacing than SNAP_GRID_SIZE itself\n (10 units) — showing every actual snap line would be a\n 10x10=100 solid wall of dots at this space's scale, not a\n helpful visual reference. This exists purely so \"snap to\n grid\" has something visible to point at (see the toolbar\n button's own title) — drawing/dragging still snaps to the\n finer, unrendered SNAP_GRID_SIZE lines underneath it. */}\n <defs>\n <pattern\n id={`be-canvas-grid-${id}`}\n width={SNAP_GRID_VISUAL_SPACING}\n height={SNAP_GRID_VISUAL_SPACING}\n patternUnits=\"userSpaceOnUse\"\n >\n <circle cx={1} cy={1} r={1.5} className=\"be-canvas-grid-dot\" />\n </pattern>\n </defs>\n <rect\n className=\"be-canvas-grid-background\"\n x={view.x}\n y={view.y}\n width={viewSize}\n height={viewSize}\n fill={`url(#be-canvas-grid-${id})`}\n />\n </>\n )}\n {/* One shared bottom-to-top stacking order across strokes AND shapes (see zOrder.js) — a pen\n stroke drawn after a filled shape now renders on top of it, instead of every shape always\n painting over every stroke regardless of draw order. */}\n {orderedDrawables(strokes, shapes).map(({ kind, item }) => {\n if (kind === 'stroke') {\n const stroke = item;\n const moved = moveOverride?.ids?.includes(stroke.id);\n const path = moved\n ? getStrokeOutlinePath(applyStrokeOffset(stroke, moveOverride.dx, moveOverride.dy).points, { size: stroke.size })\n : getStrokePath(stroke);\n return (\n <path\n key={stroke.id}\n d={path}\n fill={stroke.color}\n fillRule=\"nonzero\"\n opacity={erasingIds.has(stroke.id) ? 0.25 : 1}\n />\n );\n }\n const shape = item;\n let displayShape = shape;\n if (moveOverride?.ids?.includes(shape.id)) displayShape = applyShapeOffset(shape, moveOverride.dx, moveOverride.dy);\n else if (resizePreviewShape?.id === shape.id) displayShape = resizePreviewShape;\n return <ShapeElement key={shape.id} shape={displayShape} opacity={erasingShapeIds.has(shape.id) ? 0.25 : 1} />;\n })}\n {/* The in-progress pen/shape draft always renders on top of everything else while actively drawing. */}\n {previewPath && <path d={previewPath} fill={color} fillRule=\"nonzero\" />}\n {shapeDraftPreview && <ShapeElement shape={shapeDraftPreview} opacity={0.6} />}\n {selectionBoxes.map(({ id: selId, box, rotation }) => (\n <g\n key={selId}\n transform={rotation ? `rotate(${rotation} ${box.x + box.width / 2} ${box.y + box.height / 2})` : undefined}\n >\n <rect\n className=\"be-canvas-selection-box\"\n x={box.x - SELECTION_PADDING}\n y={box.y - SELECTION_PADDING}\n width={box.width + SELECTION_PADDING * 2}\n height={box.height + SELECTION_PADDING * 2}\n fill=\"none\"\n />\n </g>\n ))}\n {selectionHandlePoints.map(([corner, cx, cy]) => (\n <rect\n key={corner}\n className=\"be-canvas-selection-handle\"\n x={cx - HANDLE_VISUAL_SIZE / 2}\n y={cy - HANDLE_VISUAL_SIZE / 2}\n width={HANDLE_VISUAL_SIZE}\n height={HANDLE_VISUAL_SIZE}\n />\n ))}\n {rotateHandle && (\n <circle\n className=\"be-canvas-rotate-handle\"\n cx={rotateHandle[0]}\n cy={rotateHandle[1]}\n r={HANDLE_VISUAL_SIZE / 2}\n />\n )}\n {marqueeRect && (\n <rect\n className=\"be-canvas-marquee\"\n x={marqueeRect.x}\n y={marqueeRect.y}\n width={marqueeRect.width}\n height={marqueeRect.height}\n />\n )}\n {textEditDraft && (\n <foreignObject x={textEditDraft.x} y={textEditDraft.y} width={textEditDraft.width} height={textEditDraft.height}>\n <textarea\n // eslint-disable-next-line react/no-unknown-property\n xmlns=\"http://www.w3.org/1999/xhtml\"\n ref={(el) => el?.focus()}\n className=\"be-canvas-text-editor\"\n value={textEditDraft.text}\n style={{ color: textEditDraft.color, fontSize: textEditDraft.fontSize }}\n onChange={(event) => setTextEditDraft((prev) => (prev ? { ...prev, text: event.target.value } : prev))}\n onBlur={() => commitTextEdit()}\n onKeyDown={(event) => {\n // Escape discards the draft (a new box vanishes; an edit\n // reverts to whatever was last committed) instead of\n // committing whatever's currently typed — plain Enter\n // inserts a newline (multi-line text is the whole point of\n // a resizable box), so there's no separate \"confirm\" key.\n if (event.key === 'Escape') {\n event.preventDefault();\n cancelTextEdit();\n }\n event.stopPropagation(); // don't let the svg's own onKeyDown (Delete/nudge/paste/...) fire while typing\n }}\n />\n </foreignObject>\n )}\n </svg>\n <div\n className=\"be-canvas-resize-handle\"\n onMouseDown={handleResizeStart}\n role=\"slider\"\n aria-label=\"Resize canvas\"\n aria-valuemin={MIN_CANVAS_WIDTH}\n aria-valuenow={effectiveWidth}\n contentEditable={false}\n />\n </div>\n );\n}\n","import { CanvasBlock } from './CanvasBlock.jsx';\nimport { createCanvasBlock, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT } from './createCanvasBlock.js';\nimport { buildCanvasSVGMarkup } from './exportSvg.js';\nimport { insertSiblingAfter, insertSiblingAfterAndFocus } from '../shared/blockCommands.js';\nimport { createTextLeafBlock } from '../shared/leafBlockFactory.js';\nimport { updateRun } from '../../store/operations.js';\nimport { ScribbleIcon } from '../../react/icons.jsx';\n\n/**\n * Bakes a self-contained inline `<svg>` (see exportSvg.js's own doc\n * comment for why that logic lives in its own module rather than here).\n * Mirrors embed's own `if (!src) return '<p></p>';` convention for\n * \"nothing meaningful here yet\" (see embed/index.js's toHTML).\n */\nfunction toHTML(block) {\n const { strokes = [], shapes = [] } = block.props;\n if (!strokes.length && !shapes.length) return '<p></p>';\n return buildCanvasSVGMarkup(block);\n}\n\n// A drawing has no meaningful plain-text representation (unlike embed,\n// which at least has a filename, or divider's decorative \"---\") — this is a\n// deliberate, permanent v1 limitation: no OCR/description generation.\nfunction toPlainText() {\n return '';\n}\n\n// No paste-round-trip import of arbitrary pasted <svg> markup back into\n// stroke data in v1 — reverse-parsing arbitrary path `d` data back into a\n// normalized-space point array is a non-trivial, out-of-scope problem. A\n// canvas block can only be created via its own slash command for now;\n// pasting exported HTML back in falls through to whatever the paste\n// pipeline does for an unrecognized node.\nfunction fromHTML() {\n return null;\n}\n\n/** Same pattern as divider's/embed's slash command: a canvas has no run of its own to focus into, so seed and focus a following paragraph. */\nfunction insertCanvasCommand(store, { blockId, runId, sliceStart, sliceEnd }) {\n const run = store.getRun(runId);\n const value = run?.value ?? '';\n store.applyOperation(updateRun(runId, { value: value.slice(0, sliceStart) + value.slice(sliceEnd) }));\n const canvasId = insertSiblingAfter(store, blockId, createCanvasBlock());\n insertSiblingAfterAndFocus(store, canvasId, createTextLeafBlock('paragraph'));\n return canvasId;\n}\n\nexport const canvasBlockType = {\n component: CanvasBlock,\n isLeaf: true, // contentIds always [] — a pure widget, same convention as divider/embed\n defaultProps: { strokes: [], shapes: [], width: DEFAULT_CANVAS_WIDTH, height: DEFAULT_CANVAS_HEIGHT },\n toHTML,\n toPlainText,\n fromHTML,\n slashCommand: {\n label: 'Canvas',\n icon: ScribbleIcon,\n keywords: ['canvas', 'draw', 'drawing', 'sketch', 'freehand'],\n run: insertCanvasCommand,\n },\n};\n","import { paragraphBlockType } from './paragraph/index.js';\r\nimport { headingBlockType } from './heading/index.js';\r\nimport { listItemBlockType } from './listItem/index.js';\r\nimport { tableBlockType, tableRowBlockType, tableCellBlockType } from './table/index.js';\r\nimport { layoutBlockType, layoutColumnBlockType } from './layout/index.js';\r\nimport { dividerBlockType } from './divider/index.js';\r\nimport { calloutBlockType } from './callout/index.js';\r\nimport { blockquoteBlockType } from './blockquote/index.js';\r\nimport { codeBlockType } from './code/index.js';\r\nimport { toggleHeadingBlockType } from './toggleHeading/index.js';\r\nimport { buttonBlockType } from './button/index.js';\r\nimport { embedBlockType } from './embed/index.js';\r\nimport { canvasBlockType } from './canvas/index.js';\r\n\r\n/** Registers every built-in block type on the given registry. */\r\nexport function registerBuiltInBlocks(registry) {\r\n registerBlocks(registry, {\r\n paragraph: paragraphBlockType,\r\n heading: headingBlockType,\r\n listItem: listItemBlockType,\r\n ...TABLE_BLOCKS,\r\n ...LAYOUT_BLOCKS,\r\n divider: dividerBlockType,\r\n callout: calloutBlockType,\r\n blockquote: blockquoteBlockType,\r\n code: codeBlockType,\r\n toggleHeading: toggleHeadingBlockType,\r\n button: buttonBlockType,\r\n embed: embedBlockType,\r\n canvas: canvasBlockType,\r\n });\r\n}\r\n\r\n/**\r\n * Registers only the block types you name — the opt-in counterpart to\r\n * `registerBuiltInBlocks`, for a consumer who wants (say) just paragraph,\r\n * heading, and table, with nothing else's code even reachable from their\r\n * bundle. `blocksByType` is `{ [type]: blockTypeEntry }`; every built-in\r\n * block type object below (`paragraphBlockType`, `tableBlockType`, ...) is\r\n * published individually for exactly this purpose — plain, tree-shakeable\r\n * values, not something living only inside this file's own registration\r\n * call.\r\n *\r\n * `table` and `layout` are each three/two block types that only work\r\n * together (a table with no `tableRow`/`tableCell` registered can't render\r\n * its own rows) — see `TABLE_BLOCKS`/`LAYOUT_BLOCKS` below, spread the\r\n * whole group in rather than picking pieces of one apart.\r\n */\r\nexport function registerBlocks(registry, blocksByType) {\r\n for (const [type, entry] of Object.entries(blocksByType)) {\r\n registry.register(type, entry);\r\n }\r\n}\r\n\r\n/** `table` needs its row/cell block types registered alongside it — spread this whole group in together. */\r\nexport const TABLE_BLOCKS = {\r\n table: tableBlockType,\r\n tableRow: tableRowBlockType,\r\n tableCell: tableCellBlockType,\r\n};\r\n\r\n/** `layout` needs its column block type registered alongside it — spread this whole group in together. */\r\nexport const LAYOUT_BLOCKS = {\r\n layout: layoutBlockType,\r\n layoutColumn: layoutColumnBlockType,\r\n};\r\n\r\nexport {\r\n paragraphBlockType,\r\n headingBlockType,\r\n listItemBlockType,\r\n tableBlockType,\r\n tableRowBlockType,\r\n tableCellBlockType,\r\n layoutBlockType,\r\n layoutColumnBlockType,\r\n dividerBlockType,\r\n calloutBlockType,\r\n blockquoteBlockType,\r\n codeBlockType,\r\n toggleHeadingBlockType,\r\n buttonBlockType,\r\n embedBlockType,\r\n canvasBlockType,\r\n};\r\n","import { useCallback } from 'react';\r\nimport { useRun } from '../../react/useBlock.js';\r\nimport { useEditorStore } from '../../react/EditorProvider.jsx';\r\nimport { updateRun } from '../../store/operations.js';\r\nimport { Select } from '../../react/Select.jsx';\r\n\r\n/**\r\n * An atomic inline \"chip\" mixed directly into running text — e.g. a\r\n * diagnosis/complaint picker inside a paragraph, exactly like the old\r\n * notevo schema's inline `type: 'select'` runs. `EditableBlockContent`\r\n * mounts this into an imperatively-managed host element that carries\r\n * `data-run-id`/`contentEditable={false}` itself (via a React portal) — this\r\n * component only renders its own inner content/styling.\r\n *\r\n * Renders the shared searchable `Select` combobox — no inline add/remove-\r\n * option UI. A chip inserted via the `/select` command starts with an empty\r\n * options list (see index.js's slashCommand); populating/editing that list\r\n * is left to a host app's own options-source integration (see\r\n * createSelectFieldType for a full, named/reusable version of that idea),\r\n * to be revisited later.\r\n */\r\nexport function SelectInlineNode({ id }) {\r\n const store = useEditorStore();\r\n const run = useRun(id);\r\n\r\n const handleChange = useCallback(\r\n (selectedValue) => {\r\n store.applyOperation(updateRun(id, { data: { ...run?.data, selectedValue } }));\r\n },\r\n [store, id, run?.data],\r\n );\r\n\r\n if (!run) return null;\r\n const { options = [], selectedValue = '', placeholder = 'Select…' } = run.data ?? {};\r\n\r\n return (\r\n <span\r\n className=\"be-inline-select\"\r\n // preventDefault too, not just stopPropagation: the browser's default\r\n // mousedown action collapses the surrounding paragraph's text\r\n // selection/caret to wherever was clicked, even for a click that\r\n // lands on a nested non-text control like the Select's trigger\r\n // button or its search input — without this, that default caret-\r\n // collapse wins the timing race against Select's own\r\n // inputRef.current.focus() (called from a useEffect once the\r\n // popover mounts), so the very first character typed lands back in\r\n // the paragraph instead of the search box (same rationale as\r\n // FloatingToolbar's identical onMouseDown preventDefault).\r\n onMouseDown={(event) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }}\r\n // React re-dispatches bubbling synthetic events along the *React*\r\n // tree, not the physical DOM tree — since this chip is mounted via a\r\n // portal, a keydown on the Select below would otherwise still reach\r\n // EditableBlockContent's own onKeyDown and can be misread as e.g.\r\n // \"Backspace next to this chip\", deleting the whole chip instead of\r\n // just interacting with the dropdown.\r\n onKeyDown={(event) => event.stopPropagation()}\r\n >\r\n <Select value={selectedValue} options={options} onChange={handleChange} placeholder={placeholder} ariaLabel=\"Select an option\" />\r\n </span>\r\n );\r\n}\r\n","import { genId } from '../../utils/idGen.js';\r\nimport { replaceRunSpan } from '../../store/operations.js';\r\nimport { focusRunEnd } from '../../react/focusRun.js';\r\n\r\n/**\r\n * Splices a newly-created inline run in at the *exact* cursor position\r\n * (sliceStart/sliceEnd bracket the \"/query\" text that triggered it) —\r\n * splitting the triggering run into three: whatever came before the \"/\",\r\n * the new atomic chip, and whatever came after the cursor. This is what\r\n * makes the chip land where you actually typed \"/\", not always at the end\r\n * of the block — a run with only \"before\" text and no \"after\" (cursor was\r\n * at the end) still gets an empty trailing run so there's somewhere to\r\n * keep typing past the chip. The \"before\" run keeps the original run's id\r\n * so its DOM span isn't remounted.\r\n */\r\nexport function insertInlineRunAtCursor(store, { blockId, runId, sliceStart, sliceEnd }, createInlineRun) {\r\n const currentRun = store.getRun(runId);\r\n const value = currentRun?.value ?? '';\r\n const beforeText = value.slice(0, sliceStart);\r\n const afterText = value.slice(sliceEnd);\r\n\r\n const inlineRun = createInlineRun();\r\n const beforeRun = { ...currentRun, value: beforeText };\r\n const afterRun = { id: genId(), type: 'text', value: afterText, marks: { ...currentRun?.marks } };\r\n\r\n store.applyOperation(replaceRunSpan(blockId, [runId], [beforeRun, inlineRun, afterRun]));\r\n focusRunEnd(afterRun.id);\r\n}\r\n","import { SelectInlineNode } from './SelectInlineNode.jsx';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { insertInlineRunAtCursor } from '../shared/insertInlineRun.js';\r\nimport { SelectIcon } from '../../react/icons.jsx';\r\n\r\nfunction escapeAttr(str) {\r\n return String(str).replace(/&/g, '&amp;').replace(/\"/g, '&quot;');\r\n}\r\n\r\nfunction selectedLabel(run) {\r\n const { options = [], selectedValue = '' } = run.data ?? {};\r\n return options.find((opt) => opt.value === selectedValue)?.label ?? '';\r\n}\r\n\r\nfunction toHTML(run) {\r\n const label = selectedLabel(run) || run.data?.placeholder || '';\r\n return `<span data-inline-type=\"select\" data-selected-value=\"${escapeAttr(run.data?.selectedValue ?? '')}\">${label}</span>`;\r\n}\r\n\r\nfunction toPlainText(run) {\r\n return selectedLabel(run);\r\n}\r\n\r\n/**\r\n * Only claims nodes carrying our own `data-inline-type=\"select\"` marker —\r\n * i.e. lossless same-editor round-trips (the app-specific clipboard JSON\r\n * path already round-trips runs directly without going through HTML at\r\n * all; this fromHTML exists for the text/html clipboard fallback). Foreign\r\n * HTML from another app has no such marker and correctly falls through to\r\n * plain text, since there's no way to know what a \"select\" from another\r\n * app's DOM even means.\r\n */\r\nfunction fromHTML(node) {\r\n if (node.getAttribute?.('data-inline-type') !== 'select') return null;\r\n return {\r\n id: genId(),\r\n type: 'select',\r\n value: '',\r\n marks: {},\r\n data: {\r\n options: [],\r\n selectedValue: node.getAttribute('data-selected-value') ?? '',\r\n },\r\n };\r\n}\r\n\r\nexport const selectInlineType = {\r\n component: SelectInlineNode,\r\n isAtomic: true,\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: {\r\n label: 'Select',\r\n icon: SelectIcon,\r\n keywords: ['select', 'dropdown', 'choice', 'picker'],\r\n run: (store, { blockId, runId, sliceStart, sliceEnd }) =>\r\n insertInlineRunAtCursor(store, { blockId, runId, sliceStart, sliceEnd }, () => ({\r\n id: genId(),\r\n type: 'select',\r\n value: '',\r\n marks: {},\r\n data: { options: [], selectedValue: '', placeholder: 'Select…' },\r\n })),\r\n },\r\n};\r\n","import { useCallback } from 'react';\r\nimport { useRun } from '../../react/useBlock.js';\r\nimport { useEditorStore } from '../../react/EditorProvider.jsx';\r\nimport { updateRun } from '../../store/operations.js';\r\n\r\n/**\r\n * An atomic date chip — a real <input type=\"date\">, proving the inline\r\n * mechanism generalizes to arbitrary native controls, not just <select>\r\n * (see selectInlineType). `EditableBlockContent` mounts this into an\r\n * imperatively-managed host element that carries `data-run-id`/\r\n * `contentEditable={false}` itself (via a React portal) — this component\r\n * only renders its own inner content/styling.\r\n */\r\nexport function DateInlineNode({ id }) {\r\n const store = useEditorStore();\r\n const run = useRun(id);\r\n\r\n const handleChange = useCallback(\r\n (event) => {\r\n store.applyOperation(updateRun(id, { data: { ...run?.data, isoDate: event.target.value } }));\r\n },\r\n [store, id, run?.data],\r\n );\r\n\r\n if (!run) return null;\r\n const { isoDate = '' } = run.data ?? {};\r\n\r\n return (\r\n <span\r\n className=\"be-inline-date\"\r\n onMouseDown={(event) => event.stopPropagation()}\r\n // See SelectInlineNode's onKeyDown comment: without this, a keydown on\r\n // the date input (e.g. Backspace while editing it) still reaches\r\n // EditableBlockContent's onKeyDown via React's portal-following\r\n // synthetic bubbling, and can be misread as deleting this whole chip.\r\n onKeyDown={(event) => event.stopPropagation()}\r\n >\r\n <input type=\"date\" value={isoDate} onChange={handleChange} />\r\n </span>\r\n );\r\n}\r\n","import { DateInlineNode } from './DateInlineNode.jsx';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { insertInlineRunAtCursor } from '../shared/insertInlineRun.js';\r\nimport { DateIcon } from '../../react/icons.jsx';\r\n\r\nfunction escapeAttr(str) {\r\n return String(str).replace(/&/g, '&amp;').replace(/\"/g, '&quot;');\r\n}\r\n\r\nfunction formatDate(isoDate) {\r\n if (!isoDate) return '';\r\n const parsed = new Date(`${isoDate}T00:00:00`);\r\n if (Number.isNaN(parsed.getTime())) return isoDate;\r\n return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\r\n}\r\n\r\nfunction toHTML(run) {\r\n const isoDate = run.data?.isoDate ?? '';\r\n return `<span data-inline-type=\"date\" data-iso-date=\"${escapeAttr(isoDate)}\">${formatDate(isoDate)}</span>`;\r\n}\r\n\r\nfunction toPlainText(run) {\r\n return formatDate(run.data?.isoDate ?? '');\r\n}\r\n\r\n/** Only claims our own `data-inline-type=\"date\"` marker — see select's fromHTML for why. */\r\nfunction fromHTML(node) {\r\n if (node.getAttribute?.('data-inline-type') !== 'date') return null;\r\n return {\r\n id: genId(),\r\n type: 'date',\r\n value: '',\r\n marks: {},\r\n data: { isoDate: node.getAttribute('data-iso-date') ?? '' },\r\n };\r\n}\r\n\r\nfunction todayIso() {\r\n return new Date().toISOString().slice(0, 10);\r\n}\r\n\r\nexport const dateInlineType = {\r\n component: DateInlineNode,\r\n isAtomic: true,\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: {\r\n label: 'Date',\r\n icon: DateIcon,\r\n keywords: ['date', 'when', 'schedule', 'calendar'],\r\n run: (store, { blockId, runId, sliceStart, sliceEnd }) =>\r\n insertInlineRunAtCursor(store, { blockId, runId, sliceStart, sliceEnd }, () => ({\r\n id: genId(),\r\n type: 'date',\r\n value: '',\r\n marks: {},\r\n data: { isoDate: todayIso() },\r\n })),\r\n },\r\n};\r\n","import { useCallback } from 'react';\r\nimport { useRun } from '../../react/useBlock.js';\r\nimport { useEditorStore } from '../../react/EditorProvider.jsx';\r\nimport { updateRun } from '../../store/operations.js';\r\n\r\n/**\r\n * An atomic checkbox-with-label chip — pairs a toggle with its own free-text\r\n * label (e.g. \"Diagnosis confirmed ☑\") in one unit, distinct from a to-do\r\n * list item's `props.checked` (that's block-level state for a whole line;\r\n * this is inline content mixed into running text or, more commonly, a\r\n * table cell — see the \"checkbox\" table column type).\r\n */\r\nexport function CheckboxInlineNode({ id }) {\r\n const store = useEditorStore();\r\n const run = useRun(id);\r\n\r\n const handleCheckedChange = useCallback(\r\n (event) => {\r\n store.applyOperation(updateRun(id, { data: { ...run?.data, checked: event.target.checked } }));\r\n },\r\n [store, id, run?.data],\r\n );\r\n\r\n const handleLabelChange = useCallback(\r\n (event) => {\r\n store.applyOperation(updateRun(id, { data: { ...run?.data, label: event.target.value } }));\r\n },\r\n [store, id, run?.data],\r\n );\r\n\r\n if (!run) return null;\r\n const { checked = false, label = '' } = run.data ?? {};\r\n\r\n return (\r\n <span\r\n className=\"be-inline-checkbox\"\r\n onMouseDown={(event) => event.stopPropagation()}\r\n // See SelectInlineNode's onKeyDown comment for why this is needed.\r\n onKeyDown={(event) => event.stopPropagation()}\r\n >\r\n <input type=\"checkbox\" className=\"be-inline-checkbox-input\" checked={checked} onChange={handleCheckedChange} />\r\n <input\r\n type=\"text\"\r\n className=\"be-inline-checkbox-label\"\r\n value={label}\r\n onChange={handleLabelChange}\r\n placeholder=\"Label…\"\r\n />\r\n </span>\r\n );\r\n}\r\n","import { CheckboxInlineNode } from './CheckboxInlineNode.jsx';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { insertInlineRunAtCursor } from '../shared/insertInlineRun.js';\r\nimport { CheckboxIcon } from '../../react/icons.jsx';\r\n\r\nfunction escapeHTML(str) {\r\n return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\r\n}\r\n\r\nfunction escapeAttr(str) {\r\n return escapeHTML(str).replace(/\"/g, '&quot;');\r\n}\r\n\r\nfunction toHTML(run) {\r\n const { checked = false, label = '' } = run.data ?? {};\r\n return `<span data-inline-type=\"checkbox\" data-checked=\"${checked}\">${checked ? '☑' : '☐'} ${escapeHTML(label)}</span>`;\r\n}\r\n\r\nfunction toPlainText(run) {\r\n const { checked = false, label = '' } = run.data ?? {};\r\n return `${checked ? '[x]' : '[ ]'} ${label}`.trim();\r\n}\r\n\r\n/** Only claims our own `data-inline-type=\"checkbox\"` marker — see select's fromHTML for why. */\r\nfunction fromHTML(node) {\r\n if (node.getAttribute?.('data-inline-type') !== 'checkbox') return null;\r\n return {\r\n id: genId(),\r\n type: 'checkbox',\r\n value: '',\r\n marks: {},\r\n data: { checked: node.getAttribute('data-checked') === 'true', label: (node.textContent ?? '').replace(/^[☑☐]\\s*/, '') },\r\n };\r\n}\r\n\r\nexport const checkboxInlineType = {\r\n component: CheckboxInlineNode,\r\n isAtomic: true,\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: {\r\n label: 'Checkbox',\r\n icon: CheckboxIcon,\r\n keywords: ['checkbox', 'todo', 'check', 'toggle'],\r\n run: (store, { blockId, runId, sliceStart, sliceEnd }) =>\r\n insertInlineRunAtCursor(store, { blockId, runId, sliceStart, sliceEnd }, () => ({\r\n id: genId(),\r\n type: 'checkbox',\r\n value: '',\r\n marks: {},\r\n data: { checked: false, label: '' },\r\n })),\r\n },\r\n};\r\n","import { useCallback } from 'react';\r\nimport { useRun, useBlock } from '../../react/useBlock.js';\r\nimport { useEditorStore } from '../../react/EditorProvider.jsx';\r\nimport { updateRun } from '../../store/operations.js';\r\nimport { resolveColumns } from '../../blocks/table/tableColumns.js';\r\nimport { pickTagColor } from '../../blocks/table/tagColors.js';\r\nimport { Select } from '../../react/Select.jsx';\r\n\r\n/**\r\n * The atomic chip for a table's \"select\" column type — deliberately a\r\n * *different* inline type from the general-purpose `select` (used for\r\n * ad-hoc dropdown chips mixed into paragraph text), not a reuse of it. The\r\n * general one owns its options per-run with its own add/remove-option UI,\r\n * which is right for an independent inline chip but wrong for a table\r\n * column: every cell in a \"select\" column should offer the *same* choices\r\n * and stay in sync when an option is added, renamed, or removed. That\r\n * shared list lives on the table's own `props.columns[i].options` (see\r\n * tableColumns.js) — configured once from the column header's menu, not\r\n * per cell — so this component is intentionally table-aware (it resolves\r\n * its own containing cell -> row -> table via `blockId`, a coupling the\r\n * general inline types don't need and don't have).\r\n *\r\n * `useBlock(tableId)` (not a one-off `store.getBlock`) is what makes this\r\n * re-render when the column's options change elsewhere (the header menu)\r\n * even though this run itself didn't change.\r\n */\r\nexport function TableSelectInlineNode({ id, blockId }) {\r\n const store = useEditorStore();\r\n const run = useRun(id);\r\n\r\n const cell = blockId ? store.getBlock(blockId) : null;\r\n const row = cell ? store.getBlock(cell.parentId) : null;\r\n const tableId = row?.parentId ?? null;\r\n const table = useBlock(tableId);\r\n\r\n const colIndex = row ? row.contentIds.indexOf(blockId) : -1;\r\n const columns = table && row ? resolveColumns(table, row.contentIds.length) : [];\r\n // Fallback for options created before per-option colors existed: derive\r\n // one by position rather than leaving it uncolored, same convention as\r\n // TableHeaderRow's own SelectOptionsManager swatch fallback.\r\n const options = (columns[colIndex]?.options ?? []).map((option, i) => ({\r\n ...option,\r\n color: option.color ?? pickTagColor(i),\r\n }));\r\n\r\n const handleChange = useCallback(\r\n (selectedValue, option) => {\r\n store.applyOperation(updateRun(id, { data: { selectedValue, selectedLabel: option?.label ?? '' } }));\r\n },\r\n [store, id],\r\n );\r\n\r\n if (!run) return null;\r\n const { selectedValue = '' } = run.data ?? {};\r\n\r\n return (\r\n <span\r\n className=\"be-inline-table-select\"\r\n // preventDefault too, not just stopPropagation — see SelectInlineNode's\r\n // onMouseDown comment: without it, the browser's default caret-\r\n // collapse-to-click-position wins the race against Select's own\r\n // focus() call, and the first typed character lands in the\r\n // surrounding cell/paragraph instead of the search box.\r\n onMouseDown={(event) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }}\r\n // See SelectInlineNode's onKeyDown comment for why this is needed.\r\n onKeyDown={(event) => event.stopPropagation()}\r\n >\r\n <Select\r\n value={selectedValue}\r\n options={options}\r\n onChange={handleChange}\r\n placeholder=\"Select…\"\r\n ariaLabel=\"Select an option\"\r\n variant=\"tag\"\r\n />\r\n </span>\r\n );\r\n}\r\n","import { TableSelectInlineNode } from './TableSelectInlineNode.jsx';\r\nimport { genId } from '../../utils/idGen.js';\r\n\r\nfunction escapeHTML(str) {\r\n return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\r\n}\r\n\r\nfunction escapeAttr(str) {\r\n return escapeHTML(str).replace(/\"/g, '&quot;');\r\n}\r\n\r\n// `run.data.selectedLabel` is a denormalized cache of the currently\r\n// selected option's label (kept in sync by TableSelectInlineNode's\r\n// onChange and by setColumnOptions whenever the column's shared options\r\n// change) — deliberately redundant with the column's own options list, so\r\n// toHTML/toPlainText/fromHTML never need table/column context (which\r\n// serialization call sites don't have) to render a sensible value.\r\nfunction toHTML(run) {\r\n const { selectedValue = '', selectedLabel = '' } = run.data ?? {};\r\n return `<span data-inline-type=\"tableSelect\" data-selected-value=\"${escapeAttr(selectedValue)}\">${escapeHTML(selectedLabel)}</span>`;\r\n}\r\n\r\nfunction toPlainText(run) {\r\n return run.data?.selectedLabel ?? '';\r\n}\r\n\r\n/**\r\n * Only claims nodes carrying our own `data-inline-type=\"tableSelect\"`\r\n * marker (see select's fromHTML for why). The reconstructed run has no\r\n * knowledge of which column it'll end up in on paste — the pasted label\r\n * is taken at face value, and its `selectedValue` will only match an\r\n * actual column option again if the destination table happens to have one\r\n * with the same id, which is possible but not guaranteed for a same-editor\r\n * paste; a cross-editor paste always lands as an unmatched value anyway.\r\n */\r\nfunction fromHTML(node) {\r\n if (node.getAttribute?.('data-inline-type') !== 'tableSelect') return null;\r\n return {\r\n id: genId(),\r\n type: 'tableSelect',\r\n value: '',\r\n marks: {},\r\n data: {\r\n selectedValue: node.getAttribute('data-selected-value') ?? '',\r\n selectedLabel: node.textContent ?? '',\r\n },\r\n };\r\n}\r\n\r\nexport const tableSelectInlineType = {\r\n component: TableSelectInlineNode,\r\n isAtomic: true,\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n // No slashCommand: unlike select/date/custom field types, this type is never\r\n // inserted ad-hoc into a paragraph — it only exists inside a table cell\r\n // whose column type has been set to \"select\" (see setColumnType).\r\n};\r\n","/**\r\n * Not an atomic run type at all — an emoji is inserted as plain text (the\r\n * literal unicode character), exactly as selectable/deletable/editable as\r\n * anything else typed there, not a persistent chip. So there's no\r\n * `component`/`toHTML`/`fromHTML`/`slashCommands` here — emoji has its own\r\n * dedicated \":\" trigger (see useEmojiMenuTrigger + emojiCommands.js)\r\n * instead of contributing to the shared \"/\" slash-command list, so this\r\n * entry is registered only for consistency/discoverability (host code that\r\n * enumerates `inlineRegistry` sees an 'emoji' entry) even though it\r\n * currently does nothing on its own.\r\n */\r\nexport const emojiInlineType = {};\r\n","import { selectInlineType } from './select/index.js';\r\nimport { dateInlineType } from './date/index.js';\r\nimport { checkboxInlineType } from './checkbox/index.js';\r\nimport { tableSelectInlineType } from './tableSelect/index.js';\r\nimport { emojiInlineType } from './emoji/index.js';\r\n\r\n/**\r\n * Registers every built-in inline type on the given inline registry. Not\r\n * on this list: \"mention\"-style @-someone chips — those are now just an\r\n * ordinary use of createSelectFieldType with `triggers: ['slash', 'at']`\r\n * (see the example app's \"Assignee\" field type), rather than a separate\r\n * hardcoded built-in, since a real app's roster/search always needs to be\r\n * host-supplied anyway.\r\n */\r\nexport function registerBuiltInInlineTypes(inlineRegistry) {\r\n registerInlineTypes(inlineRegistry, {\r\n select: selectInlineType,\r\n date: dateInlineType,\r\n checkbox: checkboxInlineType,\r\n ...TABLE_SELECT_INLINE_TYPES,\r\n emoji: emojiInlineType,\r\n });\r\n}\r\n\r\n/** Opt-in counterpart to `registerBuiltInInlineTypes` — see registerBlocks's own doc comment, same idea for inline types. */\r\nexport function registerInlineTypes(inlineRegistry, typesByType) {\r\n for (const [type, entry] of Object.entries(typesByType)) {\r\n inlineRegistry.register(type, entry);\r\n }\r\n}\r\n\r\n/** Only relevant alongside TABLE_BLOCKS (see blocks/index.js) — powers a table column set to \"select\" type. */\r\nexport const TABLE_SELECT_INLINE_TYPES = { tableSelect: tableSelectInlineType };\r\n\r\nexport { selectInlineType, dateInlineType, checkboxInlineType, tableSelectInlineType, emojiInlineType };\r\n","import { useMemo } from 'react';\nimport { EditorStore } from '../store/EditorStore.js';\nimport { History } from '../store/history.js';\nimport { createBlockRegistry } from '../registry/blockRegistry.js';\nimport { createInlineRegistry } from '../registry/inlineRegistry.js';\nimport { registerBuiltInBlocks } from '../blocks/index.js';\nimport { registerBuiltInInlineTypes } from '../inlineTypes/index.js';\nimport { genId } from '../utils/idGen.js';\n\nfunction defaultDoc() {\n const rootId = 'root';\n const blockId = genId();\n const runId = genId();\n return {\n rootId,\n blocks: [\n { id: rootId, type: 'page', parentId: null, contentIds: [blockId], props: {} },\n { id: blockId, type: 'paragraph', parentId: rootId, contentIds: [runId], props: {} },\n ],\n runs: [{ id: runId, type: 'text', value: '', marks: {} }],\n };\n}\n\n/**\n * The one-call path to a working editor: creates and memoizes the store\n * (undo/redo-aware by default) plus both registries, pre-populated with\n * every built-in block/inline type, so the common case needs no manual\n * wiring. Pass the result to <NoteloomEditor editor={...} />, or use its\n * `store`/`registry`/`inlineRegistry` fields directly with <EditorProvider>\n * for anything this doesn't cover — nothing here is hidden, just defaulted.\n *\n * `registerBlocks`/`registerInlineTypes` swap in a custom set instead of\n * every built-in type (see the `registerBlocks`/`TABLE_BLOCKS`-style opt-in\n * exports for picking a subset), matching this package's existing\n * opt-in-by-replacement convention rather than an extensions array.\n *\n * The store is created once, on first render — pass a different `doc` and\n * change `key` on the consuming component to load a different document,\n * the same convention used throughout this package's examples.\n *\n * `currentUserId`, if given, is stamped as every edit's `actorId` (see\n * History's `defaultActorId`) with no per-call-site wiring needed —\n * `createAutoVersionHistory`'s own \"who changed this\" attribution reads it\n * straight off the history log this populates. Since the store is only\n * built once, changing `currentUserId` on a later render has no effect —\n * call `editor.store.setDefaultActorId(id)` directly if it can change after\n * mount (e.g. identity resolving asynchronously).\n */\nexport function useEditor({\n doc,\n history = true,\n currentUserId = null,\n registerBlocks: customRegisterBlocks,\n registerInlineTypes: customRegisterInlineTypes,\n} = {}) {\n return useMemo(() => {\n const registry = createBlockRegistry();\n (customRegisterBlocks ?? registerBuiltInBlocks)(registry);\n const inlineRegistry = createInlineRegistry();\n (customRegisterInlineTypes ?? registerBuiltInInlineTypes)(inlineRegistry);\n const store = new EditorStore(doc ?? defaultDoc());\n return { store: history ? new History(store, { defaultActorId: currentUserId }) : store, registry, inlineRegistry };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n}\n","import { useCallback } from 'react';\r\nimport { useEditorStore, usePreviewMode } from './EditorProvider.jsx';\r\nimport { insertSiblingAfterAndFocus } from '../blocks/shared/blockCommands.js';\r\nimport { createTextLeafBlock } from '../blocks/shared/leafBlockFactory.js';\r\nimport { focusBlockEnd } from '../blocks/shared/navigationCommands.js';\r\nimport { ensureRootNonEmpty } from '../blocks/shared/ensureRootNonEmpty.js';\r\n\r\n/**\r\n * Matches every real editor's \"click below the last block to keep writing\"\r\n * affordance: a plain clickable strip below the\r\n * document's own content, sized so there's always somewhere to click even\r\n * when the last block fills the viewport. If the last top-level block is\r\n * already a paragraph, clicking here just moves the caret to its end —\r\n * clicking below your own last paragraph shouldn't create a new empty one\r\n * under it. For anything else (a heading, list, table, embed, ...), there's\r\n * nothing to place a text caret in at that position, so a fresh paragraph\r\n * is inserted after it and focused instead.\r\n *\r\n * A no-op in preview mode (see usePreviewMode) — a preview isn't something\r\n * you edit, so clicking below its content shouldn't create a new block.\r\n */\r\nexport function EditorTrailingSpace({ minHeight = 180, className = 'be-trailing-space' }) {\r\n const store = useEditorStore();\r\n const [isPreviewMode] = usePreviewMode();\r\n\r\n const handleClick = useCallback(() => {\r\n if (isPreviewMode) return;\r\n const rootId = store.getRootId();\r\n const root = store.getBlock(rootId);\r\n const lastId = root?.contentIds?.[root.contentIds.length - 1];\r\n\r\n if (!lastId) {\r\n const fallbackId = ensureRootNonEmpty(store);\r\n if (fallbackId) focusBlockEnd(store, fallbackId);\r\n return;\r\n }\r\n\r\n const lastBlock = store.getBlock(lastId);\r\n if (lastBlock?.type === 'paragraph') {\r\n focusBlockEnd(store, lastId);\r\n } else {\r\n insertSiblingAfterAndFocus(store, lastId, createTextLeafBlock('paragraph'));\r\n }\r\n }, [store, isPreviewMode]);\r\n\r\n return <div className={className} style={{ minHeight }} onClick={handleClick} />;\r\n}\r\n","import { serializeBlockRange } from './serialize.js';\r\n\r\n/**\r\n * Writes a block range to the system clipboard via the async\r\n * `navigator.clipboard` API — used by BlockRangeActionMenu's Copy/Cut\r\n * buttons, which aren't a native `copy`/`cut` ClipboardEvent (those go\r\n * through useClipboardHandlers' synchronous, `event.clipboardData` path\r\n * instead, which is the only one that can carry the app's own lossless\r\n * MIME type — see serialize.js's own doc comment on that risk). The async\r\n * API's `ClipboardItem` support for arbitrary MIME types is inconsistent\r\n * across browsers, so this deliberately only ever writes `text/plain` and\r\n * `text/html` — a paste elsewhere (or back into this editor) still works\r\n * via the same text/html -> domWalk fallback path an external app's copy\r\n * would use, just without the same-editor lossless round-trip.\r\n */\r\nexport async function copyBlockRangeToClipboard(store, registry, inlineRegistry, blockIds) {\r\n const { html, text } = serializeBlockRange(store, registry, blockIds, inlineRegistry);\r\n if (typeof ClipboardItem !== 'undefined' && navigator.clipboard?.write) {\r\n await navigator.clipboard.write([\r\n new ClipboardItem({\r\n 'text/plain': new Blob([text], { type: 'text/plain' }),\r\n 'text/html': new Blob([html], { type: 'text/html' }),\r\n }),\r\n ]);\r\n return;\r\n }\r\n await navigator.clipboard?.writeText?.(text);\r\n}\r\n","import { removeBlock, moveBlock, updateBlockProps } from '../../store/operations.js';\r\nimport { isTurnIntoEligible, turnBlockInto } from './turnInto.js';\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n/**\r\n * Removes every block in `blockIds` (a contiguous run — see\r\n * useBlockRangeDrag) as ONE atomic undo step, regardless of how many\r\n * blocks are in the range. Each `removeBlock` op looks its own target's\r\n * index up fresh at apply time (see EditorStore), so issuing one op per id\r\n * in document order is correct without any special ordering care.\r\n */\r\nexport function deleteBlockRange(store, blockIds) {\r\n if (blockIds.length === 0) return;\r\n applyOps(store, blockIds.map((id) => removeBlock(id)));\r\n}\r\n\r\n/**\r\n * Moves the whole contiguous range up by one sibling position — implemented\r\n * as swapping the range with its immediately preceding sibling (ONE\r\n * `moveBlock` op moving that single neighbor to just after the range's new\r\n * end) rather than moving every block in the range individually. Returns\r\n * false (no-op) if the range is already at the top.\r\n */\r\nexport function moveBlockRangeUp(store, blockIds) {\r\n if (blockIds.length === 0) return false;\r\n const first = store.getBlock(blockIds[0]);\r\n if (!first) return false;\r\n const parent = store.getBlock(first.parentId);\r\n if (!parent) return false;\r\n\r\n const startIndex = parent.contentIds.indexOf(blockIds[0]);\r\n const endIndex = parent.contentIds.indexOf(blockIds[blockIds.length - 1]);\r\n if (startIndex <= 0) return false;\r\n\r\n const precedingId = parent.contentIds[startIndex - 1];\r\n store.applyOperation(moveBlock(precedingId, first.parentId, endIndex));\r\n return true;\r\n}\r\n\r\n/** Symmetric to moveBlockRangeUp — swaps the range with its immediately following sibling. */\r\nexport function moveBlockRangeDown(store, blockIds) {\r\n if (blockIds.length === 0) return false;\r\n const first = store.getBlock(blockIds[0]);\r\n if (!first) return false;\r\n const parent = store.getBlock(first.parentId);\r\n if (!parent) return false;\r\n\r\n const startIndex = parent.contentIds.indexOf(blockIds[0]);\r\n const endIndex = parent.contentIds.indexOf(blockIds[blockIds.length - 1]);\r\n if (endIndex === -1 || endIndex >= parent.contentIds.length - 1) return false;\r\n\r\n const followingId = parent.contentIds[endIndex + 1];\r\n store.applyOperation(moveBlock(followingId, first.parentId, startIndex));\r\n return true;\r\n}\r\n\r\n/** True only if every block in the range is currently hidden — used to decide whether the menu's toggle should read \"Hide\" or \"Show\". */\r\nexport function isEntireBlockRangeHidden(store, blockIds) {\r\n return blockIds.length > 0 && blockIds.every((id) => Boolean(store.getBlock(id)?.props?.hidden));\r\n}\r\n\r\n/** Sets props.hidden on every block in the range, one atomic undo step. */\r\nexport function setBlockRangeHidden(store, blockIds, hidden) {\r\n if (blockIds.length === 0) return;\r\n applyOps(store, blockIds.map((id) => updateBlockProps(id, { hidden })));\r\n}\r\n\r\n/**\r\n * Converts every *eligible* (see `isTurnIntoEligible`) block in the range to\r\n * `target` ({ type, props }), as ONE atomic undo step for the whole range —\r\n * ineligible blocks (table, embed, divider, ...) are silently left\r\n * untouched rather than erroring, matching the same \"skip, don't fail\"\r\n * behavior every reference editor's own multi-select conversion has.\r\n *\r\n * Every block's own `ops` are computed by `turnBlockInto` up front, against\r\n * the store's state as it stood *before* any of this range's conversions\r\n * were applied — each conversion replaces one block with one new block at\r\n * the exact same slot, which never shifts any sibling's index, so it's\r\n * safe to compute every block's ops first (in document order) and apply\r\n * the full concatenated batch only once at the end, rather than\r\n * interleaving compute-then-apply per block.\r\n */\r\nexport function convertBlockRangeType(store, registry, blockIds, target) {\r\n const eligibleIds = blockIds.filter((id) => isTurnIntoEligible(store.getBlock(id)?.type));\r\n if (eligibleIds.length === 0) return;\r\n const allOps = eligibleIds.flatMap((id) => turnBlockInto(store, registry, id, target).ops);\r\n applyOps(store, allOps);\r\n}\r\n\r\n/**\r\n * Re-derives a previously-captured id set's DOCUMENT order from the\r\n * store's current contentIds — used after a move/hide action to keep\r\n * `selectedBlockRange` valid (same ids, correct order) without the caller\r\n * needing to know the tree shape itself.\r\n */\r\nexport function reorderBlockRangeFromStore(store, blockIds) {\r\n if (blockIds.length === 0) return [];\r\n const first = store.getBlock(blockIds[0]);\r\n const parent = first && store.getBlock(first.parentId);\r\n if (!parent) return blockIds;\r\n const idSet = new Set(blockIds);\r\n return parent.contentIds.filter((id) => idSet.has(id));\r\n}\r\n","import { useCallback, useEffect, useRef, useState } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { useEditorStore, useBlockRegistry, useInlineRegistry, useBlockRangeSelection } from './EditorProvider.jsx';\r\nimport { copyBlockRangeToClipboard } from '../clipboard/copyBlockRange.js';\r\nimport { useMenuKeyboardNav } from './useMenuKeyboardNav.js';\r\nimport { useAutoAdjustedPosition } from './useAutoAdjustedPosition.js';\r\nimport { announce } from './liveAnnouncer.js';\r\nimport { TurnIntoSubmenu } from './TurnIntoSubmenu.jsx';\r\nimport { isTurnIntoEligible } from '../blocks/shared/turnInto.js';\r\nimport {\r\n deleteBlockRange,\r\n moveBlockRangeUp,\r\n moveBlockRangeDown,\r\n isEntireBlockRangeHidden,\r\n setBlockRangeHidden,\r\n convertBlockRangeType,\r\n} from '../blocks/shared/blockRangeActions.js';\r\nimport { CopyIcon, ScissorsIcon, TrashIcon, ArrowUpIcon, ArrowDownIcon, EyeIcon, EyeOffIcon } from './icons.jsx';\r\n\r\n/**\r\n * The action menu that appears once a gutter-margin drag (see\r\n * useBlockRangeDrag) finishes selecting a run of blocks — Copy, Cut,\r\n * Delete, Move up/down, Hide/Show in preview, all applied to the whole\r\n * range as one atomic undo step apiece. Mount this once anywhere under\r\n * EditorProvider (it reads useBlockRangeSelection itself, same pattern as\r\n * FieldTypeEditorModal); it renders nothing while nothing is range-selected.\r\n *\r\n * Positioned off the LAST selected block's own row — recomputed on every\r\n * range change (including live, mid-drag), so it visibly follows a\r\n * growing/shrinking selection rather than only appearing once, stale, at\r\n * mouseup.\r\n *\r\n * Outside-click/Escape/Delete are handled with a bespoke listener here\r\n * rather than the shared useOutsideClickAndEscape hook: a click on a\r\n * *different* block's gutter must start a brand-new drag (BlockGutterRow's\r\n * own onMouseDown → startDrag) rather than being swallowed as \"outside\r\n * click, clear the old selection\" — since both listeners are native\r\n * `mousedown` handlers, a generic ref-based exemption can't express \"except\r\n * anywhere with a `.be-block-gutter` ancestor\" the way this needs.\r\n */\r\nexport function BlockRangeActionMenu() {\r\n const store = useEditorStore();\r\n const registry = useBlockRegistry();\r\n const inlineRegistry = useInlineRegistry();\r\n const [selectedBlockRange, setSelectedBlockRange] = useBlockRangeSelection();\r\n const [rect, setRect] = useState(null);\r\n const menuRef = useRef(null);\r\n const turnIntoMenuRef = useRef(null);\r\n\r\n const isOpen = selectedBlockRange.length > 0;\r\n const position = useAutoAdjustedPosition(menuRef, isOpen, rect?.bottom != null ? rect.bottom + 4 : null, rect?.left);\r\n const clear = useCallback(() => setSelectedBlockRange([]), [setSelectedBlockRange]);\r\n // No single \"trigger button\" here (the menu appears after a drag gesture,\r\n // not a click) — passed as undefined, which the hook handles fine; this\r\n // still gets arrow-key/Home/End navigation between its own menu items.\r\n useMenuKeyboardNav(menuRef, isOpen, clear, undefined);\r\n\r\n useEffect(() => {\r\n if (!isOpen) {\r\n setRect(null);\r\n return undefined;\r\n }\r\n\r\n // Recomputed on scroll/resize, not just once per selection change — the\r\n // menu is position:fixed off a getBoundingClientRect() snapshot, which\r\n // is only valid for the instant it was measured. Without this, scrolling\r\n // the page after selecting a range leaves the menu stuck at its old\r\n // viewport position while the actual selected blocks scroll away\r\n // underneath it (exactly the \"menu drifts away from the selection\"\r\n // symptom) instead of staying anchored to the last selected block's row.\r\n const recompute = () => {\r\n const lastId = selectedBlockRange[selectedBlockRange.length - 1];\r\n const el = document.querySelector(`[data-block-row-id=\"${lastId}\"]`);\r\n setRect(el?.getBoundingClientRect() ?? null);\r\n };\r\n recompute();\r\n window.addEventListener('scroll', recompute, true);\r\n window.addEventListener('resize', recompute);\r\n return () => {\r\n window.removeEventListener('scroll', recompute, true);\r\n window.removeEventListener('resize', recompute);\r\n };\r\n }, [isOpen, selectedBlockRange]);\r\n\r\n useEffect(() => {\r\n if (!isOpen) return undefined;\r\n\r\n const handlePointerDown = (event) => {\r\n if (menuRef.current?.contains(event.target)) return;\r\n // The Turn into item's own submenu is a separate portal (a DOM sibling\r\n // of this menu, not a descendant) — without this, a click inside it\r\n // reads as \"outside\", clearing the selection and unmounting the\r\n // submenu before its own click handler ever fires. See\r\n // TurnIntoSubmenu's doc comment for the full story.\r\n if (turnIntoMenuRef.current?.contains(event.target)) return;\r\n if (event.target.closest?.('.be-block-gutter')) return; // let that gutter's own drag-start take over\r\n clear();\r\n };\r\n const handleKeyDown = (event) => {\r\n if (event.key === 'Escape') {\r\n clear();\r\n } else if (event.key === 'Delete' || event.key === 'Backspace') {\r\n event.preventDefault();\r\n deleteBlockRange(store, selectedBlockRange);\r\n clear();\r\n }\r\n };\r\n document.addEventListener('mousedown', handlePointerDown);\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => {\r\n document.removeEventListener('mousedown', handlePointerDown);\r\n document.removeEventListener('keydown', handleKeyDown);\r\n };\r\n }, [isOpen, store, selectedBlockRange, clear]);\r\n\r\n const blockWord = (n) => (n === 1 ? 'block' : 'blocks');\r\n\r\n const handleCopy = useCallback(() => {\r\n copyBlockRangeToClipboard(store, registry, inlineRegistry, selectedBlockRange);\r\n announce(`${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} copied`);\r\n clear();\r\n }, [store, registry, inlineRegistry, selectedBlockRange, clear]);\r\n\r\n const handleCut = useCallback(async () => {\r\n await copyBlockRangeToClipboard(store, registry, inlineRegistry, selectedBlockRange);\r\n const count = selectedBlockRange.length;\r\n deleteBlockRange(store, selectedBlockRange);\r\n announce(`${count} ${blockWord(count)} cut`);\r\n clear();\r\n }, [store, registry, inlineRegistry, selectedBlockRange, clear]);\r\n\r\n const handleDelete = useCallback(() => {\r\n const count = selectedBlockRange.length;\r\n deleteBlockRange(store, selectedBlockRange);\r\n announce(`${count} ${blockWord(count)} deleted`);\r\n clear();\r\n }, [store, selectedBlockRange, clear]);\r\n\r\n // Every action below closes the menu and clears the selection once it's\r\n // done (matching \"click an option, it acts on the selection, the\r\n // selection and menu both go away\" — a host that wants to keep acting on\r\n // the same range repeatedly can just re-drag-select it) — Move up/down\r\n // and Hide/Show used to keep the range selected instead, to allow several\r\n // moves/toggles in a row without reselecting, but a lingering menu after\r\n // an action was already taken read as \"did my click even do anything?\".\r\n const handleMoveUp = useCallback(() => {\r\n if (moveBlockRangeUp(store, selectedBlockRange)) {\r\n announce(`${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} moved up`);\r\n }\r\n clear();\r\n }, [store, selectedBlockRange, clear]);\r\n\r\n const handleMoveDown = useCallback(() => {\r\n if (moveBlockRangeDown(store, selectedBlockRange)) {\r\n announce(`${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} moved down`);\r\n }\r\n clear();\r\n }, [store, selectedBlockRange, clear]);\r\n\r\n const isHidden = isEntireBlockRangeHidden(store, selectedBlockRange);\r\n const handleToggleHidden = useCallback(() => {\r\n setBlockRangeHidden(store, selectedBlockRange, !isHidden);\r\n announce(\r\n isHidden\r\n ? `${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} shown in preview`\r\n : `${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} hidden in preview`,\r\n );\r\n clear();\r\n }, [store, selectedBlockRange, isHidden, clear]);\r\n\r\n const hasEligibleBlock = selectedBlockRange.some((id) => isTurnIntoEligible(store.getBlock(id)?.type));\r\n const handleTurnInto = useCallback(\r\n (target) => {\r\n const count = selectedBlockRange.length;\r\n convertBlockRangeType(store, registry, selectedBlockRange, target);\r\n announce(`${count} ${blockWord(count)} turned into ${target.label}`);\r\n clear();\r\n },\r\n [store, registry, selectedBlockRange, clear],\r\n );\r\n\r\n if (!isOpen || !position) return null;\r\n\r\n return createPortal(\r\n <div\r\n ref={menuRef}\r\n role=\"menu\"\r\n aria-label=\"Selected blocks options\"\r\n className=\"be-block-range-menu\"\r\n style={{ position: 'fixed', top: position.top, left: position.left }}\r\n >\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-range-menu-item\" onClick={handleCopy}>\r\n <CopyIcon size={15} /> Copy\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-range-menu-item\" onClick={handleCut}>\r\n <ScissorsIcon size={15} /> Cut\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-range-menu-item\" onClick={handleMoveUp}>\r\n <ArrowUpIcon size={15} /> Move up\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-range-menu-item\" onClick={handleMoveDown}>\r\n <ArrowDownIcon size={15} /> Move down\r\n </button>\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-range-menu-item\" onClick={handleToggleHidden}>\r\n {isHidden ? <EyeIcon size={15} /> : <EyeOffIcon size={15} />}\r\n {isHidden ? 'Show in preview' : 'Hide in preview'}\r\n </button>\r\n {hasEligibleBlock && (\r\n <TurnIntoSubmenu\r\n onSelect={handleTurnInto}\r\n onClose={() => {}}\r\n containerRef={turnIntoMenuRef}\r\n menuClassName=\"be-block-range-menu\"\r\n itemClassName=\"be-block-range-menu-item\"\r\n />\r\n )}\r\n <button type=\"button\" role=\"menuitem\" className=\"be-block-range-menu-item be-block-range-menu-item-danger\" onClick={handleDelete}>\r\n <TrashIcon size={15} /> Delete\r\n </button>\r\n </div>,\r\n document.body,\r\n );\r\n}\r\n","// Custom clipboard MIME type for lossless same-editor copy/paste round-trips.\r\n// Reliable via the synchronous ClipboardEvent path used in useClipboardHandlers;\r\n// NOT guaranteed via the async navigator.clipboard.write/ClipboardItem API —\r\n// if a toolbar \"Copy\" button is added later, restrict it to text/plain+text/html.\r\nexport const APP_MIME = 'application/x-block-editor-blocks+json';\r\n","import { domInlineToRuns } from '../inline/runOps.js';\r\nimport { genId } from '../utils/idGen.js';\r\n\r\nexport function textToParagraphs(text) {\r\n return text\r\n .split(/\\r\\n|\\r|\\n/)\r\n .filter((line) => line.length > 0)\r\n .map((line) => {\r\n const runId = genId();\r\n return {\r\n block: { id: genId(), type: 'paragraph', parentId: null, contentIds: [runId], props: {} },\r\n runs: [{ id: runId, type: 'text', value: line, marks: {} }],\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Parses an HTML string and walks its top-level nodes, dispatching each to\r\n * whichever registered block type's `fromHTML` claims it (first match\r\n * wins). `<ul>/<ol>` are handled specially here rather than via a matcher,\r\n * since there's no standalone \"list\" block type in this model — only\r\n * `listItem` blocks carrying an `ordered` flag, one per `<li>`.\r\n */\r\nexport function walkDomToBlocks(html, registry, inlineRegistry) {\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n const ctx = { registry, inlineRegistry };\r\n const matchers = registry.listHtmlMatchers();\r\n const results = [];\r\n\r\n const consumeList = (listNode) => {\r\n const ordered = listNode.tagName === 'OL';\r\n const items = [];\r\n for (const li of listNode.children) {\r\n if (li.tagName !== 'LI') continue;\r\n const result = registry.get('listItem')?.fromHTML(li, ctx);\r\n if (result) {\r\n result.block.props.ordered = ordered;\r\n items.push(result);\r\n }\r\n }\r\n return items;\r\n };\r\n\r\n /**\r\n * A <blockquote> with several nested <p>s (a multi-line quote, matching\r\n * what serializeHTML's own grouping now emits) becomes one sibling\r\n * `blockquote` block per <p> — this model keeps multi-line quotes as\r\n * separate leaf siblings rather than one container block. A <blockquote>\r\n * with no nested <p> at all (plain external HTML, just inline content\r\n * directly inside it) falls back to the registered single-block fromHTML.\r\n */\r\n const consumeBlockquote = (bqNode) => {\r\n const paragraphs = Array.from(bqNode.children).filter((c) => c.tagName === 'P');\r\n if (paragraphs.length === 0) {\r\n const result = registry.get('blockquote')?.fromHTML(bqNode, ctx);\r\n return result ? [result] : [];\r\n }\r\n return paragraphs.map((p) => {\r\n const runs = domInlineToRuns(p, ctx);\r\n return {\r\n block: { id: genId(), type: 'blockquote', parentId: null, contentIds: runs.map((r) => r.id), props: {} },\r\n runs,\r\n };\r\n });\r\n };\r\n\r\n for (const node of doc.body.childNodes) {\r\n if (node.nodeType === 3 /* TEXT_NODE */) {\r\n const text = node.textContent.trim();\r\n if (text) results.push(...textToParagraphs(text));\r\n continue;\r\n }\r\n if (node.nodeType !== 1 /* ELEMENT_NODE */) continue;\r\n\r\n if (node.tagName === 'UL' || node.tagName === 'OL') {\r\n results.push(...consumeList(node));\r\n continue;\r\n }\r\n\r\n if (node.tagName === 'BLOCKQUOTE') {\r\n results.push(...consumeBlockquote(node));\r\n continue;\r\n }\r\n\r\n let matched = null;\r\n for (const entry of matchers) {\r\n const result = entry.fromHTML(node, ctx);\r\n if (result) {\r\n matched = result;\r\n break;\r\n }\r\n }\r\n\r\n if (matched) {\r\n results.push(matched);\r\n } else if (node.textContent.trim()) {\r\n const runs = domInlineToRuns(node, ctx);\r\n results.push({\r\n block: { id: genId(), type: 'paragraph', parentId: null, contentIds: runs.map((r) => r.id), props: {} },\r\n runs,\r\n });\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n","import { APP_MIME } from './mimeType.js';\r\nimport { walkDomToBlocks, textToParagraphs } from './domWalk.js';\r\nimport { remapSubtreeIds } from './serialize.js';\r\n\r\n/**\r\n * Given a DataTransfer-like object (real ClipboardEvent.clipboardData, or a\r\n * plain { types, getData } stand-in for tests), returns an array of\r\n * `{ block, runs, subtreeBlocks }` ready to insert. Prefers the lossless\r\n * same-editor payload, falls back to HTML (cross-editor), then plain text.\r\n */\r\nexport function deserializeClipboard(dataTransfer, registry, inlineRegistry) {\r\n const types = dataTransfer.types ?? [];\r\n\r\n if (types.includes(APP_MIME)) {\r\n const json = dataTransfer.getData(APP_MIME);\r\n if (json) return deserializeAppJSON(json);\r\n }\r\n\r\n if (types.includes('text/html')) {\r\n const html = dataTransfer.getData('text/html');\r\n if (html) return walkDomToBlocks(html, registry, inlineRegistry);\r\n }\r\n\r\n const text = dataTransfer.getData('text/plain') ?? '';\r\n return textToParagraphs(text);\r\n}\r\n\r\nfunction deserializeAppJSON(json) {\r\n const payload = JSON.parse(json);\r\n return payload.blocks.map((subtree) => remapSubtreeIds(subtree));\r\n}\r\n","import { genId } from '../utils/idGen.js';\r\nimport { setBlockRuns, removeBlock, insertBlock } from '../store/operations.js';\r\nimport { canMergeTypes } from '../blocks/shared/mergeCommands.js';\r\nimport { createTextLeafBlock } from '../blocks/shared/leafBlockFactory.js';\r\n\r\nfunction getBlockRunIds(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n return block.props?.titleRunIds ?? block.contentIds;\r\n}\r\n\r\nfunction blankRun() {\r\n return { id: genId(), type: 'text', value: '', marks: {} };\r\n}\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\n/**\r\n * Deletes the [startRunId+startOffset, endRunId+endOffset) range from one\r\n * block's own run list. Unlike mark-toggling (applyMarkOverRunSpan), an\r\n * atomic (non-text) run anywhere in the range is simply dropped — there's\r\n * no sensible \"delete the surrounding text but keep the chip\" here. Falls\r\n * back to one blank run if the deletion would leave zero runs (same \"never\r\n * leave a caret-less contentEditable region\" guarantee as\r\n * EditableBlockContent's removeRun/handleInput).\r\n *\r\n * Returns `{ blockId, runId, offset }` for the collapsed caret the\r\n * deletion leaves behind, or null if the range didn't resolve.\r\n */\r\nexport function deleteRunRangeInBlock(store, blockId, selection) {\r\n const { startRunId, startOffset, endRunId, endOffset } = selection;\r\n const runIds = getBlockRunIds(store, blockId);\r\n const startIndex = runIds.indexOf(startRunId);\r\n const endIndex = runIds.indexOf(endRunId);\r\n if (startIndex === -1 || endIndex === -1) return null;\r\n\r\n const [fromIndex, toIndex] = startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\r\n const fromOffset = startIndex <= endIndex ? startOffset : endOffset;\r\n const toOffset = startIndex <= endIndex ? endOffset : startOffset;\r\n\r\n const beforeRuns = runIds.slice(0, fromIndex).map((id) => store.getRun(id));\r\n const afterRuns = runIds.slice(toIndex + 1).map((id) => store.getRun(id));\r\n const spanRuns = runIds.slice(fromIndex, toIndex + 1).map((id) => store.getRun(id));\r\n\r\n const survivors = [];\r\n let caretRunId = null;\r\n let caretOffset = 0;\r\n\r\n if (fromIndex === toIndex) {\r\n const run = spanRuns[0];\r\n if (run.type === 'text') {\r\n const from = Math.max(0, Math.min(fromOffset, toOffset));\r\n const to = Math.min(run.value.length, Math.max(fromOffset, toOffset));\r\n const survivor = { ...run, value: run.value.slice(0, from) + run.value.slice(to) };\r\n survivors.push(survivor);\r\n caretRunId = survivor.id;\r\n caretOffset = from;\r\n } // atomic: dropped entirely, caret resolved from before/after below\r\n } else {\r\n spanRuns.forEach((run, i) => {\r\n if (run.type !== 'text') return; // atomic anywhere in a multi-run range: dropped entirely\r\n const isFirst = i === 0;\r\n const isLast = i === spanRuns.length - 1;\r\n // isFirst/isLast are never both true here — that's the single-run\r\n // case handled above (fromIndex === toIndex).\r\n const prefix = isFirst ? run.value.slice(0, fromOffset) : '';\r\n if (isFirst && prefix) {\r\n const prefixRun = { ...run, value: prefix };\r\n survivors.push(prefixRun);\r\n caretRunId = prefixRun.id;\r\n caretOffset = prefix.length;\r\n }\r\n if (isLast && !isFirst) {\r\n const suffixValue = run.value.slice(toOffset);\r\n if (suffixValue) {\r\n const suffixRun = { id: genId(), type: 'text', value: suffixValue, marks: run.marks };\r\n survivors.push(suffixRun);\r\n if (caretRunId === null) {\r\n caretRunId = suffixRun.id;\r\n caretOffset = 0;\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n let finalRuns = [...beforeRuns, ...survivors, ...afterRuns];\r\n\r\n if (finalRuns.length === 0) {\r\n const blank = blankRun();\r\n finalRuns = [blank];\r\n caretRunId = blank.id;\r\n caretOffset = 0;\r\n } else if (caretRunId === null) {\r\n // Nothing survived from the deleted span itself (e.g. it was a single\r\n // atomic run): land at the boundary — end of whatever's right before,\r\n // or start of whatever's right after.\r\n const lastBefore = beforeRuns[beforeRuns.length - 1];\r\n if (lastBefore) {\r\n caretRunId = lastBefore.id;\r\n caretOffset = lastBefore.type === 'text' ? lastBefore.value.length : 0;\r\n } else if (afterRuns[0]) {\r\n caretRunId = afterRuns[0].id;\r\n caretOffset = 0;\r\n }\r\n }\r\n\r\n store.applyOperation(setBlockRuns(blockId, finalRuns));\r\n return { blockId, runId: caretRunId, offset: caretOffset };\r\n}\r\n\r\n/**\r\n * Deletes a selection spanning *multiple sibling blocks* under a shared\r\n * parent (see resolveCrossBlockSelection) — the same range shape\r\n * toggleMarkOverBlockRange consumes, reused here for deletion instead of\r\n * mark-toggling. This is also what a \"select all\" (twice-pressed Ctrl+A,\r\n * which spans every top-level block under root) funnels through: the\r\n * general logic below naturally handles \"delete the entire document\" as\r\n * the extreme case of \"delete across several sibling blocks\" — no special\r\n * casing needed beyond the final \"did this leave one lone empty\r\n * non-paragraph block?\" check.\r\n *\r\n * Fully-covered blocks strictly between the two boundaries are removed\r\n * outright. The two boundary blocks are trimmed to their surviving prefix/\r\n * suffix; if they're mergeable text types (see canMergeTypes), those\r\n * survivors are combined into ONE remaining block (matching\r\n * mergeWithPreviousOrDelete's merge convention). If they're not mergeable\r\n * (e.g. the range runs from a paragraph into a table cell), both trimmed\r\n * blocks are simply left in place rather than guessing at cross-type\r\n * semantics.\r\n *\r\n * One atomic undo step. Returns `{ blockId, runId, offset }` for the\r\n * resulting caret position, or null if the range didn't resolve.\r\n */\r\nexport function deleteOverBlockRange(store, crossSelection) {\r\n const { blockIds, startBlockId, startRunId, startOffset, endBlockId, endRunId, endOffset } = crossSelection;\r\n if (!blockIds || blockIds.length === 0) return null;\r\n\r\n const startBlockIndex = blockIds.indexOf(startBlockId);\r\n const endBlockIndex = blockIds.indexOf(endBlockId);\r\n if (startBlockIndex === -1 || endBlockIndex === -1) return null;\r\n\r\n const [fromBlockIndex, toBlockIndex] =\r\n startBlockIndex <= endBlockIndex ? [startBlockIndex, endBlockIndex] : [endBlockIndex, startBlockIndex];\r\n const firstIsStart = startBlockIndex <= endBlockIndex;\r\n const firstRunId = firstIsStart ? startRunId : endRunId;\r\n const firstOffset = firstIsStart ? startOffset : endOffset;\r\n const lastRunId = firstIsStart ? endRunId : startRunId;\r\n const lastOffset = firstIsStart ? endOffset : startOffset;\r\n\r\n if (fromBlockIndex === toBlockIndex) {\r\n return deleteRunRangeInBlock(store, blockIds[fromBlockIndex], {\r\n startRunId: firstRunId,\r\n startOffset: firstOffset,\r\n endRunId: lastRunId,\r\n endOffset: lastOffset,\r\n });\r\n }\r\n\r\n const firstBlockId = blockIds[fromBlockIndex];\r\n const lastBlockId = blockIds[toBlockIndex];\r\n const firstBlock = store.getBlock(firstBlockId);\r\n const lastBlock = store.getBlock(lastBlockId);\r\n\r\n const firstRunIds = getBlockRunIds(store, firstBlockId);\r\n const firstIdx = firstRunIds.indexOf(firstRunId);\r\n const firstPrefixRuns = firstRunIds.slice(0, firstIdx).map((id) => store.getRun(id));\r\n const firstRun = store.getRun(firstRunId);\r\n const firstPrefixSurvivor =\r\n firstRun.type === 'text' && firstOffset > 0 ? { ...firstRun, value: firstRun.value.slice(0, firstOffset) } : null;\r\n\r\n const lastRunIds = getBlockRunIds(store, lastBlockId);\r\n const lastIdx = lastRunIds.indexOf(lastRunId);\r\n const lastSuffixRuns = lastRunIds.slice(lastIdx + 1).map((id) => store.getRun(id));\r\n const lastRun = store.getRun(lastRunId);\r\n const lastSuffixSurvivor =\r\n lastRun.type === 'text' && lastOffset < lastRun.value.length\r\n ? { id: genId(), type: 'text', value: lastRun.value.slice(lastOffset), marks: lastRun.marks }\r\n : null;\r\n\r\n const firstSurvivors = [...firstPrefixRuns, ...(firstPrefixSurvivor ? [firstPrefixSurvivor] : [])];\r\n const lastSurvivors = [...(lastSuffixSurvivor ? [lastSuffixSurvivor] : []), ...lastSuffixRuns];\r\n\r\n const ops = [];\r\n for (let i = fromBlockIndex + 1; i < toBlockIndex; i += 1) ops.push(removeBlock(blockIds[i]));\r\n\r\n const mergeable = canMergeTypes(firstBlock.type, lastBlock.type);\r\n const parent = store.getBlock(firstBlock.parentId);\r\n // Only the mergeable branch can ever collapse to a single surviving\r\n // block (the non-mergeable branch always leaves both first and last in\r\n // place) — \"select all, then delete\" is exactly this shape: the merge\r\n // leaves nothing behind, and it was the only two blocks under the\r\n // parent. Every real editor leaves a plain paragraph there, not\r\n // whatever type happened to survive (a now-empty heading, say). Decided\r\n // analytically (without mutating the store first) so the swap can be\r\n // folded into the same ops array — one atomic undo step, not two.\r\n const removedCount = toBlockIndex - fromBlockIndex - 1 + (mergeable ? 1 : 0);\r\n const wouldBeOnlyChild = parent && parent.contentIds.length - removedCount === 1;\r\n\r\n let caretRunId;\r\n let caretOffset;\r\n let survivingBlockId;\r\n\r\n if (mergeable) {\r\n const merged = [...firstSurvivors, ...lastSurvivors];\r\n\r\n if (merged.length === 0 && wouldBeOnlyChild && firstBlock.type !== 'paragraph') {\r\n const { block: fallbackBlock, runs } = createTextLeafBlock('paragraph')(parent.id);\r\n ops.push({ type: 'insertBlock', block: fallbackBlock, parentId: parent.id, index: 0, subtree: { blocks: [fallbackBlock], runs } });\r\n ops.push(removeBlock(firstBlockId));\r\n ops.push(removeBlock(lastBlockId));\r\n applyOps(store, ops);\r\n return { blockId: fallbackBlock.id, runId: fallbackBlock.contentIds[0], offset: 0 };\r\n }\r\n\r\n const finalRuns = merged.length ? merged : [blankRun()];\r\n ops.push(setBlockRuns(firstBlockId, finalRuns));\r\n ops.push(removeBlock(lastBlockId));\r\n survivingBlockId = firstBlockId;\r\n\r\n if (firstPrefixSurvivor) {\r\n caretRunId = firstPrefixSurvivor.id;\r\n caretOffset = firstPrefixSurvivor.value.length;\r\n } else if (firstPrefixRuns.length) {\r\n const last = firstPrefixRuns[firstPrefixRuns.length - 1];\r\n caretRunId = last.id;\r\n caretOffset = last.type === 'text' ? last.value.length : 0;\r\n } else if (lastSuffixSurvivor) {\r\n caretRunId = lastSuffixSurvivor.id;\r\n caretOffset = 0;\r\n } else if (lastSuffixRuns.length) {\r\n caretRunId = lastSuffixRuns[0].id;\r\n caretOffset = 0;\r\n } else {\r\n caretRunId = finalRuns[0].id;\r\n caretOffset = 0;\r\n }\r\n } else {\r\n const firstFinalRuns = firstSurvivors.length ? firstSurvivors : [blankRun()];\r\n ops.push(setBlockRuns(firstBlockId, firstFinalRuns));\r\n ops.push(setBlockRuns(lastBlockId, lastSurvivors.length ? lastSurvivors : [blankRun()]));\r\n survivingBlockId = firstBlockId;\r\n\r\n if (firstPrefixSurvivor) {\r\n caretRunId = firstPrefixSurvivor.id;\r\n caretOffset = firstPrefixSurvivor.value.length;\r\n } else if (firstPrefixRuns.length) {\r\n const last = firstPrefixRuns[firstPrefixRuns.length - 1];\r\n caretRunId = last.id;\r\n caretOffset = last.type === 'text' ? last.value.length : 0;\r\n } else {\r\n caretRunId = firstFinalRuns[0].id;\r\n caretOffset = 0;\r\n }\r\n }\r\n\r\n applyOps(store, ops);\r\n return { blockId: survivingBlockId, runId: caretRunId, offset: caretOffset };\r\n}\r\n\r\n/**\r\n * Deletes every top-level block under the document root and leaves one\r\n * paragraph behind (blank, or seeded with `replacementText` — typing a\r\n * character over a \"whole document selected\" state replaces it, matching\r\n * the standard \"type over a selection\" convention). Deliberately its own,\r\n * much simpler function rather than routed through deleteOverBlockRange:\r\n * a whole-document deletion never needs partial-boundary trimming (unlike\r\n * a cross-sibling-block selection, which stops mid-run at each end), and\r\n * the top-level blocks can be *any* type — including containers like\r\n * tables that don't have a run-based content list at all — so there's\r\n * nothing to trim at the boundaries in the first place, only whole blocks\r\n * to remove.\r\n *\r\n * One atomic undo step. Returns `{ blockId, runId, offset }` for the\r\n * resulting caret position, or null if the document was already empty.\r\n */\r\nexport function deleteEntireDocument(store, replacementText = '') {\r\n const rootId = store.getRootId();\r\n const contentIds = store.getBlock(rootId)?.contentIds ?? [];\r\n if (contentIds.length === 0) return null;\r\n\r\n const ops = contentIds.map((id) => removeBlock(id));\r\n const { block: fallbackBlock, runs } = createTextLeafBlock('paragraph')(rootId);\r\n if (replacementText) runs[0].value = replacementText;\r\n ops.push(insertBlock(fallbackBlock, rootId, 0, { blocks: [fallbackBlock], runs }));\r\n\r\n applyOps(store, ops);\r\n return { blockId: fallbackBlock.id, runId: fallbackBlock.contentIds[0], offset: replacementText.length };\r\n}\r\n","import { useCallback } from 'react';\r\nimport { useEditorStore, useBlockRegistry, useInlineRegistry, useWholeDocumentSelection, useBlockRangeSelection } from './EditorProvider.jsx';\r\nimport { serializeBlockRange } from '../clipboard/serialize.js';\r\nimport { deserializeClipboard } from '../clipboard/deserialize.js';\r\nimport { APP_MIME } from '../clipboard/mimeType.js';\r\nimport { insertBlock, removeBlock, updateRun } from '../store/operations.js';\r\nimport { resolveMultiRunSelection, resolveCrossBlockSelection, resolveCollapsedCaret } from './selectionResolve.js';\r\nimport { deleteRunRangeInBlock, deleteOverBlockRange, deleteEntireDocument } from '../inline/deleteCommands.js';\r\nimport { deleteBlockRange } from '../blocks/shared/blockRangeActions.js';\r\nimport { focusRunAtOffset } from './focusRun.js';\r\n\r\nfunction closestBlockId(node) {\r\n let el = node?.nodeType === 1 ? node : node?.parentElement;\r\n while (el && typeof el.hasAttribute === 'function' && !el.hasAttribute('data-block-id')) {\r\n el = el.parentElement;\r\n }\r\n return el?.getAttribute?.('data-block-id') ?? null;\r\n}\r\n\r\n/**\r\n * v0.1 selection-range resolution: maps the native selection's anchor/focus\r\n * to the nearest [data-block-id] ancestor and, if they differ, to a\r\n * contiguous sibling range under their shared parent. Partial-text selection\r\n * within a single block still copies that block's whole HTML — full\r\n * character-level range slicing is a follow-up once store/selection.js\r\n * (logical {blockId, offset} tracking) is built.\r\n */\r\nfunction resolveSelectedBlockIds(store) {\r\n const selection = window.getSelection?.();\r\n if (!selection || selection.rangeCount === 0) return [];\r\n\r\n const startId = closestBlockId(selection.anchorNode);\r\n const endId = closestBlockId(selection.focusNode);\r\n if (!startId) return [];\r\n if (!endId || startId === endId) return [startId];\r\n\r\n const startBlock = store.getBlock(startId);\r\n const parent = startBlock && store.getBlock(startBlock.parentId);\r\n if (!parent) return [startId];\r\n\r\n const ids = parent.contentIds;\r\n const i1 = ids.indexOf(startId);\r\n const i2 = ids.indexOf(endId);\r\n if (i1 === -1 || i2 === -1) return [startId];\r\n\r\n const [from, to] = i1 <= i2 ? [i1, i2] : [i2, i1];\r\n return ids.slice(from, to + 1);\r\n}\r\n\r\n/** Deletes whatever's currently selected (same-block or cross-sibling-block), if anything. Returns the resulting `{ blockId, runId, offset }`, or null if there was no selection to delete. */\r\nfunction deleteCurrentSelection(store) {\r\n const same = resolveMultiRunSelection();\r\n if (same) return deleteRunRangeInBlock(store, same.blockId, same);\r\n\r\n const cross = resolveCrossBlockSelection(store);\r\n if (cross) return deleteOverBlockRange(store, cross);\r\n\r\n return null;\r\n}\r\n\r\n/** Splices `text` into an existing text run at `caret.offset` — one atomic undo step, in place, no new block. Returns the resulting caret position, or null if `caret` doesn't point at a plain text run. */\r\nfunction insertTextAtCaret(store, caret, text) {\r\n const run = store.getRun(caret.runId);\r\n if (!run || run.type !== 'text') return null;\r\n const value = run.value ?? '';\r\n const newValue = value.slice(0, caret.offset) + text + value.slice(caret.offset);\r\n store.applyOperation(updateRun(run.id, { value: newValue }));\r\n return { blockId: caret.blockId, runId: run.id, offset: caret.offset + text.length };\r\n}\r\n\r\nfunction applyOps(store, ops) {\r\n if (typeof store.performBatch === 'function') store.performBatch(ops);\r\n else for (const op of ops) store.applyOperation(op);\r\n}\r\n\r\nexport function useClipboardHandlers() {\r\n const store = useEditorStore();\r\n const registry = useBlockRegistry();\r\n const inlineRegistry = useInlineRegistry();\r\n const [isWholeDocumentSelected, setIsWholeDocumentSelected] = useWholeDocumentSelection();\r\n const [selectedBlockRange, setSelectedBlockRange] = useBlockRangeSelection();\r\n\r\n const onCopy = useCallback(\r\n (event) => {\r\n // Priority: whole-document select-all > a drag-selected block range\r\n // (see useBlockRangeDrag) > the native browser Selection. Only one of\r\n // these is ever meaningfully active at once in practice (starting\r\n // any of the others clears the rest), but the order still matters if\r\n // more than one happens to be non-empty.\r\n const blockIds = isWholeDocumentSelected\r\n ? (store.getBlock(store.getRootId())?.contentIds ?? [])\r\n : selectedBlockRange.length > 0\r\n ? selectedBlockRange\r\n : resolveSelectedBlockIds(store);\r\n if (blockIds.length === 0) return;\r\n const { html, text, json } = serializeBlockRange(store, registry, blockIds, inlineRegistry);\r\n event.clipboardData.setData('text/plain', text);\r\n event.clipboardData.setData('text/html', html);\r\n event.clipboardData.setData(APP_MIME, json);\r\n event.preventDefault();\r\n },\r\n [store, registry, inlineRegistry, isWholeDocumentSelected, selectedBlockRange],\r\n );\r\n\r\n // Cut = copy, then delete whatever was selected — same \"delete selection\"\r\n // primitive a cross-block Backspace/Delete keypress uses (see\r\n // useEditorKeyboardShortcuts), reused here instead of duplicated. One\r\n // atomic undo step for the deletion (copying doesn't touch the store).\r\n const onCut = useCallback(\r\n (event) => {\r\n onCopy(event);\r\n if (isWholeDocumentSelected) {\r\n const result = deleteEntireDocument(store);\r\n setIsWholeDocumentSelected(false);\r\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\r\n return;\r\n }\r\n if (selectedBlockRange.length > 0) {\r\n deleteBlockRange(store, selectedBlockRange);\r\n setSelectedBlockRange([]);\r\n return;\r\n }\r\n const result = deleteCurrentSelection(store);\r\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\r\n },\r\n [onCopy, store, isWholeDocumentSelected, setIsWholeDocumentSelected, selectedBlockRange, setSelectedBlockRange],\r\n );\r\n\r\n const onPaste = useCallback(\r\n (event) => {\r\n const inserts = deserializeClipboard(event.clipboardData, registry, inlineRegistry);\r\n if (inserts.length === 0) return;\r\n\r\n if (isWholeDocumentSelected) {\r\n const rootId = store.getRootId();\r\n const contentIds = store.getBlock(rootId)?.contentIds ?? [];\r\n const ops = contentIds.map((id) => removeBlock(id));\r\n let rootIndex = 0;\r\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\r\n block.parentId = rootId;\r\n ops.push(insertBlock(block, rootId, rootIndex, { blocks: [block, ...subtreeBlocks], runs }));\r\n rootIndex += 1;\r\n }\r\n applyOps(store, ops);\r\n setIsWholeDocumentSelected(false);\r\n event.preventDefault();\r\n return;\r\n }\r\n\r\n // Same idea, scoped to a drag-selected block range instead of the\r\n // whole document: the range is removed and the pasted block(s) take\r\n // its place, starting at the range's former position.\r\n if (selectedBlockRange.length > 0) {\r\n const first = store.getBlock(selectedBlockRange[0]);\r\n const parentId = first?.parentId ?? null;\r\n const parent = parentId && store.getBlock(parentId);\r\n let index = parent ? parent.contentIds.indexOf(selectedBlockRange[0]) : 0;\r\n\r\n const ops = selectedBlockRange.map((id) => removeBlock(id));\r\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\r\n block.parentId = parentId;\r\n ops.push(insertBlock(block, parentId, index, { blocks: [block, ...subtreeBlocks], runs }));\r\n index += 1;\r\n }\r\n applyOps(store, ops);\r\n setSelectedBlockRange([]);\r\n event.preventDefault();\r\n return;\r\n }\r\n\r\n // Pasting over an active selection replaces it, rather than leaving\r\n // the old selected content sitting next to the newly-inserted\r\n // blocks — same \"delete selection\" primitive as Cut/cross-block\r\n // Backspace. Its own atomic undo step, separate from the insertion\r\n // below.\r\n const deleteResult = deleteCurrentSelection(store);\r\n\r\n // Simple, single-run plain-text paste — by far the common case (a\r\n // word, a phrase, a URL) — splices directly into the run at the\r\n // caret instead of always creating a whole new sibling block,\r\n // a common rich text editor convention. Multi-block or structured clipboard\r\n // content (tables, lists, several paragraphs) still inserts as new\r\n // block(s) after the current one; splitting the current block\r\n // around it is a further follow-up.\r\n const isSimpleTextPaste =\r\n inserts.length === 1 && inserts[0].runs.every((r) => r.type === 'text') && (inserts[0].subtreeBlocks ?? []).length === 0;\r\n\r\n if (isSimpleTextPaste) {\r\n const caret = deleteResult\r\n ? { blockId: deleteResult.blockId, runId: deleteResult.runId, offset: deleteResult.offset }\r\n : resolveCollapsedCaret();\r\n if (caret) {\r\n const text = inserts[0].runs.map((r) => r.value).join('');\r\n const result = insertTextAtCaret(store, caret, text);\r\n if (result) {\r\n focusRunAtOffset(result.runId, result.offset);\r\n event.preventDefault();\r\n return;\r\n }\r\n }\r\n }\r\n\r\n const atBlockId = deleteResult?.blockId ?? closestBlockId(window.getSelection?.()?.anchorNode);\r\n if (!atBlockId) return;\r\n\r\n const current = store.getBlock(atBlockId);\r\n if (!current) return;\r\n const parent = store.getBlock(current.parentId);\r\n let index = parent.contentIds.indexOf(atBlockId) + 1;\r\n\r\n const insertOps = [];\r\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\r\n block.parentId = current.parentId;\r\n insertOps.push(insertBlock(block, current.parentId, index, { blocks: [block, ...subtreeBlocks], runs }));\r\n index += 1;\r\n }\r\n // One atomic undo step for the whole paste, regardless of how many\r\n // blocks it inserts — previously each was its own separate step.\r\n applyOps(store, insertOps);\r\n\r\n event.preventDefault();\r\n },\r\n [store, registry, inlineRegistry, isWholeDocumentSelected, setIsWholeDocumentSelected, selectedBlockRange, setSelectedBlockRange],\r\n );\r\n\r\n return { onCopy, onCut, onPaste };\r\n}\r\n","import { genId } from '../utils/idGen.js';\r\nimport { replaceRunSpan } from '../store/operations.js';\r\n\r\nconst BOOLEAN_MARK_NAMES = ['bold', 'italic', 'underline', 'strike', 'subscript', 'superscript', 'code'];\r\nconst VALUE_MARK_NAMES = ['color', 'highlight', 'link'];\r\n\r\nfunction getBlockRunIds(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n return block.props?.titleRunIds ?? block.contentIds;\r\n}\r\n\r\n// Object-valued marks (link: {href, target}) can be equal in content but\r\n// different references — e.g. after undo/redo, or a copy-pasted link — so\r\n// plain === would spuriously read as \"mixed\" even when every run in range\r\n// really does carry the same link. Primitive marks (color/highlight) are\r\n// unaffected: === already succeeds for them before this ever falls through.\r\nfunction sameMarkValue(a, b) {\r\n if (a === b) return true;\r\n if (a && b && typeof a === 'object') return JSON.stringify(a) === JSON.stringify(b);\r\n return false;\r\n}\r\n\r\nfunction summarizeMarks(runs) {\r\n const summary = {};\r\n if (runs.length === 0) return summary;\r\n for (const name of BOOLEAN_MARK_NAMES) {\r\n summary[name] = runs.every((r) => r.marks?.[name]);\r\n }\r\n for (const name of VALUE_MARK_NAMES) {\r\n const first = runs[0].marks?.[name] ?? null;\r\n summary[name] = runs.every((r) => sameMarkValue(r.marks?.[name] ?? null, first)) ? first : null;\r\n }\r\n return summary;\r\n}\r\n\r\n/**\r\n * Summarizes which marks are uniformly active across a same-block\r\n * selection — used by the floating toolbar to show a button as \"pressed\"\r\n * only when the *entire* selection already has that mark (the same\r\n * all-or-nothing convention toggleMarkOverSelection's own enable/disable\r\n * decision uses), and to read the current color/highlight value when it's\r\n * consistent across the whole selection (null when mixed or unset).\r\n */\r\nexport function getMarksSummaryOverSelection(store, blockId, selection) {\r\n const { startRunId, startOffset, endRunId, endOffset } = selection;\r\n const runIds = getBlockRunIds(store, blockId);\r\n const startIndex = runIds.indexOf(startRunId);\r\n const endIndex = runIds.indexOf(endRunId);\r\n if (startIndex === -1 || endIndex === -1) return {};\r\n const [fromIndex, toIndex] = startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\r\n const runs = runIds\r\n .slice(fromIndex, toIndex + 1)\r\n .map((id) => store.getRun(id))\r\n .filter((r) => r && r.type === 'text');\r\n return summarizeMarks(runs);\r\n}\r\n\r\n/**\r\n * Same idea as getMarksSummaryOverSelection but for a cross-block range.\r\n * Approximates by including every text run in every block the range\r\n * touches (not clipped to the exact sub-range within the first/last\r\n * block) — fine for a toolbar's \"is this button pressed\" indicator, which\r\n * doesn't need character-level precision; the actual mutation\r\n * (setMarksOverBlockRange) is exact.\r\n */\r\nexport function getMarksSummaryOverBlockRange(store, crossSelection) {\r\n const { blockIds, startBlockId, endBlockId } = crossSelection;\r\n const startBlockIndex = blockIds.indexOf(startBlockId);\r\n const endBlockIndex = blockIds.indexOf(endBlockId);\r\n if (startBlockIndex === -1 || endBlockIndex === -1) return {};\r\n const [fromBlockIndex, toBlockIndex] =\r\n startBlockIndex <= endBlockIndex ? [startBlockIndex, endBlockIndex] : [endBlockIndex, startBlockIndex];\r\n\r\n const runs = [];\r\n for (let i = fromBlockIndex; i <= toBlockIndex; i += 1) {\r\n for (const id of getBlockRunIds(store, blockIds[i])) {\r\n const run = store.getRun(id);\r\n if (run && run.type === 'text') runs.push(run);\r\n }\r\n }\r\n return summarizeMarks(runs);\r\n}\r\n\r\n/** Applies a {markName: value} patch to a marks object — value === null/undefined removes that key, anything else sets it. */\r\nfunction applyMarksPatch(marks, marksPatch) {\r\n const next = { ...marks };\r\n for (const [markName, value] of Object.entries(marksPatch)) {\r\n if (value != null) next[markName] = value;\r\n else delete next[markName];\r\n }\r\n return next;\r\n}\r\n\r\n/** Splits one run at [from, to) and applies `marksPatch` to the middle slice; the rest keeps its existing marks. */\r\nfunction applyPatchToSingleRun(store, blockId, run, from, to, marksPatch) {\r\n const nextMarks = applyMarksPatch(run.marks, marksPatch);\r\n\r\n if (from === 0 && to === run.value.length) {\r\n store.applyOperation({ type: 'updateRun', id: run.id, patch: { marks: nextMarks } });\r\n return run.id;\r\n }\r\n\r\n const before = run.value.slice(0, from);\r\n const middle = run.value.slice(from, to);\r\n const after = run.value.slice(to);\r\n\r\n const newRuns = [];\r\n if (before) newRuns.push({ id: genId(), type: 'text', value: before, marks: { ...run.marks } });\r\n const middleRun = { id: genId(), type: 'text', value: middle, marks: nextMarks };\r\n newRuns.push(middleRun);\r\n if (after) newRuns.push({ id: genId(), type: 'text', value: after, marks: { ...run.marks } });\r\n\r\n store.applyOperation(replaceRunSpan(blockId, [run.id], newRuns));\r\n return middleRun.id;\r\n}\r\n\r\n/**\r\n * Applies `marksPatch` — one or more `{markName: value}` entries, value\r\n * `null`/`undefined` meaning \"remove this mark\" and anything else meaning\r\n * \"set it to this value\" — across a run span within one block, which may\r\n * cover one run or several. Applying several marks in the same patch (e.g.\r\n * `{ superscript: true, subscript: null }`, so turning superscript on\r\n * always clears subscript in the same pass) matters because two *sequential*\r\n * calls would each independently split/replace runs and mint new ids, so\r\n * the second call's selection (addressed by run id) could already be stale\r\n * by the time it runs — one patch, one pass, no staleness window.\r\n *\r\n * Atomic (non-text) runs in the span are passed through untouched. This is\r\n * the shared primitive every mark command below (boolean toggle, or a\r\n * value-based mark like color/highlight) ultimately applies per block.\r\n */\r\nfunction applyMarksPatchOverRunSpan(store, blockId, selection, marksPatch) {\r\n const { startRunId, startOffset, endRunId, endOffset } = selection;\r\n const runIds = getBlockRunIds(store, blockId);\r\n const startIndex = runIds.indexOf(startRunId);\r\n const endIndex = runIds.indexOf(endRunId);\r\n if (startIndex === -1 || endIndex === -1) return null;\r\n\r\n const [fromIndex, toIndex] = startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\r\n const fromOffset = startIndex <= endIndex ? startOffset : endOffset;\r\n const toOffset = startIndex <= endIndex ? endOffset : startOffset;\r\n\r\n const rangeRunIds = runIds.slice(fromIndex, toIndex + 1);\r\n const rangeRuns = rangeRunIds.map((id) => store.getRun(id));\r\n\r\n if (fromIndex === toIndex) {\r\n const run = rangeRuns[0];\r\n if (run.type !== 'text') return run.id;\r\n const from = Math.max(0, Math.min(fromOffset, toOffset));\r\n const to = Math.min(run.value.length, Math.max(fromOffset, toOffset));\r\n if (from === to) return run.id;\r\n return applyPatchToSingleRun(store, blockId, run, from, to, marksPatch);\r\n }\r\n\r\n const newRuns = [];\r\n let lastNewRunId = null;\r\n\r\n rangeRuns.forEach((run, i) => {\r\n if (run.type !== 'text') {\r\n newRuns.push(run); // atomic: pass through untouched\r\n lastNewRunId = run.id;\r\n return;\r\n }\r\n\r\n const isFirst = i === 0;\r\n const isLast = i === rangeRuns.length - 1;\r\n const sliceStart = isFirst ? fromOffset : 0;\r\n const sliceEnd = isLast ? toOffset : run.value.length;\r\n\r\n const before = run.value.slice(0, sliceStart);\r\n const middle = run.value.slice(sliceStart, sliceEnd);\r\n const after = run.value.slice(sliceEnd);\r\n\r\n if (before) newRuns.push({ id: genId(), type: 'text', value: before, marks: { ...run.marks } });\r\n\r\n const middleRun = { id: genId(), type: 'text', value: middle, marks: applyMarksPatch(run.marks, marksPatch) };\r\n newRuns.push(middleRun);\r\n lastNewRunId = middleRun.id;\r\n\r\n if (after) newRuns.push({ id: genId(), type: 'text', value: after, marks: { ...run.marks } });\r\n });\r\n\r\n store.applyOperation(replaceRunSpan(blockId, rangeRunIds, newRuns));\r\n return lastNewRunId;\r\n}\r\n\r\n/** Whether every *text* run covered by the range already has the mark (decides enable vs disable for a boolean toggle). */\r\nfunction computeShouldEnableForRange(store, blockId, selection, markName) {\r\n const { startRunId, startOffset, endRunId, endOffset } = selection;\r\n const runIds = getBlockRunIds(store, blockId);\r\n const startIndex = runIds.indexOf(startRunId);\r\n const endIndex = runIds.indexOf(endRunId);\r\n if (startIndex === -1 || endIndex === -1) return true;\r\n const [fromIndex, toIndex] = startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\r\n const textRuns = runIds\r\n .slice(fromIndex, toIndex + 1)\r\n .map((id) => store.getRun(id))\r\n .filter((r) => r.type === 'text');\r\n if (textRuns.length === 0) return true;\r\n if (fromIndex === toIndex) {\r\n const from = Math.max(0, Math.min(startOffset, endOffset));\r\n const to = Math.min(textRuns[0].value.length, Math.max(startOffset, endOffset));\r\n if (from === to) return !textRuns[0].marks?.[markName]; // collapsed: mirror toggleMarkOnRunRange's convention\r\n }\r\n return !textRuns.every((r) => r.marks?.[markName]);\r\n}\r\n\r\n/**\r\n * Toggles `markName` on the [startOffset, endOffset) slice of one run's\r\n * text. Kept as a direct single-run entry point (used when the caller\r\n * already knows it's exactly one run) — internally now just computes the\r\n * enable/disable decision and delegates to applyPatchToSingleRun.\r\n *\r\n * Returns the id of the run that now contains the toggled middle segment\r\n * (or the whole run, if no split was needed) — useful for restoring focus.\r\n */\r\nexport function toggleMarkOnRunRange(store, blockId, runId, startOffset, endOffset, markName) {\r\n const run = store.getRun(runId);\r\n const value = run.value ?? '';\r\n const from = Math.max(0, Math.min(startOffset, endOffset));\r\n const to = Math.min(value.length, Math.max(startOffset, endOffset));\r\n if (from === to) return runId; // collapsed selection: nothing to toggle\r\n\r\n const shouldEnable = !run.marks?.[markName];\r\n return applyPatchToSingleRun(store, blockId, run, from, to, { [markName]: shouldEnable ? true : null });\r\n}\r\n\r\n/**\r\n * Applies an explicit `{markName: value}` patch (see applyMarksPatchOverRunSpan)\r\n * over a selection within one block — the entry point for value-based marks\r\n * (color/highlight, set to a specific picked value) and for any mark whose\r\n * enable/disable decision the caller has already made (e.g. clearing the\r\n * opposite of a mutually-exclusive pair like subscript/superscript\r\n * alongside setting the one being turned on, in the same pass).\r\n */\r\nexport function setMarksOverSelection(store, blockId, selection, marksPatch) {\r\n return applyMarksPatchOverRunSpan(store, blockId, selection, marksPatch);\r\n}\r\n\r\n/**\r\n * Toggles `markName` over a selection that may span *multiple runs within\r\n * the same block* — e.g. selecting \"ello wor\" across \"h[ello] [wor]ld\" where\r\n * the middle word already had a different mark boundary. Atomic (non-text)\r\n * runs caught in the range are passed through unchanged; marks don't apply\r\n * to them.\r\n *\r\n * The whole-range mark state (enable vs disable) is decided by whether\r\n * every *text* run currently in range already has the mark: if so, this\r\n * toggle removes it from all of them; otherwise it adds it to all of them\r\n * — the standard \"toggle bold over a mixed selection turns it fully on\"\r\n * rich-text convention.\r\n *\r\n * Scope: the selection must resolve to a single block (see\r\n * resolveMultiRunSelection). A selection spanning multiple blocks is\r\n * handled by toggleMarkOverBlockRange instead.\r\n */\r\nexport function toggleMarkOverSelection(store, blockId, selection, markName) {\r\n const shouldEnable = computeShouldEnableForRange(store, blockId, selection, markName);\r\n return setMarksOverSelection(store, blockId, selection, { [markName]: shouldEnable ? true : null });\r\n}\r\n\r\n/**\r\n * Toggles `markName` over a selection spanning *multiple sibling blocks*\r\n * (e.g. selecting from the middle of one paragraph through the middle of\r\n * another, a few blocks down). `crossSelection` comes from\r\n * resolveCrossBlockSelection: `{ blockIds, startBlockId, startRunId,\r\n * startOffset, endBlockId, endRunId, endOffset }`, where blockIds is the\r\n * ordered sibling range under a shared parent.\r\n *\r\n * The enable/disable decision is computed ONCE across every text run\r\n * actually spanned in the whole range (not per block), so toggling bold\r\n * across three paragraphs turns it fully on/off consistently everywhere,\r\n * matching toggleMarkOverSelection's same-block convention.\r\n *\r\n * Each affected block gets its own REPLACE_RUN_SPAN operation — this is\r\n * correct but not a single atomic undo step; undoing a cross-block toggle\r\n * currently takes one undo press per affected block. Fully atomic\r\n * cross-block undo is a further follow-up.\r\n */\r\nexport function toggleMarkOverBlockRange(store, crossSelection, markName) {\r\n return setMarksOverBlockRange(store, crossSelection, (allMarked) => ({ [markName]: allMarked ? null : true }), markName);\r\n}\r\n\r\n/**\r\n * Same shape as toggleMarkOverBlockRange, but for an explicit marks patch\r\n * rather than a single boolean toggle — `marksPatchOrFn` is either a plain\r\n * `{markName: value}` object (applied identically to every affected block,\r\n * e.g. a color pick) or a function `(allMarked) => marksPatch` when the\r\n * patch itself depends on the toggle decision (mirrors\r\n * toggleMarkOverBlockRange's own \"decide once across the whole range\"\r\n * semantics — `markNameForDecision` is which mark's presence decides\r\n * `allMarked`, defaulting to the lookup used by the boolean-toggle case).\r\n */\r\nexport function setMarksOverBlockRange(store, crossSelection, marksPatchOrFn, markNameForDecision) {\r\n const { blockIds, startBlockId, startRunId, startOffset, endBlockId, endRunId, endOffset } = crossSelection;\r\n if (!blockIds || blockIds.length === 0) return null;\r\n\r\n const startBlockIndex = blockIds.indexOf(startBlockId);\r\n const endBlockIndex = blockIds.indexOf(endBlockId);\r\n if (startBlockIndex === -1 || endBlockIndex === -1) return null;\r\n\r\n const [fromBlockIndex, toBlockIndex] =\r\n startBlockIndex <= endBlockIndex ? [startBlockIndex, endBlockIndex] : [endBlockIndex, startBlockIndex];\r\n const firstIsStart = startBlockIndex <= endBlockIndex;\r\n const firstRunId = firstIsStart ? startRunId : endRunId;\r\n const firstOffset = firstIsStart ? startOffset : endOffset;\r\n const lastRunId = firstIsStart ? endRunId : startRunId;\r\n const lastOffset = firstIsStart ? endOffset : startOffset;\r\n\r\n let marksPatch = marksPatchOrFn;\r\n if (typeof marksPatchOrFn === 'function') {\r\n let sawText = false;\r\n let allMarked = true;\r\n for (let i = fromBlockIndex; i <= toBlockIndex; i += 1) {\r\n const runs = getBlockRunIds(store, blockIds[i])\r\n .map((id) => store.getRun(id))\r\n .filter((r) => r.type === 'text');\r\n if (runs.length === 0) continue;\r\n sawText = true;\r\n if (!runs.every((r) => r.marks?.[markNameForDecision])) allMarked = false;\r\n }\r\n marksPatch = marksPatchOrFn(sawText && allMarked);\r\n }\r\n\r\n if (fromBlockIndex === toBlockIndex) {\r\n return setMarksOverSelection(\r\n store,\r\n blockIds[fromBlockIndex],\r\n { startRunId: firstRunId, startOffset: firstOffset, endRunId: lastRunId, endOffset: lastOffset },\r\n marksPatch,\r\n );\r\n }\r\n\r\n let lastNewRunId = null;\r\n for (let i = fromBlockIndex; i <= toBlockIndex; i += 1) {\r\n const blockId = blockIds[i];\r\n const runIds = getBlockRunIds(store, blockId);\r\n const blockFirstRunId = runIds[0];\r\n const blockLastRunId = runIds[runIds.length - 1];\r\n const blockLastRun = store.getRun(blockLastRunId);\r\n const blockLastOffset = blockLastRun?.value?.length ?? 0;\r\n\r\n let selection;\r\n if (i === fromBlockIndex && i === toBlockIndex) {\r\n selection = { startRunId: firstRunId, startOffset: firstOffset, endRunId: lastRunId, endOffset: lastOffset };\r\n } else if (i === fromBlockIndex) {\r\n selection = { startRunId: firstRunId, startOffset: firstOffset, endRunId: blockLastRunId, endOffset: blockLastOffset };\r\n } else if (i === toBlockIndex) {\r\n selection = { startRunId: blockFirstRunId, startOffset: 0, endRunId: lastRunId, endOffset: lastOffset };\r\n } else {\r\n selection = { startRunId: blockFirstRunId, startOffset: 0, endRunId: blockLastRunId, endOffset: blockLastOffset };\r\n }\r\n\r\n lastNewRunId = setMarksOverSelection(store, blockId, selection, marksPatch);\r\n }\r\n\r\n return lastNewRunId;\r\n}\r\n","import { resolveMultiRunSelection, resolveCollapsedCaret } from './selectionResolve.js';\r\nimport { isRunsEmpty } from '../blocks/shared/blockEmpty.js';\r\n\r\nfunction getBlockRunIds(store, blockId) {\r\n const block = store.getBlock(blockId);\r\n return block?.props?.titleRunIds ?? block?.contentIds ?? [];\r\n}\r\n\r\n/**\r\n * True when the current (non-collapsed) selection exactly spans one\r\n * block's own content, start to end. The trigger for promoting a second\r\n * Ctrl+A press from \"select this block\" (already true via native browser\r\n * behavior — Ctrl+A in a focused contentEditable region selects only that\r\n * region by default, no code needed) to \"select the whole document\".\r\n */\r\nexport function isEntireBlockSelected(store) {\r\n const selection = resolveMultiRunSelection();\r\n if (!selection) return false; // collapsed, or already spans multiple blocks\r\n\r\n const { blockId, startRunId, startOffset, endRunId, endOffset } = selection;\r\n const runIds = getBlockRunIds(store, blockId);\r\n if (runIds.length === 0) return false;\r\n\r\n const startIndex = runIds.indexOf(startRunId);\r\n const endIndex = runIds.indexOf(endRunId);\r\n if (startIndex === -1 || endIndex === -1) return false;\r\n\r\n const [fromIndex, toIndex] = startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\r\n const fromOffset = startIndex <= endIndex ? startOffset : endOffset;\r\n const toOffset = startIndex <= endIndex ? endOffset : startOffset;\r\n if (fromIndex !== 0 || toIndex !== runIds.length - 1 || fromOffset !== 0) return false;\r\n\r\n const lastRun = store.getRun(runIds[runIds.length - 1]);\r\n const lastLength = lastRun?.type === 'text' ? (lastRun.value ?? '').length : 1; // atomic run: one selectable \"unit\"\r\n return toOffset === lastLength;\r\n}\r\n\r\n/**\r\n * True when the caret sits in a block with no real content at all — e.g. a\r\n * heading just created from the slash menu, before anything's been typed\r\n * into it. An empty block has nothing for native Ctrl+A to actually\r\n * select, so the resulting selection stays collapsed no matter how many\r\n * times it's pressed — isEntireBlockSelected requires a *non-collapsed*\r\n * selection and can never detect \"fully selected\" for it, meaning a\r\n * second Ctrl+A press would never promote to whole-document mode (the\r\n * exact bug this fixes: select-all silently doing nothing on a freshly\r\n * created, still-empty block, while working fine on one that already had\r\n * text). Treating an empty current block as already \"fully selected\"\r\n * lets the very first Ctrl+A press jump straight to selecting the whole\r\n * document instead — there's nothing meaningful to select in between.\r\n */\r\nexport function isCurrentBlockEmpty(store) {\r\n const caret = resolveCollapsedCaret();\r\n if (!caret) return false;\r\n return isRunsEmpty(store, getBlockRunIds(store, caret.blockId));\r\n}\r\n","import { removeBlock } from '../../store/operations.js';\r\nimport { isContentlessBlock } from './contentless.js';\r\nimport { ensureRootNonEmpty } from './ensureRootNonEmpty.js';\r\nimport { focusRunEnd } from '../../react/focusRun.js';\r\n\r\n/**\r\n * Removes the currently-selected non-editable block (see setSelectedBlockId\r\n * in EditorProvider.jsx) and resolves what happens to focus next: its\r\n * previous sibling, or else its next sibling, or else (it was the only\r\n * block left) whatever ensureRootNonEmpty falls back to. If THAT target is\r\n * itself contentless (two dividers in a row), it becomes newly selected\r\n * (and focused, via tabIndex={-1} — see DividerBlock/EmbedBlock) rather\r\n * than focusing a run that doesn't exist; otherwise its last run is\r\n * focused normally.\r\n *\r\n * Shared by two different call sites that both need this exact resolution:\r\n * EditableBlockContent's own second-press delete (bubbled from whichever\r\n * adjacent text block still has focus throughout) and\r\n * useEditorKeyboardShortcuts' global handler (a Backspace/Delete that\r\n * lands *directly* on the already-selected, already-focused block itself —\r\n * there's no EditableBlockContent wrapping a divider/embed for that press\r\n * to bubble through).\r\n */\r\nexport function deleteSelectedBlockAndRefocus(store, selectedId, setSelectedBlockId) {\r\n const block = store.getBlock(selectedId);\r\n if (!block) {\r\n setSelectedBlockId(null);\r\n return;\r\n }\r\n const parent = store.getBlock(block.parentId);\r\n const idx = parent ? parent.contentIds.indexOf(selectedId) : -1;\r\n const prevId = idx > 0 ? parent.contentIds[idx - 1] : null;\r\n const nextId = idx !== -1 && idx < parent.contentIds.length - 1 ? parent.contentIds[idx + 1] : null;\r\n\r\n store.applyOperation(removeBlock(selectedId));\r\n setSelectedBlockId(null);\r\n const fallbackId = ensureRootNonEmpty(store);\r\n const landId = prevId ?? nextId ?? fallbackId;\r\n if (!landId) return;\r\n\r\n const landBlock = store.getBlock(landId);\r\n if (isContentlessBlock(store, landBlock)) {\r\n setSelectedBlockId(landId);\r\n requestAnimationFrame(() => document.querySelector(`[data-block-id=\"${landId}\"]`)?.focus());\r\n return;\r\n }\r\n\r\n const titleRunIds = landBlock?.props?.titleRunIds;\r\n const lastRunId = landBlock?.contentIds?.[landBlock.contentIds.length - 1] ?? titleRunIds?.[titleRunIds.length - 1];\r\n if (lastRunId) focusRunEnd(lastRunId);\r\n}\r\n","import { focusRunAtOffset } from './focusRun.js';\nimport { focusBlockStart } from '../blocks/shared/navigationCommands.js';\n\n/**\n * Moves the caret to wherever the undo/redo that was just performed should\n * leave it — call this right after a truthy store.undo()/store.redo().\n * Prefers the precise {runId, offset} History derives for a plain text-run\n * edit; falls back to the start of the first still-existing block the\n * entry touched for structural edits (insert/remove/move block, etc.),\n * which don't reduce to one offset but still shouldn't leave focus\n * dangling on whatever had it before (usually a toolbar button, or a DOM\n * node a delete/undo just replaced outright).\n */\nexport function restoreSelectionAfterHistoryChange(store) {\n const selection = store.getPendingSelection?.();\n if (selection) {\n focusRunAtOffset(selection.runId, selection.offset);\n return;\n }\n\n const affectedIds = store.getPendingAffectedBlockIds?.() ?? [];\n const targetBlockId = affectedIds.find((id) => store.getBlock(id));\n if (targetBlockId) focusBlockStart(store, targetBlockId);\n}\n","import { useEffect } from 'react';\r\nimport { useEditorStore, useWholeDocumentSelection, useSelectedBlock } from './EditorProvider.jsx';\r\nimport { toggleMarkOverSelection, toggleMarkOverBlockRange } from '../inline/markCommands.js';\r\nimport { deleteOverBlockRange, deleteEntireDocument } from '../inline/deleteCommands.js';\r\nimport { resolveMultiRunSelection, resolveCrossBlockSelection } from './selectionResolve.js';\r\nimport { isEntireBlockSelected, isCurrentBlockEmpty } from './selectAllCommand.js';\r\nimport { focusRunEnd, focusRunAtOffset } from './focusRun.js';\r\nimport { deleteSelectedBlockAndRefocus } from '../blocks/shared/deleteSelectedBlock.js';\r\nimport { restoreSelectionAfterHistoryChange } from './restoreHistorySelection.js';\r\n\r\nconst MARK_KEYS = { b: 'bold', i: 'italic', u: 'underline' };\r\n\r\n/**\r\n * Wires Ctrl/Cmd+Z (undo), Ctrl/Cmd+Shift+Z or Ctrl/Cmd+Y (redo),\r\n * Ctrl/Cmd+A (select-all, two-stage — see below), Ctrl/Cmd+B/I/U (toggle\r\n * bold/italic/underline on the current selection), and Backspace/Delete\r\n * over a selection spanning multiple blocks, at the container level.\r\n * Undo/redo are no-ops if `store` is a plain EditorStore rather than a\r\n * History instance (optional chaining on store.undo/store.redo).\r\n *\r\n * Mark toggling tries the same-block resolver first (the common case —\r\n * spans one or more runs within one block), then falls back to the\r\n * cross-block resolver for a selection spanning sibling blocks. A\r\n * selection spanning non-sibling blocks (different nesting depths) still\r\n * isn't supported.\r\n *\r\n * Select-all is two-stage, matching every other block editor: native\r\n * Ctrl+A in a focused contentEditable region already\r\n * selects only that block's own content — no code needed for the first\r\n * press. Pressing it *again*, once the whole current block is already\r\n * selected, promotes to a *custom* \"whole document selected\" state (see\r\n * useWholeDocumentSelection) rather than trying to construct a native\r\n * Selection/Range spanning every block — browsers don't reliably support a\r\n * script-constructed Range across multiple independent contentEditable\r\n * islands (each is its own \"editing host\"), which is exactly why this\r\n * editor uses one region per block in the first place. A block editor's\r\n * cross-block \"select all\" highlight isn't native browser text selection\r\n * either, for the same reason.\r\n *\r\n * While the whole document is selected this way: Backspace/Delete clears\r\n * it (via deleteEntireDocument, falling back to one blank paragraph),\r\n * typing a printable character replaces it with that character (matching\r\n * the standard \"type over a selection\" convention), Escape or any other\r\n * key cancels the mode, and Ctrl/Cmd+C/X pick it up in useClipboardHandlers.\r\n *\r\n * Backspace/Delete over an *ordinary* (native, same- or cross-sibling-\r\n * block) selection is handled separately below: a same-block selection is\r\n * left to the existing native-typing + reconcileDomToRuns/beforeinput\r\n * pipeline in EditableBlockContent, which already handles it correctly —\r\n * letting the browser delete across *multiple separate* contentEditable\r\n * regions is what isn't safe.\r\n */\r\nexport function useEditorKeyboardShortcuts(containerRef) {\r\n const store = useEditorStore();\r\n const [isWholeDocumentSelected, setIsWholeDocumentSelected] = useWholeDocumentSelection();\r\n const { getSelectedBlockId, setSelectedBlockId } = useSelectedBlock();\r\n\r\n useEffect(() => {\r\n const container = containerRef.current;\r\n if (!container) return undefined;\r\n\r\n const handleKeyDown = (event) => {\r\n // A non-editable block (image/divider/...) selected pending a second\r\n // Backspace/Delete (see EditableBlockContent's\r\n // selectOrDeleteContentlessNeighbor). Two different situations reach\r\n // here:\r\n // - The keydown bubbled up from an adjacent TEXT block's own\r\n // EditableBlockContent, which already fully handled it (selected\r\n // or deleted, and called preventDefault) — event.defaultPrevented\r\n // is already true, so there's nothing left to do here.\r\n // - The keydown landed *directly* on the already-selected, already-\r\n // focused block itself (a divider/embed has no EditableBlockContent\r\n // of its own to bubble through — see focusAfterMerge, which moves\r\n // real DOM focus onto it once the block that used to hold it was\r\n // deleted for being empty) — event.defaultPrevented is still\r\n // false, so this is the only place that can delete it.\r\n if (getSelectedBlockId() && (event.key === 'Backspace' || event.key === 'Delete') && !event.defaultPrevented) {\r\n event.preventDefault();\r\n // This listener is native (added via addEventListener below) on an\r\n // ancestor of the React root's own delegated event target, so it\r\n // fires *before* React's synthetic onKeyDown dispatch during the\r\n // bubble phase. preventDefault() alone doesn't stop that dispatch —\r\n // without stopPropagation, the same keydown would also reach\r\n // whichever EditableBlockContent still has focus and be handled a\r\n // second time (e.g. re-evaluating its own now-stale neighbor check\r\n // after the divider this call just removed is already gone,\r\n // wrongly merging into the previous block instead of doing nothing).\r\n event.stopPropagation();\r\n deleteSelectedBlockAndRefocus(store, getSelectedBlockId(), setSelectedBlockId);\r\n return;\r\n }\r\n\r\n // Any other key cancels a pending selection, matching\r\n // isWholeDocumentSelected's own \"anything else cancels\" convention\r\n // below.\r\n if (getSelectedBlockId() && event.key !== 'Backspace' && event.key !== 'Delete') {\r\n setSelectedBlockId(null);\r\n }\r\n\r\n const mod = event.metaKey || event.ctrlKey;\r\n\r\n if (mod) {\r\n const key = event.key.toLowerCase();\r\n\r\n if (key === 'z' && !event.shiftKey) {\r\n event.preventDefault();\r\n if (store.undo?.()) restoreSelectionAfterHistoryChange(store);\r\n return;\r\n }\r\n if ((key === 'z' && event.shiftKey) || key === 'y') {\r\n event.preventDefault();\r\n if (store.redo?.()) restoreSelectionAfterHistoryChange(store);\r\n return;\r\n }\r\n if (key === 'a') {\r\n if (isWholeDocumentSelected) return; // already fully selected\r\n if (isEntireBlockSelected(store) || isCurrentBlockEmpty(store)) {\r\n event.preventDefault();\r\n // Deliberately leave the native selection alone (still\r\n // highlighting just the current block) rather than clearing\r\n // it — Ctrl+C/X/V are native browser commands that need an\r\n // active selection/focus target to even dispatch a copy/cut/\r\n // paste event to us at all. Our onCopy/onCut/onPaste always\r\n // check isWholeDocumentSelected first and use every top-level\r\n // block when it's set, so the leftover single-block native\r\n // selection's actual content is never used for anything.\r\n setIsWholeDocumentSelected(true);\r\n }\r\n return; // first press: let native Ctrl+A select the current block\r\n }\r\n if (MARK_KEYS[key]) {\r\n if (isWholeDocumentSelected) return; // formatting over \"select all\" isn't supported yet\r\n event.preventDefault();\r\n const markName = MARK_KEYS[key];\r\n\r\n const sameBlockSelection = resolveMultiRunSelection();\r\n if (sameBlockSelection) {\r\n const newRunId = toggleMarkOverSelection(store, sameBlockSelection.blockId, sameBlockSelection, markName);\r\n if (newRunId) focusRunEnd(newRunId);\r\n return;\r\n }\r\n\r\n const crossBlockSelection = resolveCrossBlockSelection(store);\r\n if (crossBlockSelection) {\r\n const newRunId = toggleMarkOverBlockRange(store, crossBlockSelection, markName);\r\n if (newRunId) focusRunEnd(newRunId);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n if (isWholeDocumentSelected) {\r\n if (event.key === 'Backspace' || event.key === 'Delete') {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n const result = deleteEntireDocument(store);\r\n setIsWholeDocumentSelected(false);\r\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\r\n return;\r\n }\r\n if (event.key.length === 1) {\r\n // typing a printable character over \"select all\" replaces the\r\n // whole document with it, matching every editor's \"type over a\r\n // selection\" convention.\r\n event.preventDefault();\r\n event.stopPropagation();\r\n const result = deleteEntireDocument(store, event.key);\r\n setIsWholeDocumentSelected(false);\r\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\r\n return;\r\n }\r\n // Escape, arrows, or anything else not explicitly handled: just\r\n // cancel the mode and let the key proceed normally.\r\n setIsWholeDocumentSelected(false);\r\n if (event.key === 'Escape') return;\r\n }\r\n\r\n if (event.key === 'Backspace' || event.key === 'Delete') {\r\n const crossSelection = resolveCrossBlockSelection(store);\r\n if (!crossSelection) return; // same-block/collapsed: leave to EditableBlockContent's own handling\r\n\r\n event.preventDefault();\r\n event.stopPropagation(); // this block's own Backspace/Delete handler must not also run\r\n const result = deleteOverBlockRange(store, crossSelection);\r\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\r\n }\r\n };\r\n\r\n const handleMouseDown = () => {\r\n if (isWholeDocumentSelected) setIsWholeDocumentSelected(false);\r\n if (getSelectedBlockId()) setSelectedBlockId(null);\r\n };\r\n\r\n container.addEventListener('keydown', handleKeyDown);\r\n container.addEventListener('mousedown', handleMouseDown);\r\n return () => {\r\n container.removeEventListener('keydown', handleKeyDown);\r\n container.removeEventListener('mousedown', handleMouseDown);\r\n };\r\n }, [containerRef, store, isWholeDocumentSelected, setIsWholeDocumentSelected, getSelectedBlockId, setSelectedBlockId]);\r\n}\r\n","import { useCallback, useEffect, useRef } from 'react';\r\nimport { useEditorStore, useBlockRangeSelection } from './EditorProvider.jsx';\r\n\r\n// Minimum pointer movement (px) before a press counts as an actual drag —\r\n// below this, mouseup fires with nothing selected at all. Keeps a plain\r\n// click in the margin (mousedown+mouseup with no real movement) from\r\n// selecting a block; only a genuine drag gesture does.\r\nconst DRAG_THRESHOLD_PX = 4;\r\n\r\n/** Ids of `anchorId`..`hoverId` inclusive, in document order, among their shared parent's siblings. */\r\nfunction computeRange(store, anchorId, hoverId) {\r\n const anchorBlock = store.getBlock(anchorId);\r\n if (!anchorBlock) return [];\r\n const parent = store.getBlock(anchorBlock.parentId);\r\n if (!parent) return [anchorId];\r\n\r\n const ids = parent.contentIds;\r\n const anchorIndex = ids.indexOf(anchorId);\r\n const hoverIndex = hoverId ? ids.indexOf(hoverId) : anchorIndex;\r\n if (anchorIndex === -1) return [anchorId];\r\n const [from, to] = hoverIndex === -1 ? [anchorIndex, anchorIndex] : [Math.min(anchorIndex, hoverIndex), Math.max(anchorIndex, hoverIndex)];\r\n return ids.slice(from, to + 1);\r\n}\r\n\r\nfunction isCoarsePointer() {\r\n return typeof window !== 'undefined' && window.matchMedia?.('(pointer: coarse)')?.matches === true;\r\n}\r\n\r\n/**\r\n * \"Drag in the margin to select a run of blocks\" mechanic.\r\n * Call this ONCE (e.g. in EditorSurface), passing the same containerRef the\r\n * rest of the surface's own trigger hooks use — it registers a single\r\n * document-level mousedown listener that decides, per press, whether it\r\n * landed somewhere that COULD start a block-range drag:\r\n *\r\n * - Inside a block row's own DOM box (data-block-row-id) but OUTSIDE its\r\n * rendered content (be-block-row-content) — covers both the narrow\r\n * per-block gutter (the +/grip buttons sit there too, so those are\r\n * explicitly excluded) and any empty space to a short block's right.\r\n * - Entirely outside every row's own box, but still within this editor's\r\n * container — covers the wide blank page margins on either side of the\r\n * content column (`.be-surface`'s own `max-width` centering), found by\r\n * whichever row's vertical span contains the click's Y coordinate.\r\n *\r\n * That press only becomes an actual selection once the pointer has moved\r\n * at least DRAG_THRESHOLD_PX from where it went down — a plain click\r\n * (mousedown immediately followed by mouseup, no real movement) selects\r\n * nothing at all. This is a genuine drag-to-select gesture, not a\r\n * click-to-select one; a single block can still be selected by dragging a\r\n * few pixels within its own row.\r\n *\r\n * A press directly on the actual editable content (inside\r\n * be-block-row-content) is deliberately left alone either way, so normal\r\n * click-to-place-caret and native text selection are never hijacked.\r\n *\r\n * Disabled entirely on coarse-pointer (touch) devices — dragging in the\r\n * margin would fight the page's own scroll gesture there, and there's no\r\n * equivalent \"hover to reveal the gutter\" affordance on touch anyway.\r\n */\r\nexport function useBlockRangeDrag(containerRef) {\r\n const store = useEditorStore();\r\n const [, setSelectedBlockRange] = useBlockRangeSelection();\r\n const anchorIdRef = useRef(null); // set from mousedown onward, whether or not the drag has \"armed\" yet\r\n const isArmedRef = useRef(false); // true only once movement has passed DRAG_THRESHOLD_PX\r\n const startPointRef = useRef(null);\r\n\r\n const handleMouseMove = useCallback(\r\n (event) => {\r\n if (!anchorIdRef.current) return;\r\n\r\n if (!isArmedRef.current) {\r\n const { x, y } = startPointRef.current ?? { x: event.clientX, y: event.clientY };\r\n const movedPx = Math.hypot(event.clientX - x, event.clientY - y);\r\n if (movedPx < DRAG_THRESHOLD_PX) return;\r\n isArmedRef.current = true;\r\n // Suppresses native text selection for the rest of this drag —\r\n // preventDefault alone isn't enough once the pointer has crossed\r\n // into real block content: the browser may have already latched\r\n // onto that content as a fresh selection anchor. `user-select:none`\r\n // on the document root is the standard belt-and-braces fix (see\r\n // `.be-block-range-dragging` in the example app's CSS), removed the\r\n // instant the drag ends.\r\n document.documentElement.classList.add('be-block-range-dragging');\r\n window.getSelection?.()?.removeAllRanges();\r\n }\r\n // Also keep clearing it on every subsequent move — some browsers\r\n // still extend a selection that started a frame earlier even with\r\n // user-select:none applied mid-gesture.\r\n window.getSelection?.()?.removeAllRanges();\r\n event.preventDefault();\r\n\r\n const el = document.elementFromPoint(event.clientX, event.clientY)?.closest('[data-block-row-id]');\r\n const hoverId = el?.getAttribute('data-block-row-id') ?? null;\r\n setSelectedBlockRange(computeRange(store, anchorIdRef.current, hoverId));\r\n },\r\n [store, setSelectedBlockRange],\r\n );\r\n\r\n const handleMouseUp = useCallback(() => {\r\n anchorIdRef.current = null;\r\n isArmedRef.current = false;\r\n startPointRef.current = null;\r\n document.documentElement.classList.remove('be-block-range-dragging');\r\n }, []);\r\n\r\n const armDrag = useCallback((blockId, event) => {\r\n anchorIdRef.current = blockId;\r\n isArmedRef.current = false;\r\n startPointRef.current = { x: event.clientX, y: event.clientY };\r\n }, []);\r\n\r\n const handleMouseDown = useCallback(\r\n (event) => {\r\n if (event.button !== 0) return; // left click only\r\n if (isCoarsePointer()) return;\r\n if (event.target.closest?.('button, input, textarea, select')) return;\r\n\r\n const row = event.target.closest('[data-block-row-id]');\r\n if (row) {\r\n // DOM-ancestor check, not a geometry/rect comparison: the previous\r\n // rect-based version only compared clientX against\r\n // be-block-row-content's own bounding box, and (a) never checked Y\r\n // at all, (b) broke down for any block whose content box isn't a\r\n // simple full-width rectangle (wrapped text, an inline chip at the\r\n // end of a short line, a table). Any of those could put a genuine\r\n // click on real content just outside the rect's clientX range,\r\n // misclassifying it as \"margin\" and arming a drag — which doesn't\r\n // itself steal the click, but does mean the *next* mousemove (even\r\n // an incidental few px of jitter before the click properly\r\n // registers) can flip it into an actual drag-select, hijacking\r\n // what the user experienced as a plain click. Walking the DOM via\r\n // closest() instead answers \"is this element actually inside the\r\n // block's own rendered content\" exactly, with no geometry involved.\r\n if (event.target.closest('.be-block-row-content')) return;\r\n armDrag(row.getAttribute('data-block-row-id'), event);\r\n return;\r\n }\r\n\r\n // The press landed entirely outside every row's own DOM box — the\r\n // wide blank page margin on either side of `.be-surface`'s centered\r\n // content column (that margin is never inside any row's own element,\r\n // since each row is only ever as wide as the content column itself).\r\n // Scoped to THIS editor's own rows via containerRef, deliberately\r\n // NOT via container.contains(event.target) — a blank-margin click's\r\n // target is by definition outside the container's own narrower box.\r\n const container = containerRef?.current;\r\n if (!container) return;\r\n const rows = [...container.querySelectorAll('[data-block-row-id]')];\r\n const hovered = rows.find((el) => {\r\n const r = el.getBoundingClientRect();\r\n return event.clientY >= r.top && event.clientY <= r.bottom;\r\n });\r\n if (hovered) {\r\n armDrag(hovered.getAttribute('data-block-row-id'), event);\r\n }\r\n },\r\n [containerRef, armDrag],\r\n );\r\n\r\n useEffect(() => {\r\n document.addEventListener('mousedown', handleMouseDown);\r\n document.addEventListener('mousemove', handleMouseMove);\r\n document.addEventListener('mouseup', handleMouseUp);\r\n return () => {\r\n document.removeEventListener('mousedown', handleMouseDown);\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n document.removeEventListener('mouseup', handleMouseUp);\r\n document.documentElement.classList.remove('be-block-range-dragging'); // in case unmounted mid-drag\r\n };\r\n }, [handleMouseDown, handleMouseMove, handleMouseUp]);\r\n}\r\n","import { useEffect, useRef, useState } from 'react';\r\nimport { useVirtualKeyboardInset } from '../react/useVirtualKeyboardInset.js';\r\nimport { useHorizontalAutoAdjustedLeft } from '../react/usePopoverEdgeClamp.js';\r\n\r\n// Rough worst-case menu height (max-height in .be-slash-menu's own CSS is\r\n// 320px, plus a little padding) — used only to decide *which side* of the\r\n// caret to open on, not as an exact pixel budget, so an approximation here\r\n// is fine either way.\r\nconst ESTIMATED_MENU_HEIGHT = 340;\r\n\r\n/**\r\n * Focus deliberately stays in the run's contentEditable (moving it into the\r\n * menu would exit typing) — so this follows the ARIA \"listbox with\r\n * aria-activedescendant\" pattern: the actively-selected option lives in\r\n * `aria-activedescendant` on whatever *does* have focus (the triggering run\r\n * element), not on the listbox itself. `runId` is what identifies that\r\n * element; its `aria-expanded`/`aria-activedescendant` are set/cleared here\r\n * rather than threaded through every block type, since only this component\r\n * knows the listbox's ids and open/active state.\r\n */\r\nfunction useActiveDescendantWiring(isOpen, runId, activeOptionId, menuId) {\r\n useEffect(() => {\r\n if (!isOpen || !runId) return undefined;\r\n const runEl = document.querySelector(`[data-run-id=\"${runId}\"]`);\r\n if (!runEl) return undefined;\r\n\r\n runEl.setAttribute('aria-expanded', 'true');\r\n runEl.setAttribute('aria-haspopup', 'listbox');\r\n runEl.setAttribute('aria-controls', menuId);\r\n if (activeOptionId) runEl.setAttribute('aria-activedescendant', activeOptionId);\r\n\r\n return () => {\r\n runEl.removeAttribute('aria-expanded');\r\n runEl.removeAttribute('aria-haspopup');\r\n runEl.removeAttribute('aria-controls');\r\n runEl.removeAttribute('aria-activedescendant');\r\n };\r\n }, [isOpen, runId, activeOptionId, menuId]);\r\n}\r\n\r\n/**\r\n * Generic filterable command popover — not slash-specific despite the name\r\n * (kept for backward compatibility), also used as-is for the \":\" emoji menu\r\n * (see useEmojiMenuTrigger). Pass a distinct `menuId`/`ariaLabel` for a\r\n * second simultaneously-mounted instance so DOM ids and\r\n * aria-controls/aria-activedescendant wiring never collide between them.\r\n */\r\nexport function SlashMenu({\r\n isOpen,\r\n rect,\r\n commands,\r\n runId,\r\n onSelect,\r\n onClose,\r\n menuId = 'be-slash-menu',\r\n ariaLabel = 'Slash commands',\r\n}) {\r\n const [activeIndex, setActiveIndex] = useState(0);\r\n const activeItemRef = useRef(null);\r\n const menuRef = useRef(null);\r\n const keyboardInset = useVirtualKeyboardInset();\r\n const adjustedLeft = useHorizontalAutoAdjustedLeft(menuRef, isOpen && commands.length > 0 && Boolean(rect), rect?.left);\r\n\r\n useEffect(() => {\r\n setActiveIndex(0);\r\n }, [commands.length]);\r\n\r\n // Keeps the keyboard-active item visible as Arrow Up/Down moves it past\r\n // the edge of the scrollable list — without this, arrowing past the\r\n // bottom (or top) leaves the highlighted item scrolled out of view with\r\n // nothing on screen showing which one is currently selected.\r\n useEffect(() => {\r\n activeItemRef.current?.scrollIntoView?.({ block: 'nearest' });\r\n }, [activeIndex]);\r\n\r\n useEffect(() => {\r\n if (!isOpen) return undefined;\r\n\r\n const handleKeyDown = (event) => {\r\n if (event.key === 'ArrowDown') {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n setActiveIndex((i) => Math.min(i + 1, Math.max(commands.length - 1, 0)));\r\n } else if (event.key === 'ArrowUp') {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n setActiveIndex((i) => Math.max(i - 1, 0));\r\n } else if (event.key === 'Enter') {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n if (commands[activeIndex]) onSelect(commands[activeIndex]);\r\n } else if (event.key === 'Escape') {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n onClose();\r\n }\r\n };\r\n\r\n // capture phase: must win over EditableBlockContent's own onKeyDown (Enter/etc.)\r\n document.addEventListener('keydown', handleKeyDown, true);\r\n return () => document.removeEventListener('keydown', handleKeyDown, true);\r\n }, [isOpen, commands, activeIndex, onSelect, onClose]);\r\n\r\n const activeCommand = commands[activeIndex];\r\n const activeOptionId = activeCommand ? `${menuId}-option-${activeIndex}` : null;\r\n useActiveDescendantWiring(isOpen, runId, activeOptionId, menuId);\r\n\r\n if (!isOpen || commands.length === 0 || !rect || adjustedLeft == null) return null;\r\n\r\n // Flip to open above the caret instead of below it once there isn't\r\n // enough room left under it before the keyboard (or the bottom of the\r\n // screen) starts — without this, the popover can render partly or\r\n // entirely underneath the on-screen keyboard, invisible.\r\n const availableBottom = window.innerHeight - keyboardInset;\r\n const openAbove = rect.bottom + ESTIMATED_MENU_HEIGHT > availableBottom;\r\n const positionStyle = openAbove\r\n ? { bottom: window.innerHeight - rect.top + 4 }\r\n : { top: rect.bottom + 4 };\r\n\r\n return (\r\n <div\r\n ref={menuRef}\r\n id={menuId}\r\n role=\"listbox\"\r\n aria-label={ariaLabel}\r\n className=\"be-slash-menu\"\r\n style={{ position: 'fixed', left: adjustedLeft, zIndex: 1000, ...positionStyle }}\r\n >\r\n {commands.map((command, i) => {\r\n const Icon = command.icon;\r\n return (\r\n <div\r\n key={command.label}\r\n ref={i === activeIndex ? activeItemRef : undefined}\r\n id={`${menuId}-option-${i}`}\r\n role=\"option\"\r\n aria-selected={i === activeIndex}\r\n className={`be-slash-menu-item${i === activeIndex ? ' be-slash-menu-item-active' : ''}`}\r\n onMouseDown={(event) => {\r\n event.preventDefault();\r\n onSelect(command);\r\n }}\r\n onMouseEnter={() => setActiveIndex(i)}\r\n >\r\n {Icon && (\r\n <span className=\"be-slash-menu-item-icon\">\r\n <Icon size={16} />\r\n </span>\r\n )}\r\n <span className=\"be-slash-menu-item-label\">{command.label}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n","import { useCallback, useEffect, useState } from 'react';\r\nimport { useEditorStore } from '../react/EditorProvider.jsx';\r\nimport { stripEmptyRunPlaceholder } from '../react/domRunSync.js';\r\n\r\nfunction matchesQuery(command, query) {\r\n if (!query) return true;\r\n const q = query.toLowerCase();\r\n return command.label.toLowerCase().includes(q) || command.keywords?.some((k) => k.toLowerCase().includes(q));\r\n}\r\n\r\n/**\r\n * Resolves the caret's logical offset within `runEl`'s text (with the\r\n * empty-run placeholder stripped), regardless of whether the browser's\r\n * selection anchors on the run's text node directly or on the run element\r\n * itself (e.g. a not-yet-populated node). Falls back to \"end of text\" if\r\n * the selection isn't actually inside this element.\r\n */\r\nfunction caretOffsetInRun(runEl, selection) {\r\n const node = selection.anchorNode;\r\n const rawOffset = selection.anchorOffset;\r\n let rawTextBeforeCaret;\r\n\r\n if (node === runEl) {\r\n rawTextBeforeCaret = '';\r\n for (let i = 0; i < rawOffset && i < runEl.childNodes.length; i += 1) {\r\n rawTextBeforeCaret += runEl.childNodes[i].textContent ?? '';\r\n }\r\n } else if (node && node.parentElement === runEl) {\r\n rawTextBeforeCaret = (node.textContent ?? '').slice(0, rawOffset);\r\n } else {\r\n rawTextBeforeCaret = runEl.textContent ?? '';\r\n }\r\n\r\n return stripEmptyRunPlaceholder(rawTextBeforeCaret).length;\r\n}\r\n\r\n/**\r\n * Shared machinery behind both useSlashMenuTrigger (\"/\") and\r\n * useEmojiMenuTrigger (\":\") — watches for `regex` matching the text up to\r\n * the caret within any run inside `containerRef`, and resolves the matching\r\n * commands via `getCommands()`. Each caller only differs in its trigger\r\n * regex and its command source; the caret-resolution/query-matching/\r\n * keyboard-dismiss logic (this file) is identical either way.\r\n *\r\n * `regex` must have exactly two capture groups: group 1 is whatever\r\n * precedes the trigger character (start-of-string or whitespace, so it\r\n * isn't consumed as part of the query), group 2 is the query typed after\r\n * the trigger character.\r\n */\r\nexport function useTriggerMenu(containerRef, regex, getCommands) {\r\n const store = useEditorStore();\r\n const [state, setState] = useState(null); // { query, blockId, runId, sliceStart, sliceEnd, rect }\r\n\r\n useEffect(() => {\r\n const container = containerRef.current;\r\n if (!container) return undefined;\r\n\r\n const handleInput = () => {\r\n const selection = window.getSelection?.();\r\n const anchorNode = selection?.anchorNode;\r\n let el = anchorNode?.nodeType === 1 ? anchorNode : anchorNode?.parentElement;\r\n while (el && typeof el.hasAttribute === 'function' && !el.hasAttribute('data-run-id')) {\r\n el = el.parentElement;\r\n }\r\n const runId = el?.getAttribute?.('data-run-id');\r\n if (!runId || !selection) {\r\n setState(null);\r\n return;\r\n }\r\n\r\n const caretOffset = caretOffsetInRun(el, selection);\r\n const textBeforeCaret = stripEmptyRunPlaceholder(el.textContent).slice(0, caretOffset);\r\n const match = regex.exec(textBeforeCaret);\r\n if (!match) {\r\n setState(null);\r\n return;\r\n }\r\n\r\n const blockId = el.closest?.('[data-block-id]')?.getAttribute('data-block-id');\r\n if (!blockId) {\r\n setState(null);\r\n return;\r\n }\r\n const sliceStart = match.index + match[1].length; // position of the trigger character itself\r\n setState({ query: match[2], blockId, runId, sliceStart, sliceEnd: caretOffset, rect: el.getBoundingClientRect() });\r\n };\r\n\r\n const handleKeyDown = (event) => {\r\n if (event.key === 'Escape') setState(null);\r\n };\r\n\r\n container.addEventListener('input', handleInput);\r\n container.addEventListener('keydown', handleKeyDown);\r\n return () => {\r\n container.removeEventListener('input', handleInput);\r\n container.removeEventListener('keydown', handleKeyDown);\r\n };\r\n }, [containerRef, regex]);\r\n\r\n const commands = state ? getCommands().filter((cmd) => matchesQuery(cmd, state.query)) : [];\r\n\r\n const selectCommand = useCallback(\r\n (command) => {\r\n if (!state) return;\r\n // Deliberately does NOT trim the query text here: a block command\r\n // just wants it gone (trimSlashQueryAndInsertAfter handles that), but\r\n // an inline command needs the untouched sliceStart/sliceEnd to splice\r\n // its chip/text in at the exact cursor position — pre-merging before/\r\n // after text here would destroy that split point.\r\n command.run(store, {\r\n blockId: state.blockId,\r\n runId: state.runId,\r\n sliceStart: state.sliceStart,\r\n sliceEnd: state.sliceEnd,\r\n });\r\n setState(null);\r\n },\r\n [state, store],\r\n );\r\n\r\n const close = useCallback(() => setState(null), []);\r\n\r\n return {\r\n isOpen: Boolean(state),\r\n query: state?.query ?? '',\r\n rect: state?.rect ?? null,\r\n runId: state?.runId ?? null,\r\n commands,\r\n selectCommand,\r\n close,\r\n };\r\n}\r\n","import { useCallback } from 'react';\r\nimport { useBlockRegistry, useInlineRegistry } from '../react/EditorProvider.jsx';\r\nimport { useTriggerMenu } from './useTriggerMenu.js';\r\n\r\n// Matches a \"/\" at the very start of the text, or right after whitespace,\r\n// followed by any word characters, anchored to the END of the string passed\r\n// in — the caller passes only the text *up to the caret*, which is what\r\n// lets \"/\" work with content after the cursor too (\"hello /table| world\"),\r\n// not just when the caret happens to be at the very end of the run.\r\nconst SLASH_RE = /(^|\\s)\\/(\\w*)$/;\r\n\r\n/**\r\n * Watches for \"/\" typed anywhere inside a run within `containerRef` and\r\n * tracks the query typed after it — works mid-block, with other text both\r\n * before and after the trigger in the same run, not just when the caret is\r\n * at the very end of otherwise-empty content. Commands come from both the\r\n * block registry (insert a new block after the current one) and the\r\n * inline-type registry (splice an atomic element in at the cursor) — see\r\n * each type's own `run(store, {blockId, runId})`. Only the matched\r\n * \"/query\" substring is removed on selection (preserving whatever comes\r\n * before *and after* it in the run), not the whole run.\r\n *\r\n * Emoji is its own separate \":\" trigger (see useEmojiMenuTrigger) — not\r\n * merged in here — so it doesn't crowd out every other \"/\" command with\r\n * ~60 emoji entries.\r\n *\r\n * See useTriggerMenu for the shared caret-resolution/query-matching\r\n * machinery this and useEmojiMenuTrigger both build on.\r\n */\r\nexport function useSlashMenuTrigger(containerRef) {\r\n const registry = useBlockRegistry();\r\n const inlineRegistry = useInlineRegistry();\r\n\r\n const getCommands = useCallback(\r\n () => [...registry.listSlashCommands(), ...(inlineRegistry?.listSlashCommands() ?? [])],\r\n [registry, inlineRegistry],\r\n );\r\n\r\n return useTriggerMenu(containerRef, SLASH_RE, getCommands);\r\n}\r\n","/**\r\n * A curated, hardcoded set of common emoji — no external emoji-data\r\n * package (matches this project's zero-runtime-dependency constraint).\r\n * Each entry's `name` doubles as its slash-command label/search keyword;\r\n * `keywords` adds a couple of common synonyms so \"/fire\", \"/heart\", etc.\r\n * find the right one directly, without having to type \"/emoji\" first.\r\n */\r\nexport const EMOJI_LIST = [\r\n { char: '😀', name: 'grinning face', keywords: ['smile', 'happy'] },\r\n { char: '😂', name: 'face with tears of joy', keywords: ['laugh', 'lol'] },\r\n { char: '😍', name: 'heart eyes', keywords: ['love', 'crush'] },\r\n { char: '😎', name: 'cool', keywords: ['sunglasses'] },\r\n { char: '🤔', name: 'thinking face', keywords: ['hmm'] },\r\n { char: '😉', name: 'winking face', keywords: ['wink'] },\r\n { char: '😢', name: 'crying face', keywords: ['sad', 'tear'] },\r\n { char: '😡', name: 'angry face', keywords: ['mad', 'rage'] },\r\n { char: '😱', name: 'screaming face', keywords: ['shock', 'scared'] },\r\n { char: '🥳', name: 'party face', keywords: ['celebrate', 'birthday'] },\r\n { char: '🙏', name: 'folded hands', keywords: ['please', 'pray', 'thanks'] },\r\n { char: '👍', name: 'thumbs up', keywords: ['approve', 'yes', 'like'] },\r\n { char: '👎', name: 'thumbs down', keywords: ['disapprove', 'no'] },\r\n { char: '👏', name: 'clapping hands', keywords: ['applause', 'congrats'] },\r\n { char: '🙌', name: 'raised hands', keywords: ['hooray', 'yay'] },\r\n { char: '👋', name: 'waving hand', keywords: ['hello', 'bye'] },\r\n { char: '✌️', name: 'victory hand', keywords: ['peace'] },\r\n { char: '💪', name: 'flexed biceps', keywords: ['strong', 'muscle'] },\r\n { char: '🤝', name: 'handshake', keywords: ['deal', 'agree'] },\r\n { char: '❤️', name: 'red heart', keywords: ['love'] },\r\n { char: '🔥', name: 'fire', keywords: ['hot', 'lit'] },\r\n { char: '⭐', name: 'star', keywords: ['favorite'] },\r\n { char: '✨', name: 'sparkles', keywords: ['shiny', 'magic'] },\r\n { char: '🎉', name: 'party popper', keywords: ['celebrate', 'congrats'] },\r\n { char: '🎊', name: 'confetti ball', keywords: ['celebrate'] },\r\n { char: '💡', name: 'light bulb', keywords: ['idea', 'tip'] },\r\n { char: '✅', name: 'check mark', keywords: ['done', 'yes', 'complete'] },\r\n { char: '❌', name: 'cross mark', keywords: ['no', 'wrong', 'delete'] },\r\n { char: '⚠️', name: 'warning', keywords: ['caution', 'alert'] },\r\n { char: '❓', name: 'question mark', keywords: ['question', 'help'] },\r\n { char: '❗', name: 'exclamation mark', keywords: ['important', 'alert'] },\r\n { char: '🚀', name: 'rocket', keywords: ['launch', 'fast', 'ship'] },\r\n { char: '🐛', name: 'bug', keywords: ['bug', 'issue'] },\r\n { char: '🔧', name: 'wrench', keywords: ['fix', 'tool', 'settings'] },\r\n { char: '📌', name: 'pushpin', keywords: ['pin', 'note'] },\r\n { char: '📎', name: 'paperclip', keywords: ['attachment', 'clip'] },\r\n { char: '📅', name: 'calendar', keywords: ['date', 'schedule'] },\r\n { char: '⏰', name: 'alarm clock', keywords: ['time', 'reminder'] },\r\n { char: '📈', name: 'chart increasing', keywords: ['growth', 'stats'] },\r\n { char: '📉', name: 'chart decreasing', keywords: ['decline', 'stats'] },\r\n { char: '💰', name: 'money bag', keywords: ['money', 'cash'] },\r\n { char: '💬', name: 'speech balloon', keywords: ['comment', 'chat'] },\r\n { char: '📝', name: 'memo', keywords: ['note', 'write'] },\r\n { char: '📚', name: 'books', keywords: ['reading', 'docs'] },\r\n { char: '🔗', name: 'link', keywords: ['url', 'chain'] },\r\n { char: '🔒', name: 'locked', keywords: ['private', 'secure'] },\r\n { char: '🔑', name: 'key', keywords: ['password', 'access'] },\r\n { char: '☕', name: 'coffee', keywords: ['coffee', 'break'] },\r\n { char: '🍕', name: 'pizza', keywords: ['food'] },\r\n { char: '🎂', name: 'birthday cake', keywords: ['birthday', 'cake'] },\r\n { char: '🎁', name: 'gift', keywords: ['present'] },\r\n { char: '🌟', name: 'glowing star', keywords: ['star', 'shiny'] },\r\n { char: '🌈', name: 'rainbow', keywords: ['colorful'] },\r\n { char: '☀️', name: 'sun', keywords: ['sunny', 'weather'] },\r\n { char: '🌧️', name: 'rain cloud', keywords: ['rainy', 'weather'] },\r\n { char: '🐶', name: 'dog face', keywords: ['dog', 'pet'] },\r\n { char: '🐱', name: 'cat face', keywords: ['cat', 'pet'] },\r\n { char: '🌍', name: 'globe', keywords: ['world', 'earth'] },\r\n { char: '🎯', name: 'direct hit', keywords: ['target', 'goal'] },\r\n { char: '🏆', name: 'trophy', keywords: ['win', 'award'] },\r\n { char: '🕐', name: 'clock', keywords: ['time'] },\r\n { char: '📣', name: 'megaphone', keywords: ['announce', 'shout'] },\r\n { char: '🧠', name: 'brain', keywords: ['smart', 'idea', 'mind'] },\r\n { char: '👀', name: 'eyes', keywords: ['look', 'watching'] },\r\n];\r\n","import { updateRun } from '../../store/operations.js';\r\nimport { focusRunAtOffset } from '../../react/focusRun.js';\r\n\r\n/**\r\n * Replaces the [sliceStart, sliceEnd) \"/query\" span in `runId`'s own text\r\n * with literal `text` — unlike insertInlineRunAtCursor, this never creates\r\n * a new run at all: the inserted content is ordinary text (an emoji\r\n * character), not an atomic chip, so it's just as selectable/deletable/\r\n * editable as anything else typed there. Used by the emoji slash commands.\r\n */\r\nexport function insertPlainTextAtCursor(store, { runId, sliceStart, sliceEnd }, text) {\r\n const run = store.getRun(runId);\r\n const value = run?.value ?? '';\r\n const newValue = value.slice(0, sliceStart) + text + value.slice(sliceEnd);\r\n store.applyOperation(updateRun(runId, { value: newValue }));\r\n focusRunAtOffset(runId, sliceStart + text.length);\r\n}\r\n","import { EMOJI_LIST } from './emojiList.js';\r\nimport { insertPlainTextAtCursor } from '../shared/insertPlainText.js';\r\n\r\n/**\r\n * One command per emoji, shared between however many trigger surfaces want\r\n * it (currently just the \":\" emoji menu — see useEmojiMenuTrigger). Kept as\r\n * its own module, separate from emojiList.js's raw data and index.js's\r\n * (now-empty) inline-type registration, so it's reusable without pulling in\r\n * anything registry-specific.\r\n */\r\nexport const EMOJI_COMMANDS = EMOJI_LIST.map(({ char, name, keywords }) => ({\r\n label: `${char} ${name}`,\r\n keywords,\r\n run: (store, ctx) => insertPlainTextAtCursor(store, ctx, char),\r\n}));\r\n","import { useTriggerMenu } from './useTriggerMenu.js';\r\nimport { EMOJI_COMMANDS } from '../inlineTypes/emoji/emojiCommands.js';\r\n\r\n// Matches a \":\" at the very start of the text, or right after whitespace,\r\n// followed by any word characters — same shape as the slash trigger, just a\r\n// different character, so \":fire\" narrows to 🔥 without colliding with \"/\"\r\n// commands typed in the same run.\r\nconst EMOJI_RE = /(^|\\s):(\\w*)$/;\r\n\r\nconst getEmojiCommands = () => EMOJI_COMMANDS;\r\n\r\n/**\r\n * Watches for \":\" typed anywhere inside a run within `containerRef` and\r\n * tracks the query typed after it, resolving against the built-in emoji\r\n * list — its own dedicated trigger, deliberately separate from \"/\" (see\r\n * useSlashMenuTrigger's doc comment), so emoji don't crowd out every other\r\n * slash command. Render the SAME `SlashMenu` component against this hook's\r\n * return value (it's a generic filterable command popover, not slash-\r\n * specific) — pass distinct `menuId`/`ariaLabel` props so the two popovers\r\n * (this one and the \"/\" one) never collide if both happen to be mounted at\r\n * once.\r\n */\r\nexport function useEmojiMenuTrigger(containerRef) {\r\n return useTriggerMenu(containerRef, EMOJI_RE, getEmojiCommands);\r\n}\r\n","import { useCallback } from 'react';\r\nimport { useInlineRegistry } from '../react/EditorProvider.jsx';\r\nimport { useTriggerMenu } from './useTriggerMenu.js';\r\n\r\n// Same shape as SLASH_RE/EMOJI_RE (see useSlashMenuTrigger/useEmojiMenuTrigger)\r\n// with \"@\" as the trigger character instead.\r\nconst AT_RE = /(^|\\s)@(\\w*)$/;\r\n\r\n/**\r\n * Watches for \"@\" typed anywhere inside a run within `containerRef` and\r\n * tracks the query typed after it, resolving against every inline type\r\n * that opted into `atCommand`/`atCommands` (see InlineRegistry's doc\r\n * comment) — its own dedicated trigger, deliberately separate from \"/\"\r\n * (same rationale as useEmojiMenuTrigger's own \":\" trigger: doesn't crowd\r\n * out every other slash command, and \"@\" carries its own well-understood\r\n * meaning elsewhere that \"/\" doesn't).\r\n *\r\n * Not every inline type shows up here — only ones that asked to (e.g. a\r\n * host-defined \"Assignee\" field type registered with\r\n * `createSelectFieldType({ ..., triggers: ['slash', 'at'] })`). A generic\r\n * \"Priority\"/\"Status\" dropdown, for instance, would usually stay slash-only\r\n * since \"@Priority\" doesn't read naturally the way \"@Assignee\" does.\r\n *\r\n * Render the SAME `SlashMenu` component against this hook's return value\r\n * (it's a generic filterable command popover, not slash-specific) — pass a\r\n * distinct `menuId`/`ariaLabel`, same as the emoji menu, so the popovers\r\n * never collide if more than one happens to be mounted at once.\r\n */\r\nexport function useAtMenuTrigger(containerRef) {\r\n const inlineRegistry = useInlineRegistry();\r\n const getAtCommands = useCallback(() => inlineRegistry?.listAtCommands() ?? [], [inlineRegistry]);\r\n return useTriggerMenu(containerRef, AT_RE, getAtCommands);\r\n}\r\n","import { useCallback, useRef, useState } from 'react';\nimport {\n toggleMarkOverSelection,\n toggleMarkOverBlockRange,\n setMarksOverSelection,\n setMarksOverBlockRange,\n} from '../inline/markCommands.js';\nimport { focusRunEnd } from '../react/focusRun.js';\n\n/**\n * The mark-toggling/link-editing logic behind the text-formatting UI —\n * shared by FloatingToolbar (desktop, appears as a bubble above a mouse\n * selection) and MobileActionBar (touch, appears pinned above the on-screen\n * keyboard instead, since a floating bubble fights the OS's own native\n * selection-handle UI there). Both are just different chrome around the\n * exact same setMarksOverSelection/setMarksOverBlockRange/\n * toggleMarkOverSelection/toggleMarkOverBlockRange primitives the keyboard\n * shortcuts already use — extracting this once means there's only one place\n * that ever calls those, not two copies that could drift apart.\n *\n * `kind`/`selection`/`crossSelection` are whatever useFloatingToolbarTrigger\n * already resolves ('same-block' vs 'cross-block' plus the matching\n * selection shape) — this hook doesn't re-resolve anything itself, so it\n * works identically whether the caller is reacting to a live mouse\n * selection or a snapshot captured earlier (e.g. right before a modal steals\n * focus — see openLinkModal's pendingLinkRef below).\n */\nexport function useTextFormattingActions(store, kind, selection, crossSelection, marks) {\n const [isLinkModalOpen, setIsLinkModalOpen] = useState(false);\n\n const applyPatch = useCallback(\n (marksPatch) => {\n const newRunId =\n kind === 'same-block'\n ? setMarksOverSelection(store, selection.blockId, selection, marksPatch)\n : setMarksOverBlockRange(store, crossSelection, marksPatch);\n if (newRunId) focusRunEnd(newRunId);\n return newRunId;\n },\n [store, kind, selection, crossSelection],\n );\n\n const toggleBoolean = useCallback(\n (markName) => {\n const newRunId =\n kind === 'same-block'\n ? toggleMarkOverSelection(store, selection.blockId, selection, markName)\n : toggleMarkOverBlockRange(store, crossSelection, markName);\n if (newRunId) focusRunEnd(newRunId);\n },\n [store, kind, selection, crossSelection],\n );\n\n // Subscript/superscript are mutually exclusive — enabling one always\n // clears the other in the SAME patch (one pass over the run span), not\n // two sequential calls, which would risk the second call addressing runs\n // by an id the first call's split already made stale (see\n // applyMarksPatchOverRunSpan's doc comment in markCommands.js).\n const setSubSuper = useCallback(\n (markName) => {\n const opposite = markName === 'subscript' ? 'superscript' : 'subscript';\n const enable = !marks[markName];\n applyPatch({ [markName]: enable ? true : null, [opposite]: null });\n },\n [marks, applyPatch],\n );\n\n // Captured at the moment \"Link\" is clicked, not read live from props —\n // focusing the link modal's URL input moves focus out of the\n // contentEditable region, which can collapse/change the document\n // selection this hook was built for (kind/selection/crossSelection would\n // otherwise go stale, or the caller's own bar would unmount out from\n // under the still-open modal).\n const pendingLinkRef = useRef(null);\n\n const openLinkModal = useCallback(() => {\n pendingLinkRef.current = { kind, selection, crossSelection };\n setIsLinkModalOpen(true);\n }, [kind, selection, crossSelection]);\n\n const closeLinkModal = useCallback(() => setIsLinkModalOpen(false), []);\n\n const applyLinkPatch = useCallback(\n (marksPatch) => {\n const pending = pendingLinkRef.current;\n if (!pending) return;\n const newRunId =\n pending.kind === 'same-block'\n ? setMarksOverSelection(store, pending.selection.blockId, pending.selection, marksPatch)\n : setMarksOverBlockRange(store, pending.crossSelection, marksPatch);\n if (newRunId) focusRunEnd(newRunId);\n setIsLinkModalOpen(false);\n },\n [store],\n );\n\n const handleSaveLink = useCallback((href, target) => applyLinkPatch({ link: { href, target } }), [applyLinkPatch]);\n const handleRemoveLink = useCallback(() => applyLinkPatch({ link: null }), [applyLinkPatch]);\n\n return {\n applyPatch,\n toggleBoolean,\n setSubSuper,\n isLinkModalOpen,\n openLinkModal,\n closeLinkModal,\n handleSaveLink,\n handleRemoveLink,\n };\n}\n","import { useEffect, useState } from 'react';\n\nconst TOUCH_INPUT_CLASS = 'be-touch-input';\n\nfunction matchesCoarsePointer() {\n return typeof window !== 'undefined' && window.matchMedia?.('(pointer: coarse)')?.matches === true;\n}\n\n/**\n * Reactive \"should touch-first UI show right now\" signal.\n *\n * A static `matchMedia('(pointer: coarse)')` check alone is the wrong tool\n * for this: it reports the device's *primary* pointer type, which is a\n * fixed hardware/OS classification, not \"what is the user actually using\n * right now.\" A touchscreen laptop (2-in-1s, Surface-style devices, plenty\n * of ordinary Windows laptops) has a real touchscreen sitting right there\n * that can be used at any moment, but the OS reports the trackpad/mouse as\n * primary — so a pure media-query check would never show touch UI on that\n * device even while the user is actively tapping the screen. There's no\n * reliable way to ask \"does this device have touch\" and get an answer that\n * actually predicts the next interaction; the only trustworthy signal is\n * the interaction itself.\n *\n * So: `matchMedia` only supplies the *initial* guess (correct before any\n * interaction has happened at all, including for SSR) — every real\n * `pointerdown` afterward overrides it with that event's own `pointerType`\n * ('touch'/'pen' switch touch UI on, 'mouse' switches it off), so a hybrid\n * device correctly shows desktop UI while its trackpad is in use and\n * mobile UI the instant the screen is tapped, with no reload needed either\n * way.\n *\n * Also mirrors the result onto `document.documentElement`'s classList\n * (`be-touch-input`) so plain CSS — the block gutter's touch handling, in\n * particular — can react to the same live signal, not just whatever calls\n * this hook directly.\n */\nexport function useCoarsePointer() {\n const [isTouch, setIsTouch] = useState(matchesCoarsePointer);\n\n useEffect(() => {\n if (typeof window === 'undefined') return undefined;\n const handlePointerDown = (event) => {\n setIsTouch(event.pointerType === 'touch' || event.pointerType === 'pen');\n };\n window.addEventListener('pointerdown', handlePointerDown, { passive: true });\n return () => window.removeEventListener('pointerdown', handlePointerDown);\n }, []);\n\n useEffect(() => {\n document.documentElement?.classList.toggle(TOUCH_INPUT_CLASS, isTouch);\n }, [isTouch]);\n\n return isTouch;\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useTextFormattingActions } from './useTextFormattingActions.js';\nimport { useCoarsePointer } from '../react/useCoarsePointer.js';\nimport { LinkEditModal } from '../react/LinkEditModal.jsx';\nimport { CommentComposer } from '../react/CommentComposer.jsx';\nimport { CommentPopoverHeader } from '../react/CommentPopoverHeader.jsx';\nimport { useAutoAdjustedCenteredLeft } from '../react/usePopoverEdgeClamp.js';\nimport { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, LinkIcon, CommentIcon } from '../react/icons.jsx';\nimport { addCommentMarkOverRange, removeCommentMarkEverywhere } from '../comments/commentMarks.js';\nimport { addCommentThread } from '../store/operations.js';\nimport { genId } from '../utils/idGen.js';\n\nconst BOOLEAN_BUTTONS = [\n { markName: 'bold', Icon: BoldIcon, title: 'Bold (Ctrl+B)' },\n { markName: 'italic', Icon: ItalicIcon, title: 'Italic (Ctrl+I)' },\n { markName: 'underline', Icon: UnderlineIcon, title: 'Underline (Ctrl+U)' },\n { markName: 'strike', Icon: StrikethroughIcon, title: 'Strikethrough' },\n];\n\nconst TEXT_COLORS = [\n { label: 'Default', value: null },\n { label: 'Red', value: '#e03131' },\n { label: 'Orange', value: '#e8590c' },\n { label: 'Green', value: '#2f9e44' },\n { label: 'Blue', value: '#1971c2' },\n { label: 'Purple', value: '#9c36b5' },\n];\n\nconst HIGHLIGHT_COLORS = [\n { label: 'None', value: null },\n { label: 'Yellow', value: '#fff3bf' },\n { label: 'Green', value: '#d3f9d8' },\n { label: 'Blue', value: '#d0ebff' },\n { label: 'Pink', value: '#ffdeeb' },\n { label: 'Gray', value: '#e9ecef' },\n];\n\n/**\n * A floating format bar that appears above a non-collapsed text\n * selection (see useFloatingToolbarTrigger). Every action goes through\n * useTextFormattingActions (shared with MobileActionBar) — this component\n * only owns the desktop bubble's own chrome/positioning/color-picker state.\n *\n * The whole bar has one onMouseDown that calls preventDefault: the browser's\n * default mousedown action is what collapses the text selection and shifts\n * focus to whatever you clicked — preventing it here (before any button's\n * own onClick even fires) is what lets a toolbar button apply formatting to\n * a selection that's still fully intact, exactly like every other\n * mousedown-then-click floating format toolbar.\n *\n * Deliberately a no-op on a coarse (touch) pointer: a floating bubble\n * positioned off Range.getBoundingClientRect() fights the OS's own native\n * selection-handle UI on mobile, which occupies similar screen space —\n * MobileActionBar (pinned above the keyboard instead) is the touch\n * equivalent, reusing the exact same useTextFormattingActions hook.\n *\n * The Comment button (Notion-style: appears alongside the formatting\n * buttons on any text selection) shows whenever either `onComment` or\n * `commentAuthorId` is given, and is only shown for a same-block selection\n * (`kind === 'same-block'`): commentMarks.js's addCommentMarkOverRange\n * doesn't support a cross-block range yet, matching that module's own\n * single-block scope.\n *\n * If `onComment` is given, clicking it calls `onComment(selection)` and\n * stops there — full host control (open your own modal/popover, decide the\n * author yourself). Otherwise, if `commentAuthorId` is given (see\n * NoteloomEditor's own prop of the same name), clicking it opens a small\n * built-in inline composer — REPLACING the whole button row (not another\n * picker alongside it) so the composer is centered under the selection the\n * exact same way the toolbar itself is, instead of trailing off wherever\n * the Comment button happens to sit in a wide button row. The selected\n * text is highlighted immediately when the composer opens (an `addCommentMarkOverRange`\n * op applied right away, same visible-while-composing behavior Notion/\n * Google Docs have) — Cancel strips that mark back off\n * (`removeCommentMarkEverywhere`), Submit creates the thread using the\n * same id the mark already carries.\n */\nexport function FloatingToolbar({ isOpen, rect, kind, selection, crossSelection, marks, store, onComment, commentAuthorId }) {\n const isCoarsePointer = useCoarsePointer();\n const [openPicker, setOpenPicker] = useState(null); // 'color' | 'highlight' | 'comment' | null\n const [pendingComment, setPendingComment] = useState(null); // { commentId } | null -- see openCommentComposer\n const rootRef = useRef(null);\n\n const {\n applyPatch,\n toggleBoolean,\n setSubSuper,\n isLinkModalOpen,\n openLinkModal,\n closeLinkModal,\n handleSaveLink,\n handleRemoveLink,\n } = useTextFormattingActions(store, kind, selection, crossSelection, marks);\n\n // Mirrors `pendingComment` without being a `useEffect` dependency of its\n // own -- read by the effects below (outside-click/Escape, and the\n // selection-changed reset) so closing the toolbar ANY way while a comment\n // is mid-compose still strips the just-applied highlight, not just the\n // Cancel button's own click handler.\n const pendingCommentRef = useRef(null);\n pendingCommentRef.current = pendingComment;\n\n /**\n * Blurs whatever's currently focused (typically the composer's own\n * textarea) and clears the native selection once a comment's been\n * created/discarded -- without this, the selection stays intact and the\n * ordinary Bold/Italic toolbar pops right back up \"behind\" the composer\n * the instant it closes, since as far as the browser's concerned nothing\n * about the underlying selection ever changed. Blurring first matters:\n * useFloatingToolbarTrigger's recompute() deliberately ignores selection\n * changes while focus is still inside `.be-floating-toolbar` (see its own\n * comment, added to keep IT from blanking out state mid-type) -- without\n * the blur, clearing the selection here would be silently ignored too.\n */\n function closeFloatingSelection() {\n document.activeElement?.blur?.();\n window.getSelection?.()?.removeAllRanges();\n }\n\n function openCommentComposer() {\n if (!selection) return;\n const commentId = genId();\n const markOp = addCommentMarkOverRange(store, selection, commentId);\n if (markOp) store.applyOperation(markOp);\n setPendingComment({ commentId });\n setOpenPicker('comment');\n }\n\n /** Strips a mid-compose comment's highlight back off (no thread was ever created for it) -- safe to call even when nothing is pending. */\n function discardPendingComment() {\n const pending = pendingCommentRef.current;\n if (!pending) return;\n for (const op of removeCommentMarkEverywhere(store, pending.commentId)) store.applyOperation(op);\n setPendingComment(null);\n closeFloatingSelection();\n }\n\n function submitCommentComposer(text) {\n if (!pendingComment || !selection) return;\n store.applyOperation(\n addCommentThread({\n id: pendingComment.commentId,\n blockId: selection.blockId,\n anchorRunIds: [selection.startRunId, selection.endRunId],\n resolved: false,\n messages: [{ id: genId(), authorId: commentAuthorId, text, createdAt: Date.now() }],\n }),\n );\n setPendingComment(null);\n setOpenPicker(null);\n closeFloatingSelection();\n }\n\n function cancelCommentComposer() {\n discardPendingComment();\n setOpenPicker(null);\n }\n\n // Ctrl/Cmd+Alt+M -- same shortcut most other editors use for \"comment on\n // the current selection\". Only listens while a same-block selection with\n // the Comment button actually available is open, so it doesn't shadow\n // the shortcut for anything else.\n useEffect(() => {\n if (!isOpen || kind !== 'same-block' || !(onComment || commentAuthorId)) return undefined;\n const handleKeyDown = (event) => {\n // event.code (the physical key), not event.key -- Option/Alt+M\n // doesn't produce the character \"m\" at all on a Mac (US layout types\n // \"µ\"), and Ctrl+Alt is AltGr on several European Windows layouts,\n // remapping the character too. .code is unaffected by either.\n if ((event.metaKey || event.ctrlKey) && event.altKey && event.code === 'KeyM') {\n event.preventDefault();\n if (onComment) onComment(selection);\n else openCommentComposer();\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, kind, onComment, commentAuthorId, selection]);\n\n useEffect(() => {\n if (!openPicker) return undefined;\n const handlePointerDown = (event) => {\n if (rootRef.current && !rootRef.current.contains(event.target)) {\n discardPendingComment();\n setOpenPicker(null);\n }\n };\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') {\n discardPendingComment();\n setOpenPicker(null);\n }\n };\n document.addEventListener('mousedown', handlePointerDown);\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('mousedown', handlePointerDown);\n document.removeEventListener('keydown', handleKeyDown);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [openPicker]);\n\n // Closing the picker (not the whole toolbar) whenever the selection this\n // toolbar was built for changes out from under it — same rect/kind means\n // the same live selection is still current. Also discards a mid-compose\n // comment's highlight, same reasoning as the outside-click/Escape handlers\n // above (the pending mark shouldn't outlive the composer that would have\n // turned it into a real thread).\n useEffect(() => {\n discardPendingComment();\n setOpenPicker(null);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rect, kind]);\n\n const centerLeft = useAutoAdjustedCenteredLeft(\n rootRef,\n Boolean(isOpen && rect),\n rect ? rect.left + rect.width / 2 : null,\n );\n\n if (isCoarsePointer) return null;\n if ((!isOpen || !rect) && !isLinkModalOpen) return null;\n\n const isComposingComment = !onComment && openPicker === 'comment';\n\n return (\n <>\n {isOpen && rect && centerLeft != null && isComposingComment && (\n // Composing a new comment REPLACES the whole button row (not another\n // picker floating off one of its buttons) -- same outer position as the\n // ordinary toolbar below (centered under the selection), so the\n // composer lands right under the highlighted text instead of trailing\n // off toward wherever the Comment button happened to sit in a wide row.\n <div\n ref={rootRef}\n // Keeping the base `be-floating-toolbar` class (alongside the\n // standalone-specific one below) matters beyond styling --\n // useFloatingToolbarTrigger's recompute() checks\n // `document.activeElement?.closest('.be-floating-toolbar')` to avoid\n // blanking out toolbar state while focus is inside it (e.g. typing\n // into this exact composer); a different class here would silently\n // defeat that guard.\n className=\"be-floating-toolbar be-floating-toolbar-comment-standalone\"\n role=\"dialog\"\n aria-label=\"Add comment\"\n style={{ position: 'fixed', top: rect.top - 44, left: centerLeft, transform: 'translateX(-50%)' }}\n onMouseDown={(event) => {\n if (event.target.tagName !== 'TEXTAREA') event.preventDefault();\n }}\n >\n <CommentPopoverHeader title=\"Add comment\" onClose={cancelCommentComposer} />\n <CommentComposer authorId={commentAuthorId} autoFocus onSubmit={submitCommentComposer} onCancel={cancelCommentComposer} />\n </div>\n )}\n {isOpen && rect && centerLeft != null && !isComposingComment && (\n <div\n ref={rootRef}\n className=\"be-floating-toolbar\"\n role=\"toolbar\"\n aria-label=\"Text formatting\"\n style={{ position: 'fixed', top: rect.top - 44, left: centerLeft, transform: 'translateX(-50%)' }}\n // The comment composer's textarea needs a normal mousedown (to focus/\n // place its own caret on click) -- every other button here is a plain\n // click target with no text input of its own, so preventDefault is\n // still correct for keeping the underlying selection intact when\n // clicking THOSE.\n onMouseDown={(event) => {\n if (event.target.tagName !== 'TEXTAREA') event.preventDefault();\n }}\n >\n {BOOLEAN_BUTTONS.map(({ markName, Icon, title }) => (\n <button\n key={markName}\n type=\"button\"\n className={`be-floating-toolbar-btn${marks[markName] ? ' be-floating-toolbar-btn-active' : ''}`}\n title={title}\n aria-label={title}\n aria-pressed={Boolean(marks[markName])}\n onClick={() => toggleBoolean(markName)}\n >\n <Icon />\n </button>\n ))}\n\n <button\n type=\"button\"\n className={`be-floating-toolbar-btn${marks.subscript ? ' be-floating-toolbar-btn-active' : ''}`}\n title=\"Subscript\"\n aria-pressed={Boolean(marks.subscript)}\n onClick={() => setSubSuper('subscript')}\n >\n X₂\n </button>\n <button\n type=\"button\"\n className={`be-floating-toolbar-btn${marks.superscript ? ' be-floating-toolbar-btn-active' : ''}`}\n title=\"Superscript\"\n aria-pressed={Boolean(marks.superscript)}\n onClick={() => setSubSuper('superscript')}\n >\n X²\n </button>\n\n <span className=\"be-floating-toolbar-divider\" />\n\n <div className=\"be-floating-toolbar-picker-wrap\">\n <button\n type=\"button\"\n className=\"be-floating-toolbar-btn\"\n title=\"Text color\"\n aria-haspopup=\"true\"\n aria-expanded={openPicker === 'color'}\n onClick={() => setOpenPicker((p) => (p === 'color' ? null : 'color'))}\n >\n <span style={{ color: marks.color || 'inherit', fontWeight: 700 }}>A</span>\n </button>\n {openPicker === 'color' && (\n <div className=\"be-floating-toolbar-picker\" role=\"menu\" aria-label=\"Text color\">\n {TEXT_COLORS.map((c) => (\n <button\n key={c.label}\n type=\"button\"\n role=\"menuitem\"\n className=\"be-floating-toolbar-swatch\"\n title={c.label}\n onClick={() => {\n applyPatch({ color: c.value });\n setOpenPicker(null);\n }}\n >\n <span style={{ color: c.value || '#1a1a1a', fontWeight: 700 }}>A</span>\n </button>\n ))}\n </div>\n )}\n </div>\n\n <div className=\"be-floating-toolbar-picker-wrap\">\n <button\n type=\"button\"\n className=\"be-floating-toolbar-btn\"\n title=\"Highlight\"\n aria-haspopup=\"true\"\n aria-expanded={openPicker === 'highlight'}\n onClick={() => setOpenPicker((p) => (p === 'highlight' ? null : 'highlight'))}\n >\n <span\n style={{ backgroundColor: marks.highlight || 'transparent', padding: '0 2px', borderRadius: 2 }}\n >\n H\n </span>\n </button>\n {openPicker === 'highlight' && (\n <div className=\"be-floating-toolbar-picker\" role=\"menu\" aria-label=\"Highlight color\">\n {HIGHLIGHT_COLORS.map((c) => (\n <button\n key={c.label}\n type=\"button\"\n role=\"menuitem\"\n className=\"be-floating-toolbar-swatch\"\n style={{ backgroundColor: c.value || 'transparent' }}\n title={c.label}\n onClick={() => {\n applyPatch({ highlight: c.value });\n setOpenPicker(null);\n }}\n />\n ))}\n </div>\n )}\n </div>\n\n <span className=\"be-floating-toolbar-divider\" />\n\n <button\n type=\"button\"\n className={`be-floating-toolbar-btn${marks.link ? ' be-floating-toolbar-btn-active' : ''}`}\n title=\"Link\"\n aria-label=\"Link\"\n aria-pressed={Boolean(marks.link)}\n onClick={openLinkModal}\n >\n <LinkIcon />\n </button>\n\n {(onComment || commentAuthorId) && kind === 'same-block' && (\n <>\n <span className=\"be-floating-toolbar-divider\" />\n <button\n type=\"button\"\n className=\"be-floating-toolbar-btn\"\n title=\"Comment (Ctrl+Alt+M)\"\n aria-label=\"Comment\"\n onClick={() => (onComment ? onComment(selection) : openCommentComposer())}\n >\n <CommentIcon />\n </button>\n </>\n )}\n </div>\n )}\n <LinkEditModal\n isOpen={isLinkModalOpen}\n initialHref={marks.link?.href ?? ''}\n initialTarget={marks.link?.target ?? '_self'}\n hasExistingLink={Boolean(marks.link)}\n onSave={handleSaveLink}\n onRemove={handleRemoveLink}\n onClose={closeLinkModal}\n />\n </>\n );\n}\n","import { useEffect, useState } from 'react';\r\nimport { useEditorStore } from '../react/EditorProvider.jsx';\r\nimport { resolveMultiRunSelection, resolveCrossBlockSelection } from '../react/selectionResolve.js';\r\nimport { getMarksSummaryOverSelection, getMarksSummaryOverBlockRange } from '../inline/markCommands.js';\r\n\r\n/**\r\n * Shows a floating format toolbar whenever the current selection is a real\r\n * (non-collapsed) text range within `containerRef` — same-block or\r\n * cross-block, reusing the exact same resolvers useEditorKeyboardShortcuts'\r\n * Ctrl+B/I already rely on, so \"can this selection be formatted at all\" is\r\n * answered identically everywhere in the codebase, not re-derived here.\r\n *\r\n * Listens on `document`'s `selectionchange` (selection state can change from\r\n * a mouseup/keyup that fires outside this exact container, e.g. releasing a\r\n * drag over another block) rather than a local mouseup/keyup — this mirrors\r\n * how real editors track selection, and is the only event that reliably\r\n * fires for every way a selection can change (mouse drag, shift+arrow,\r\n * double/triple-click, select-all, programmatic).\r\n *\r\n * Position is read directly off `Range.getBoundingClientRect()` — a\r\n * `position: fixed` box anchored to that rect stays correct regardless of\r\n * page scroll, so this also recomputes on window scroll/resize (capture\r\n * phase, since an inner scrollable region's scroll event doesn't bubble to\r\n * window by default).\r\n */\r\nexport function useFloatingToolbarTrigger(containerRef) {\r\n const store = useEditorStore();\r\n const [state, setState] = useState(null); // { rect, kind: 'same-block' | 'cross-block', selection/crossSelection, marks }\r\n\r\n useEffect(() => {\r\n const container = containerRef.current;\r\n if (!container) return undefined;\r\n\r\n const recompute = () => {\r\n // Don't re-derive (and don't blank out) toolbar state while focus is\r\n // inside the toolbar's own popover content (e.g. typing into the\r\n // Comment button's inline composer textarea) -- a <textarea> isn't\r\n // part of the editor's own run/block DOM, so resolveMultiRunSelection\r\n // below would find nothing and close the whole toolbar out from under\r\n // whatever's being typed. The toolbar keeps showing whatever\r\n // selection/rect it already had before focus moved there.\r\n if (document.activeElement?.closest?.('.be-floating-toolbar')) return;\r\n\r\n const selection = window.getSelection?.();\r\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\r\n setState(null);\r\n return;\r\n }\r\n if (!container.contains(selection.anchorNode) || !container.contains(selection.focusNode)) {\r\n setState(null);\r\n return;\r\n }\r\n\r\n // jsdom (used by this package's own test suite) implements\r\n // Element.prototype.getBoundingClientRect but not\r\n // Range.prototype.getBoundingClientRect at all — falling back to a\r\n // zero rect keeps this hook's logic testable without a real layout\r\n // engine, the same way a zero-size rect from a real browser (a\r\n // genuinely empty range) is already handled fine by callers.\r\n const rect = selection.getRangeAt(0).getBoundingClientRect?.() ?? { top: 0, left: 0, right: 0, bottom: 0, width: 0, height: 0 };\r\n\r\n const sameBlock = resolveMultiRunSelection();\r\n if (sameBlock) {\r\n setState({\r\n kind: 'same-block',\r\n rect,\r\n selection: sameBlock,\r\n marks: getMarksSummaryOverSelection(store, sameBlock.blockId, sameBlock),\r\n });\r\n return;\r\n }\r\n\r\n const crossBlock = resolveCrossBlockSelection(store);\r\n if (crossBlock) {\r\n setState({\r\n kind: 'cross-block',\r\n rect,\r\n crossSelection: crossBlock,\r\n marks: getMarksSummaryOverBlockRange(store, crossBlock),\r\n });\r\n return;\r\n }\r\n\r\n setState(null);\r\n };\r\n\r\n document.addEventListener('selectionchange', recompute);\r\n window.addEventListener('scroll', recompute, true);\r\n window.addEventListener('resize', recompute);\r\n return () => {\r\n document.removeEventListener('selectionchange', recompute);\r\n window.removeEventListener('scroll', recompute, true);\r\n window.removeEventListener('resize', recompute);\r\n };\r\n }, [containerRef, store]);\r\n\r\n return {\r\n isOpen: Boolean(state),\r\n rect: state?.rect ?? null,\r\n kind: state?.kind ?? null,\r\n selection: state?.selection ?? null,\r\n crossSelection: state?.crossSelection ?? null,\r\n marks: state?.marks ?? {},\r\n close: () => setState(null),\r\n };\r\n}\r\n","import { useRef } from 'react';\nimport { EditorProvider } from './EditorProvider.jsx';\nimport { BlockChildren } from './BlockChildren.jsx';\nimport { EditorTrailingSpace } from './EditorTrailingSpace.jsx';\nimport { BlockRangeActionMenu } from './BlockRangeActionMenu.jsx';\nimport { CommentsPanel } from './CommentsPanel.jsx';\nimport { useClipboardHandlers } from './useClipboardHandlers.js';\nimport { useEditorKeyboardShortcuts } from './useEditorKeyboardShortcuts.js';\nimport { useBlockRangeDrag } from './useBlockRangeDrag.js';\nimport { SlashMenu } from '../commands/SlashMenu.jsx';\nimport { useSlashMenuTrigger } from '../commands/useSlashMenuTrigger.js';\nimport { useEmojiMenuTrigger } from '../commands/useEmojiMenuTrigger.js';\nimport { useAtMenuTrigger } from '../commands/useAtMenuTrigger.js';\nimport { FloatingToolbar } from '../commands/FloatingToolbar.jsx';\nimport { useFloatingToolbarTrigger } from '../commands/useFloatingToolbarTrigger.js';\n\nfunction EditorSurface({ store, rootId, onComment, commentAuthorId }) {\n const containerRef = useRef(null);\n const { onCopy, onCut, onPaste } = useClipboardHandlers();\n const slashMenu = useSlashMenuTrigger(containerRef);\n const emojiMenu = useEmojiMenuTrigger(containerRef);\n const atMenu = useAtMenuTrigger(containerRef);\n const floatingToolbar = useFloatingToolbarTrigger(containerRef);\n useEditorKeyboardShortcuts(containerRef);\n useBlockRangeDrag(containerRef);\n\n return (\n <div ref={containerRef} role=\"document\" aria-label=\"Document editor\" onCopy={onCopy} onCut={onCut} onPaste={onPaste}>\n <BlockRangeActionMenu />\n <BlockChildren parentId={rootId} isTopLevel />\n <EditorTrailingSpace />\n <SlashMenu\n isOpen={slashMenu.isOpen}\n rect={slashMenu.rect}\n commands={slashMenu.commands}\n runId={slashMenu.runId}\n onSelect={slashMenu.selectCommand}\n onClose={slashMenu.close}\n />\n <SlashMenu\n isOpen={emojiMenu.isOpen}\n rect={emojiMenu.rect}\n commands={emojiMenu.commands}\n runId={emojiMenu.runId}\n onSelect={emojiMenu.selectCommand}\n onClose={emojiMenu.close}\n menuId=\"be-emoji-menu\"\n ariaLabel=\"Emoji\"\n />\n <SlashMenu\n isOpen={atMenu.isOpen}\n rect={atMenu.rect}\n commands={atMenu.commands}\n runId={atMenu.runId}\n onSelect={atMenu.selectCommand}\n onClose={atMenu.close}\n menuId=\"be-at-menu\"\n ariaLabel=\"Mention\"\n />\n <FloatingToolbar\n isOpen={floatingToolbar.isOpen}\n rect={floatingToolbar.rect}\n kind={floatingToolbar.kind}\n selection={floatingToolbar.selection}\n crossSelection={floatingToolbar.crossSelection}\n marks={floatingToolbar.marks}\n store={store}\n onComment={onComment}\n commentAuthorId={commentAuthorId}\n />\n </div>\n );\n}\n\n/**\n * The rendering half of useEditor(): everything examples/basic wires by\n * hand — clipboard, slash/emoji/@-mention menus, the floating format\n * toolbar, keyboard shortcuts, block-range drag — bundled into one\n * component. Pass the object useEditor() returned and you're done:\n *\n * const editor = useEditor();\n * return <NoteloomEditor editor={editor} />;\n *\n * `className`/`style`/`theme`/`getBlockClassName` forward straight to\n * EditorProvider (see its own doc comment); `children` renders inside the provider alongside\n * the editor surface, for a toolbar or other chrome that needs store\n * access via the usual hooks (useEditorStore, useHistory, ...). Anything\n * this doesn't cover (a custom toolbar, mobile chrome, voice typing, field\n * type management) is still just EditorProvider + the granular hooks/\n * components underneath, unchanged and fully available.\n *\n * Comments, built in:\n * - `onComment`, if given, adds a Comment button to the floating format\n * toolbar (Notion-style) that calls `onComment(selection)` on click —\n * full host control over what happens next (open your own UI). See\n * FloatingToolbar's own doc comment.\n * - `commentAuthorId`, if given (and `onComment` is NOT), makes the whole\n * comments experience self-contained with no host UI code at all: the\n * floating toolbar's Comment button opens a small built-in composer,\n * clicking/hovering existing highlighted text opens a popover to view/\n * reply/resolve/delete it (CommentPopover, mounted automatically inside\n * every block), and `showCommentsPanel` (below) adds a right-side list of\n * every thread in the document. Every reply composed through any of these\n * built-in surfaces is attributed to this id — see useCommentAuthorId.\n * - `showCommentsPanel`, if true, renders CommentsPanel (Notion/Google\n * Docs-style, `position: fixed` to the right by default — see\n * `.be-comments-panel` in style.css) — purely additive to the popover\n * above, not a replacement for it.\n */\nexport function NoteloomEditor({ editor, className, style, theme, getBlockClassName, onComment, commentAuthorId, showCommentsPanel, children }) {\n const { store, registry, inlineRegistry } = editor;\n const rootId = store.getRootId();\n return (\n <EditorProvider\n store={store}\n registry={registry}\n inlineRegistry={inlineRegistry}\n history={store}\n className={className}\n style={style}\n theme={theme}\n getBlockClassName={getBlockClassName}\n commentAuthorId={commentAuthorId}\n >\n <EditorSurface store={store} rootId={rootId} onComment={onComment} commentAuthorId={commentAuthorId} />\n {showCommentsPanel && <CommentsPanel authorId={commentAuthorId} />}\n {children}\n </EditorProvider>\n );\n}\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useEditorStore } from './EditorProvider.jsx';\r\n\r\nconst FIELD_TYPES_KEY = '$fieldTypes';\r\n\r\n/**\r\n * Subscribes to the store's persisted, user-created field type definitions\r\n * (see createSelectFieldType / registerStoredFieldTypes) — reactive so a\r\n * \"manage field types\" list re-renders after add/update/remove, the same\r\n * way useBlock re-renders on a single block's change. Not used by the\r\n * slash menu itself: that reads inlineRegistry.listSlashCommands() fresh\r\n * on every trigger, so a newly-registered type shows up there without any\r\n * separate subscription.\r\n *\r\n * store.getFieldTypes() returns a referentially-stable array (cached,\r\n * invalidated only by a fieldTypes op) — required by useSyncExternalStore,\r\n * same contract as useBlock/useRun.\r\n */\r\nexport function useFieldTypes() {\r\n const store = useEditorStore();\r\n const subscribe = useCallback((onStoreChange) => store.subscribe(FIELD_TYPES_KEY, onStoreChange), [store]);\r\n const getSnapshot = useCallback(() => store.getFieldTypes(), [store]);\r\n return useSyncExternalStore(subscribe, getSnapshot);\r\n}\r\n","import { useCallback, useSyncExternalStore } from 'react';\r\nimport { useEditorContext } from './EditorProvider.jsx';\r\nimport { restoreSelectionAfterHistoryChange } from './restoreHistorySelection.js';\r\n\r\nconst STABLE_STATE = { canUndo: false, canRedo: false };\r\n\r\n/**\r\n * Subscribes to undo/redo availability, for wiring up toolbar buttons.\r\n * Returns null if the editor was created without a History instance (i.e.\r\n * the provider was given a plain EditorStore).\r\n */\r\nexport function useHistory() {\r\n const { history } = useEditorContext();\r\n\r\n const subscribe = useCallback(\r\n (onChange) => (history ? history.subscribeToHistory(onChange) : () => {}),\r\n [history],\r\n );\r\n const getSnapshot = useCallback(\r\n () => (history ? history.getUndoRedoSnapshot() : STABLE_STATE),\r\n [history],\r\n );\r\n\r\n const state = useSyncExternalStore(subscribe, getSnapshot);\r\n if (!history) return null;\r\n\r\n return {\r\n ...state,\r\n undo: () => {\r\n const changed = history.undo();\r\n if (changed) restoreSelectionAfterHistoryChange(history);\r\n return changed;\r\n },\r\n redo: () => {\r\n const changed = history.redo();\r\n if (changed) restoreSelectionAfterHistoryChange(history);\r\n return changed;\r\n },\r\n getHistoryLog: () => history.getHistoryLog(),\r\n };\r\n}\r\n","import { useEffect, useState } from 'react';\nimport { loadPersistedDocument } from '../persistence/indexedDbPersistence.js';\nimport { createAutoPersistence } from '../persistence/autoPersist.js';\n\n/**\n * Ties a store to IndexedDB persistence for React usage: loads whatever\n * was last saved under `docId` (if anything) into the store on mount, and\n * auto-saves on every change from then on — the \"lightweight editor,\n * works fully offline, no server required\" building block.\n *\n * `store` must already exist (created via `useMemo`, same as every\n * example in this package) — this hook does not construct one. If a\n * persisted document is found, the store's content is REPLACED with it\n * (the same direct-swap pattern `CollabSession` uses to adopt a peer's\n * snapshot); if nothing was found, the store is left exactly as its\n * caller initialized it (e.g. with a starter document).\n *\n * Returns `{ isLoaded }` — `false` until the initial IndexedDB read\n * resolves, so callers can show a loading state instead of briefly\n * flashing default content that's about to be replaced.\n *\n * Known edge case: an edit made in the narrow window between mount and\n * the initial load resolving can be discarded once the load applies\n * (whatever was actually persisted always wins) — acceptable for a\n * hydrate-on-mount pattern, and not reachable in practice outside\n * deliberately racing it.\n */\nexport function usePersistedDocument({ store, docId, debounceMs, onError }) {\n const [isLoaded, setIsLoaded] = useState(false);\n\n useEffect(() => {\n let cancelled = false;\n setIsLoaded(false);\n\n loadPersistedDocument(docId)\n .then((doc) => {\n if (cancelled) return;\n if (doc) {\n const rawStore = store.store ?? store; // unwrap a History instance to the underlying EditorStore\n rawStore.blocks = new Map((doc.blocks ?? []).map((b) => [b.id, b]));\n rawStore.runs = new Map((doc.runs ?? []).map((r) => [r.id, r]));\n rawStore.rootId = doc.rootId ?? null;\n rawStore.fieldTypes = new Map((doc.fieldTypes ?? []).map((f) => [f.id, f]));\n rawStore._fieldTypesSnapshot = null;\n rawStore._orders = new Map();\n rawStore._notify([...rawStore.blocks.keys(), ...rawStore.runs.keys()]);\n }\n })\n .catch((err) => onError?.(err))\n .finally(() => {\n if (!cancelled) setIsLoaded(true);\n });\n\n const { stop, flush } = createAutoPersistence({ store, docId, debounceMs, onError });\n\n return () => {\n cancelled = true;\n flush();\n stop();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [docId]);\n\n return { isLoaded };\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * Reactive access to a `CollabSession`'s presence data — the live \"who\n * else is here, and where\" (cursor position, name, color, whatever the\n * host app puts into `setLocalPresence`) alongside the document sync.\n *\n * `session` is whatever `CollabSession` instance the host app already\n * constructed (this hook doesn't create one) — pass `null`/`undefined`\n * before it exists yet (e.g. still connecting) and this returns an empty\n * map rather than erroring.\n *\n * Returns a `Map<peerId, data>` of every OTHER peer's current presence\n * (never your own — you already know that). A new render only happens\n * when presence actually changes (a peer moves, joins, or disconnects),\n * same reference-stability contract as the rest of this package's hooks.\n */\nexport function usePresence(session) {\n const [presence, setPresence] = useState(() => session?.getPresence() ?? new Map());\n\n useEffect(() => {\n if (!session) {\n setPresence(new Map());\n return undefined;\n }\n setPresence(session.getPresence());\n return session.onPresenceChange(setPresence);\n }, [session]);\n\n return presence;\n}\n","import { useEffect, useState, useCallback } from 'react';\n\n/**\n * Watches for a new, already-installed-but-waiting service worker (the\n * standard signal that a fresh build is available) and exposes a way to\n * activate it. Generic — works with any service worker registration,\n * however it got there (vite-plugin-pwa, a hand-written registration,\n * Workbox, ...); this hook doesn't register one itself, only observes.\n *\n * This is what makes \"the app shell loads with no internet\" (an offline-\n * capable service worker, set up at the host app's build level — see\n * README's \"Offline app shell (PWA)\" section) safe to combine with\n * \"actually ship updates to users\": without surfacing that a new version\n * is waiting, a service-worker-cached app can silently keep serving a\n * stale build indefinitely once installed.\n *\n * Returns `{ updateAvailable, applyUpdate }` — `applyUpdate()` tells the\n * waiting worker to activate and reloads the page once it has. No-ops\n * harmlessly (updateAvailable stays false) in a browser/context with no\n * service worker support, or when no registration exists yet.\n */\nexport function useServiceWorkerUpdate() {\n const [updateAvailable, setUpdateAvailable] = useState(false);\n const [waitingWorker, setWaitingWorker] = useState(null);\n\n useEffect(() => {\n if (!navigator.serviceWorker) return undefined;\n let cancelled = false;\n\n function watchRegistration(registration) {\n if (!registration) return;\n const noteWaiting = () => {\n if (registration.waiting) {\n setWaitingWorker(registration.waiting);\n setUpdateAvailable(true);\n }\n };\n noteWaiting(); // a worker may already be waiting by the time this hook mounts\n registration.addEventListener('updatefound', () => {\n const installing = registration.installing;\n if (!installing) return;\n installing.addEventListener('statechange', () => {\n if (installing.state === 'installed' && navigator.serviceWorker.controller) noteWaiting();\n });\n });\n }\n\n navigator.serviceWorker.getRegistration().then((registration) => {\n if (!cancelled) watchRegistration(registration);\n });\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n const applyUpdate = useCallback(() => {\n if (!waitingWorker) return;\n const reloadOnceControllerChanges = () => window.location.reload();\n navigator.serviceWorker.addEventListener('controllerchange', reloadOnceControllerChanges, { once: true });\n waitingWorker.postMessage({ type: 'SKIP_WAITING' });\n }, [waitingWorker]);\n\n return { updateAvailable, applyUpdate };\n}\n","/**\n * The spoken-phrase -> editor-action table driving voice typing (see\n * useVoiceTyping.js). Deliberately data-driven and pure (no store/DOM\n * access here at all) so the \"does this phrase count as a command\"\n * decision is directly unit-testable without a real SpeechRecognition\n * engine — matchVoiceCommand is exercised with plain strings.\n *\n * Only a *complete, isolated* recognized utterance is ever checked against\n * this table (see useVoiceTyping's isFinal handling) — a command phrase\n * spoken as part of a longer sentence while dictating never matches,\n * since the caller only calls this with one finalized speech segment at a\n * time, normalized as its own whole utterance.\n *\n * Each entry's `description` is shown to end users (see listVoiceCommands)\n * — not just a code comment — so keep it short and phrased as what saying\n * it does, not how it's implemented.\n */\nconst COMMANDS = [\n {\n phrases: ['new paragraph', 'next paragraph'],\n description: 'Start a new paragraph',\n action: { type: 'insertParagraph' },\n },\n {\n phrases: ['heading one', 'heading 1'],\n description: 'Convert the current block to a heading 1',\n action: { type: 'convertBlock', blockType: 'heading', props: { level: 1 } },\n },\n {\n phrases: ['heading two', 'heading 2'],\n description: 'Convert the current block to a heading 2',\n action: { type: 'convertBlock', blockType: 'heading', props: { level: 2 } },\n },\n {\n phrases: ['heading three', 'heading 3'],\n description: 'Convert the current block to a heading 3',\n action: { type: 'convertBlock', blockType: 'heading', props: { level: 3 } },\n },\n {\n phrases: ['bulleted list', 'bullet point', 'bullet list'],\n description: 'Convert the current block to a bulleted list item',\n action: { type: 'convertBlock', blockType: 'listItem', props: { ordered: false, titleRunIds: [] } },\n },\n {\n phrases: ['numbered list', 'ordered list'],\n description: 'Convert the current block to a numbered list item',\n action: { type: 'convertBlock', blockType: 'listItem', props: { ordered: true, titleRunIds: [] } },\n },\n {\n phrases: ['checklist', 'to-do', 'to do', 'to-do list', 'to do list'],\n description: 'Convert the current block to a to-do item',\n action: {\n type: 'convertBlock',\n blockType: 'listItem',\n props: { ordered: false, checked: false, titleRunIds: [] },\n },\n },\n {\n phrases: ['quote'],\n description: 'Convert the current block to a quote',\n action: { type: 'convertBlock', blockType: 'blockquote', props: {} },\n },\n {\n phrases: ['code block', 'code'],\n description: 'Convert the current block to a code block',\n action: { type: 'convertBlock', blockType: 'code', props: { language: 'plaintext' } },\n },\n { phrases: ['undo'], description: 'Undo the last edit', action: { type: 'undo' } },\n { phrases: ['redo'], description: 'Redo the last undone edit', action: { type: 'redo' } },\n {\n phrases: ['stop dictation', 'stop listening', 'stop'],\n description: 'Stop dictation',\n action: { type: 'stopDictation' },\n },\n];\n\nconst PHRASE_TO_ACTION = new Map();\nfor (const { phrases, action } of COMMANDS) {\n for (const phrase of phrases) PHRASE_TO_ACTION.set(phrase, action);\n}\n\n/**\n * Lowercases, trims, collapses internal whitespace, and strips trailing\n * sentence punctuation a speech engine commonly appends to a finalized\n * utterance (\".\", \",\", \"!\", \"?\") — none of that punctuation is meaningful\n * for matching a short command phrase.\n */\nexport function normalizeUtterance(text) {\n return (text ?? '')\n .toLowerCase()\n .trim()\n .replace(/\\s+/g, ' ')\n .replace(/[.,!?]+$/, '');\n}\n\n/**\n * Returns the matching command action for a normalized, complete utterance,\n * or null if it's plain dictation (no command matched). Exact-match only —\n * deliberately not a substring/contains check, so a sentence that merely\n * *mentions* a command phrase while dictating prose is never misread as a\n * command (matches only when the whole finalized utterance IS the phrase).\n */\nexport function matchVoiceCommand(text) {\n return PHRASE_TO_ACTION.get(normalizeUtterance(text)) ?? null;\n}\n\n/**\n * Read-only `[{ phrases, description }]` list for a host to render as an\n * in-app \"what can I say\" help list — pure data, no rendering opinion (see\n * examples/basic's own \"Voice commands\" button for one way to display it).\n */\nexport function listVoiceCommands() {\n return COMMANDS.map(({ phrases, description }) => ({ phrases: [...phrases], description }));\n}\n","import { convertBlockType } from '../blocks/shared/convertBlockType.js';\nimport { insertSiblingAfterAndFocus } from '../blocks/shared/blockCommands.js';\nimport { createTextLeafBlock } from '../blocks/shared/leafBlockFactory.js';\nimport { focusRunStart } from '../react/focusRun.js';\nimport { restoreSelectionAfterHistoryChange } from '../react/restoreHistorySelection.js';\n\nfunction applyOps(store, ops) {\n if (typeof store.performBatch === 'function') store.performBatch(ops);\n else for (const op of ops) store.applyOperation(op);\n}\n\nfunction getOwnRunIds(block) {\n return block?.props?.titleRunIds ?? block?.contentIds ?? [];\n}\n\n/**\n * Executes one matched voice command (see voiceCommands.js) against the\n * store. `blockId` is wherever the caret currently is — resolved by the\n * caller (useVoiceTyping) via resolveCollapsedCaret, the same way every\n * other command in this codebase locates \"the current block\".\n *\n * 'convertBlock' reuses convertBlockType directly (not the slash-command\n * factory path) specifically so any text already dictated into the\n * current block survives the conversion — the same reason\n * markdownShortcuts.js uses it, and doubly important here since a live\n * dictation session is far more likely to have real typed content in the\n * block at the moment a structural command is spoken.\n */\nexport function applyVoiceAction(store, blockId, action) {\n if (action.type === 'insertParagraph') {\n insertSiblingAfterAndFocus(store, blockId, createTextLeafBlock('paragraph'));\n return;\n }\n\n if (action.type === 'convertBlock') {\n const block = store.getBlock(blockId);\n if (!block) return;\n const runIds = getOwnRunIds(block);\n const { ops } = convertBlockType(store, blockId, action.blockType, action.props, runIds);\n applyOps(store, ops);\n if (runIds[0]) focusRunStart(runIds[0]);\n return;\n }\n\n if (action.type === 'undo') {\n if (store.undo?.()) restoreSelectionAfterHistoryChange(store);\n return;\n }\n\n if (action.type === 'redo') {\n if (store.redo?.()) restoreSelectionAfterHistoryChange(store);\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { flushSync } from 'react-dom';\nimport { useEditorStore } from './EditorProvider.jsx';\nimport { resolveCollapsedCaret } from './selectionResolve.js';\nimport { setCaretSync } from './focusRun.js';\nimport { updateRun } from '../store/operations.js';\nimport { matchVoiceCommand } from '../voice/voiceCommands.js';\nimport { applyVoiceAction } from '../voice/applyVoiceAction.js';\n\nfunction getSpeechRecognitionCtor() {\n if (typeof window === 'undefined') return null;\n return window.SpeechRecognition ?? window.webkitSpeechRecognition ?? null;\n}\n\nconst PERMISSION_DENIED_MESSAGE =\n 'Microphone access is blocked. Enable it in your browser\\'s site settings, then try again.';\n\n/**\n * Native-browser (Web Speech API) voice typing: live, continuous dictation\n * into the current caret position (text appears and self-corrects as you\n * speak, not just after each pause), plus spoken structural commands\n * (\"heading one\", \"new paragraph\", \"undo\", \"stop dictation\", ...)\n * recognized via voiceCommands.js — see that file for the full command\n * table and matching rules (also exported there as listVoiceCommands() for\n * an in-app \"what can I say\" help list).\n *\n * Deliberately built on the browser's own SpeechRecognition rather than a\n * bundled speech-to-text SDK: real speech recognition needs either a\n * network round-trip to a vendor's servers or a genuinely heavy on-device\n * model, either of which conflicts with this package staying zero-runtime-\n * dependency. `isSupported` is false (start()/stop() are no-ops) wherever\n * the API doesn't exist (Firefox, most notably) — a host app decides how\n * to surface that (hide the mic button, show a note, etc.), this hook just\n * degrades safely rather than throwing.\n *\n * ---- Never trust SpeechRecognition's resultIndex for phrase identity —\n * this is the part two earlier versions of this hook got wrong ----\n *\n * `sessionAnchorRef` (`{ runId, blockId, offset }`) is this hook's own,\n * single source of truth for \"where does the next chunk of dictated text\n * go\" — resolved from the real caret when `start()` is called, and after\n * that updated only by this hook's own writes OR by the `selectionchange`\n * listener below noticing the user manually moved the caret somewhere else\n * (click, arrow keys, Tab into another block) — it is never blindly\n * re-read from `window.getSelection()` on some other trigger (e.g. every\n * `onresult` event), which is what the two broken attempts below actually\n * ran into.\n *\n * `liveEntryRef` is the *one* mutable \"currently being revised, not yet\n * final\" text buffer — on every `onresult` event, every non-final result\n * in that event is concatenated into one string and used to *fully\n * replace* this single buffer's contents, regardless of which\n * `resultIndex`(es) the browser happened to report them under.\n * `committedCountRef` is a separate, monotonically-increasing \"how many\n * result indices have I already permanently committed\" counter, advanced\n * only when *this hook* finalizes something — used purely as a \"don't\n * reprocess an index I already committed\" guard, never for matching a new\n * event's index back to an existing in-progress phrase.\n *\n * This design replaced two earlier, both-broken attempts at using\n * `resultIndex` as a phrase identifier:\n * 1. Tracking a `Map` of every \"in-flight\" phrase keyed by resultIndex,\n * re-resolving the live caret each time a new index appeared. Real\n * Chrome doesn't keep resultIndex behaving cleanly enough for that —\n * a later index could get matched against a stale map entry, and\n * text landed out of order (\"11234567 89 10 11 ...\" for numbers\n * spoken in order).\n * 2. Comparing consecutive events' resultIndex to decide \"is this a\n * revision of the same phrase, or a new one\" (one phrase at a time,\n * no Map). Real Chrome can advance resultIndex on what is still\n * conceptually the same in-progress phrase, which made this treat\n * every revision as a brand-new phrase, anchored after the\n * previous (wrongly-separate) one's text — producing runaway,\n * compounding duplication (\"test for the\" -> \"test for the life\" ->\n * \"test for the life desc\" -> ... each revision re-typing the whole\n * growing sentence from scratch instead of replacing the last guess).\n *\n * Concatenate-all-non-final-into-one-buffer is the standard pattern real\n * speech-to-text integrations use (e.g. how the `react-speech-recognition`\n * library and most Web Speech API tutorials build up \"interim transcript\"\n * + \"final transcript\" separately) — it needs no assumption whatsoever\n * about how the browser indexes results across events.\n *\n * Every write still goes through `flushSync` (react-dom) before\n * `setCaretSync` (the non-rAF variant of focusRunAtOffset, see\n * focusRun.js) moves the *visible* caret to match — `TextRunSpan`\n * (EditableBlockContent.jsx) fully destroys and recreates the run's DOM\n * text node on every value change, which resets the browser's native\n * Selection, and a plain `store.applyOperation(...)` call is not\n * guaranteed to have committed that DOM change by the time it returns\n * (React may batch it) — `flushSync` forces the commit first. This part\n * only affects what the user visually sees the caret doing; the actual\n * text-insertion math never depends on it, since `sessionAnchorRef` is the\n * authority, not the DOM.\n *\n * Text is inserted/updated plain, with no \"tentative\" styling while\n * interim — it just grows and occasionally self-corrects as the engine\n * hears more context, the same way Google's own voice typing behaves.\n *\n * Command detection vs. plain dictation: only a *finalized* segment is\n * ever checked against the command table (matchVoiceCommand) — natural\n * pauses in speech are what the Speech API itself uses to decide a segment\n * is \"final\", so a command spoken as its own isolated utterance is\n * detected reliably, while the same words embedded in a longer dictated\n * sentence never match (the whole segment has to equal a known phrase,\n * not just contain one). If a phrase that was already live-inserted as\n * interim text finalizes as a command, the interim text is reverted\n * (removed) before the command runs — so e.g. saying \"heading one\" never\n * leaves \"heading one\" sitting in the paragraph before converting it, even\n * though \"heading\" alone may have briefly appeared while still mid-\n * utterance.\n *\n * `status` (`'idle' | 'listening' | 'processing'`) is driven by the Speech\n * API's own `onspeechstart`/`onspeechend` events, not a fabricated timer:\n * `onspeechend` fires when the engine detects you've stopped talking and is\n * about to finalize what it heard ('processing'), and the next committed\n * final result (or a fresh `onspeechstart`) returns to 'listening'. Neither\n * event is guaranteed on every engine — if they never fire, status simply\n * stays 'listening' for the whole session, a safe degrade, not a crash.\n * `VoiceListeningIndicator` (also exported) renders a small badge that\n * follows the live caret off this state.\n *\n * Mic permission: `recognition.onerror` reporting 'not-allowed' or\n * 'service-not-allowed' is the one cross-browser-reliable signal that\n * permission was denied (the Permissions API's 'microphone' descriptor\n * isn't supported in Firefox at all, and is inconsistent in Safari) — that\n * error sets `permissionState: 'denied'`. Where the Permissions API *is*\n * available, it's also queried opportunistically on mount (and its own\n * `change` event subscribed to) purely so a previously-denied permission\n * shows up in `permissionState` before the user even presses the mic\n * button, rather than only ever finding out after a failed start().\n * `VoicePermissionModal` (also exported) renders itself automatically off\n * this same state.\n *\n * `options.shortcut` (default true) wires one native, document-level\n * Ctrl/Cmd+Shift+M keydown listener that toggles start()/stop() — pass\n * `{ shortcut: false }` to opt out if a host wants its own binding.\n */\nexport function useVoiceTyping({ shortcut = true } = {}) {\n const store = useEditorStore();\n const [isListening, setIsListening] = useState(false);\n const [status, setStatus] = useState('idle');\n const [permissionState, setPermissionState] = useState('unknown');\n const [error, setError] = useState(null);\n const recognitionRef = useRef(null);\n // { runId, blockId, offset } | null — this hook's single, internally-\n // owned source of truth for \"where does dictation write next.\" See the\n // class comment for why this is never re-read from the live DOM\n // mid-session EXCEPT via the selectionchange listener below, which only\n // reacts to a caret move this hook didn't itself just cause.\n const sessionAnchorRef = useRef(null);\n // { runId, offset } | null — wherever this hook itself most recently\n // placed the caret (via setCaretSync in writeEntryText/revertEntryText).\n // The selectionchange listener compares against this to tell \"the user\n // just clicked/arrow-keyed somewhere else\" apart from \"the selection\n // changed because WE just rewrote this run's text and moved the caret to\n // match\" — without it, every dictated word would look indistinguishable\n // from a manual caret move and constantly re-anchor to nowhere useful.\n const expectedCaretRef = useRef(null);\n // The one, single \"still being revised\" text buffer — replaced wholesale\n // on every onresult event, never matched against a prior event by index.\n // { runId, blockId, startOffset, insertedLength, needsLeadingSpace } | null\n const liveEntryRef = useRef(null);\n // How many result indices this hook has already permanently committed —\n // only ever advanced by this hook itself; used solely to avoid\n // reprocessing an index already committed, never to identify a phrase.\n const committedCountRef = useRef(0);\n const isSupported = getSpeechRecognitionCtor() !== null;\n\n useEffect(() => {\n if (!navigator.permissions?.query) return undefined;\n let permissionStatus;\n let cancelled = false;\n navigator.permissions\n .query({ name: 'microphone' })\n .then((result) => {\n if (cancelled) return;\n permissionStatus = result;\n setPermissionState(result.state);\n permissionStatus.onchange = () => setPermissionState(permissionStatus.state);\n })\n .catch(() => {}); // unsupported descriptor name (e.g. Safari) — fall back to onerror-only detection\n return () => {\n cancelled = true;\n if (permissionStatus) permissionStatus.onchange = null;\n };\n }, []);\n\n const createEntryAtAnchor = useCallback(() => {\n if (!sessionAnchorRef.current) {\n const caret = resolveCollapsedCaret();\n if (!caret) return null;\n sessionAnchorRef.current = caret;\n }\n return {\n runId: sessionAnchorRef.current.runId,\n blockId: sessionAnchorRef.current.blockId,\n startOffset: sessionAnchorRef.current.offset,\n insertedLength: 0,\n };\n }, []);\n\n const writeEntryText = useCallback(\n (entry, text) => {\n const run = store.getRun(entry.runId);\n if (!run || run.type !== 'text') return;\n const value = run.value ?? '';\n const before = value.slice(0, entry.startOffset);\n // The leading-space decision is made once, against whatever sat\n // right before the anchor when this phrase began, and reused for\n // every revision of this same phrase — recomputing it against the\n // phrase's *own* still-growing text on each revision would flip it\n // back and forth as that text changes shape.\n if (entry.needsLeadingSpace === undefined) {\n const beforeChar = before[before.length - 1];\n entry.needsLeadingSpace = entry.startOffset > 0 && beforeChar !== undefined && !/\\s/.test(beforeChar);\n }\n const insertedText = (entry.needsLeadingSpace ? ' ' : '') + text;\n const after = value.slice(entry.startOffset + entry.insertedLength);\n // flushSync forces React to synchronously commit this store write\n // (including TextRunSpan's DOM-rewriting layout effect) before it\n // returns, so setCaretSync right after is guaranteed to see the\n // freshly-rewritten text node rather than a stale one.\n flushSync(() => store.applyOperation(updateRun(entry.runId, { value: before + insertedText + after })));\n entry.insertedLength = insertedText.length;\n const nextOffset = entry.startOffset + insertedText.length;\n setCaretSync(entry.runId, nextOffset);\n sessionAnchorRef.current = { runId: entry.runId, blockId: entry.blockId, offset: nextOffset };\n expectedCaretRef.current = { runId: entry.runId, offset: nextOffset };\n },\n [store],\n );\n\n const revertEntryText = useCallback(\n (entry) => {\n const run = store.getRun(entry.runId);\n if (!run || run.type !== 'text') return;\n const value = run.value ?? '';\n const restored = value.slice(0, entry.startOffset) + value.slice(entry.startOffset + entry.insertedLength);\n flushSync(() => store.applyOperation(updateRun(entry.runId, { value: restored })));\n setCaretSync(entry.runId, entry.startOffset);\n sessionAnchorRef.current = { runId: entry.runId, blockId: entry.blockId, offset: entry.startOffset };\n expectedCaretRef.current = { runId: entry.runId, offset: entry.startOffset };\n },\n [store],\n );\n\n /**\n * Same text removal as `revertEntryText`, but WITHOUT touching the real\n * caret/selection — used when the user has just manually moved focus\n * away from `entry`'s own block (see the selectionchange listener below),\n * where `setCaretSync`ing back to it would fight the move the user just\n * made. Leaving the interim guess in place instead (an earlier version of\n * this fix did exactly that) caused a duplication bug: the NEXT interim\n * update for the same still-in-progress utterance writes the full\n * accumulated transcript again at the new anchor, since SpeechRecognition\n * interim results are always the whole phrase-so-far, not just the new\n * part — so the old block was left with a stale partial guess and the new\n * block got the same words all over again.\n */\n const removeEntryTextSilently = useCallback(\n (entry) => {\n const run = store.getRun(entry.runId);\n if (!run || run.type !== 'text') return;\n const value = run.value ?? '';\n const restored = value.slice(0, entry.startOffset) + value.slice(entry.startOffset + entry.insertedLength);\n store.applyOperation(updateRun(entry.runId, { value: restored }));\n },\n [store],\n );\n\n const handleRecognitionResult = useCallback(\n (event) => {\n let interimText = '';\n let hasInterim = false;\n const start = Math.max(event.resultIndex, committedCountRef.current);\n\n for (let i = start; i < event.results.length; i += 1) {\n const result = event.results[i];\n const transcript = result[0]?.transcript ?? '';\n\n if (!result.isFinal) {\n interimText += (interimText ? ' ' : '') + transcript;\n hasInterim = true;\n continue;\n }\n\n // Finalizing: reuse the live buffer if one exists (the common\n // case — this text was almost certainly interim a moment ago),\n // otherwise create a fresh one (a short utterance can finalize\n // with no prior interim event at all).\n const entry = liveEntryRef.current ?? createEntryAtAnchor();\n liveEntryRef.current = null;\n committedCountRef.current = i + 1;\n if (!entry) continue; // nowhere to anchor — drop this one\n\n const command = matchVoiceCommand(transcript);\n if (command) {\n revertEntryText(entry); // the interim guess was never real content\n if (command.type === 'stopDictation') {\n recognitionRef.current?.stop();\n } else {\n applyVoiceAction(store, entry.blockId, command);\n // The command may have moved focus into a different block/run\n // (e.g. a new paragraph) via this codebase's usual rAF-deferred\n // focus helpers — force the next phrase to re-resolve the live\n // caret rather than trusting a position that's now stale.\n // expectedCaretRef is cleared too, so the selectionchange\n // listener below doesn't mistake the command's own (rAF-\n // deferred, so not yet reflected here) focus move for a manual\n // one and race it.\n sessionAnchorRef.current = null;\n expectedCaretRef.current = null;\n setStatus('listening');\n }\n } else {\n writeEntryText(entry, transcript);\n setStatus('listening');\n }\n }\n\n if (hasInterim) {\n const entry = liveEntryRef.current ?? createEntryAtAnchor();\n if (entry) {\n liveEntryRef.current = entry;\n writeEntryText(entry, interimText);\n }\n }\n },\n [store, createEntryAtAnchor, writeEntryText, revertEntryText],\n );\n\n // Detects the user manually moving the caret (click, arrow keys, Tab into\n // another block, ...) WHILE dictation is listening, and redirects the\n // next dictated phrase there instead of silently continuing to write at\n // the stale session anchor — this is the fix for a real bug: without it,\n // clicking into a different block mid-dictation had no effect on where\n // the next phrase landed, and `setCaretSync` would keep snapping the\n // visible caret back to the old spot on every subsequent word, making it\n // look like focus was being fought over.\n //\n // Only reacts when the resolved caret differs from `expectedCaretRef` —\n // this hook's own record of wherever IT most recently placed the caret —\n // so it never mistakes its own writes (which also move the real DOM\n // selection) for a manual move. `expectedCaretRef` being null (right\n // after a voice command moved focus, before the next phrase has\n // re-resolved yet) means there's no baseline to compare against yet, so\n // the listener stays passive rather than racing that in-flight move.\n useEffect(() => {\n if (!isListening) return undefined;\n const handleSelectionChange = () => {\n const expected = expectedCaretRef.current;\n if (!expected) return;\n const caret = resolveCollapsedCaret();\n if (!caret) return; // selection isn't a collapsed caret inside a run right now — nothing to redirect to\n if (caret.runId === expected.runId && caret.offset === expected.offset) return; // our own write\n if (liveEntryRef.current) {\n // Discard the not-yet-finalized guess left behind in the old block —\n // see removeEntryTextSilently's own doc comment for why leaving it\n // in place duplicated text instead.\n removeEntryTextSilently(liveEntryRef.current);\n liveEntryRef.current = null;\n }\n sessionAnchorRef.current = caret;\n expectedCaretRef.current = { runId: caret.runId, offset: caret.offset };\n };\n document.addEventListener('selectionchange', handleSelectionChange);\n return () => document.removeEventListener('selectionchange', handleSelectionChange);\n }, [isListening, removeEntryTextSilently]);\n\n const start = useCallback(() => {\n if (!isSupported || recognitionRef.current) return;\n setError(null);\n const initialCaret = resolveCollapsedCaret();\n sessionAnchorRef.current = initialCaret;\n expectedCaretRef.current = initialCaret ? { runId: initialCaret.runId, offset: initialCaret.offset } : null;\n liveEntryRef.current = null;\n committedCountRef.current = 0;\n const Ctor = getSpeechRecognitionCtor();\n const recognition = new Ctor();\n recognition.continuous = true;\n recognition.interimResults = true;\n recognition.onresult = handleRecognitionResult;\n recognition.onstart = () => setStatus('listening');\n recognition.onspeechstart = () => setStatus('listening');\n recognition.onspeechend = () => setStatus('processing');\n recognition.onerror = (event) => {\n if (event.error === 'not-allowed' || event.error === 'service-not-allowed') {\n setPermissionState('denied');\n setError(PERMISSION_DENIED_MESSAGE);\n } else {\n setError(event.error ?? 'Voice typing stopped unexpectedly.');\n }\n };\n recognition.onend = () => {\n recognitionRef.current = null;\n sessionAnchorRef.current = null;\n expectedCaretRef.current = null;\n liveEntryRef.current = null;\n committedCountRef.current = 0;\n setIsListening(false);\n setStatus('idle');\n };\n recognitionRef.current = recognition;\n recognition.start();\n setIsListening(true);\n }, [isSupported, handleRecognitionResult]);\n\n const stop = useCallback(() => {\n recognitionRef.current?.stop();\n }, []);\n\n useEffect(() => () => recognitionRef.current?.stop(), []);\n\n useEffect(() => {\n if (!shortcut || !isSupported) return undefined;\n const handleKeyDown = (event) => {\n const mod = event.metaKey || event.ctrlKey;\n if (!mod || !event.shiftKey || event.key.toLowerCase() !== 'm') return;\n event.preventDefault();\n if (recognitionRef.current) stop();\n else start();\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [shortcut, isSupported, start, stop]);\n\n return { isSupported, isListening, status, permissionState, error, start, stop };\n}\n","import { useEffect, useState } from 'react';\nimport { Modal } from './Modal.jsx';\n\n/**\n * Ready-made \"microphone access is blocked\" dialog for useVoiceTyping —\n * mount it once anywhere alongside a mic button: `<VoicePermissionModal\n * voice={voice} />`. Driven by `voice.permissionState`, so there's no\n * separate isOpen prop to wire — it opens itself the instant permission is\n * detected as denied (whether that's from a failed start() attempt or the\n * opportunistic Permissions API check useVoiceTyping does on mount).\n *\n * Manually dismissible (Escape/backdrop click, via Modal's own built-in\n * handling) rather than forced to stay open until permission is fixed —\n * `dismissed` tracks that locally and resets the instant a *new* denial\n * comes in (voice.error changing is what \"a new denial just happened\"\n * means here, since start() always clears error first) so the dialog\n * reappears on the next real attempt even after being dismissed once,\n * rather than staying silently suppressed forever.\n */\nexport function VoicePermissionModal({ voice }) {\n const [dismissed, setDismissed] = useState(false);\n\n useEffect(() => {\n setDismissed(false);\n }, [voice?.error]);\n\n const isOpen = voice?.permissionState === 'denied' && !dismissed;\n\n return (\n <Modal isOpen={isOpen} onClose={() => setDismissed(true)} title=\"Microphone access blocked\">\n <p>{voice?.error || 'Microphone access is blocked. Enable it in your browser\\'s site settings, then try again.'}</p>\n <div className=\"be-modal-actions\">\n <button type=\"button\" className=\"be-modal-cancel\" onClick={() => setDismissed(true)}>\n Dismiss\n </button>\n <button type=\"button\" className=\"be-modal-save\" onClick={() => voice?.start?.()}>\n Try again\n </button>\n </div>\n </Modal>\n );\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * Tracks the live collapsed caret's bounding rect, recomputed via the same\n * event set `useFloatingToolbarTrigger` uses for its own (non-collapsed)\n * selection tracking — `document`'s `selectionchange`, plus `window`\n * scroll (capture phase)/resize, since a `position: fixed` box anchored to\n * a rect needs to stay correct across page scroll. `selectionchange` fires\n * even for *programmatic* `Selection.addRange()` calls, which is what\n * `setCaretSync` (focusRun.js) already does on every voice-dictation text\n * insertion — so this reliably follows the caret while dictating without\n * useVoiceTyping needing to know anything about this hook at all.\n *\n * Only active while `isActive` is true (pass `voice.isListening`) — a\n * no-op with zero listeners attached otherwise, so this costs nothing when\n * not dictating. Returns `null` whenever there's no collapsed caret inside\n * an editable run (`[data-run-id]`), rather than a stale/wrong position.\n */\nexport function useCaretRect(isActive) {\n const [rect, setRect] = useState(null);\n\n useEffect(() => {\n if (!isActive) {\n setRect(null);\n return undefined;\n }\n\n const recompute = () => {\n const selection = window.getSelection?.();\n if (!selection || selection.rangeCount === 0 || !selection.isCollapsed) {\n setRect(null);\n return;\n }\n const node = selection.anchorNode;\n const el = node?.nodeType === 1 ? node : node?.parentElement;\n if (!el?.closest?.('[data-run-id]')) {\n setRect(null);\n return;\n }\n\n // jsdom (this package's own test suite) implements\n // Element.prototype.getBoundingClientRect but not\n // Range.prototype.getBoundingClientRect — falling back to a zero\n // rect keeps this testable without a real layout engine, same\n // convention as useFloatingToolbarTrigger.\n const nextRect = selection.getRangeAt(0).getBoundingClientRect?.() ?? {\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n width: 0,\n height: 0,\n };\n setRect(nextRect);\n };\n\n recompute();\n document.addEventListener('selectionchange', recompute);\n window.addEventListener('scroll', recompute, true);\n window.addEventListener('resize', recompute);\n return () => {\n document.removeEventListener('selectionchange', recompute);\n window.removeEventListener('scroll', recompute, true);\n window.removeEventListener('resize', recompute);\n };\n }, [isActive]);\n\n return rect;\n}\n","import { useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useCaretRect } from './useCaretRect.js';\nimport { useAutoAdjustedCenteredLeft } from './usePopoverEdgeClamp.js';\nimport { MicIcon } from './icons.jsx';\n\n/**\n * Ready-made \"voice typing is actively working\" indicator for\n * useVoiceTyping — mount it once anywhere: `<VoiceListeningIndicator\n * voice={voice} />`. A toolbar-only status label is easy to miss since\n * attention is on the text being dictated, not the toolbar, so this\n * renders a small pulsing badge anchored right above the live caret\n * instead — the same `getBoundingClientRect()`-off-a-Range positioning\n * `FloatingToolbar`/`LinkHoverCard` already use elsewhere in this\n * codebase (see useCaretRect.js), so it visibly follows the caret as\n * dictated text streams in and moves it.\n *\n * Renders nothing when not listening, or when there's currently no\n * resolvable caret position (useCaretRect returns null) — never shows a\n * stale/wrong-position badge.\n */\nexport function VoiceListeningIndicator({ voice }) {\n const isActive = Boolean(voice?.isListening);\n const rect = useCaretRect(isActive);\n const badgeRef = useRef(null);\n // Only the horizontal axis is clamped — the badge sits right above the\n // caret (`translateY(-100%)`), which stays within the viewport in\n // practice since the caret itself must be visible to type into; the\n // centered horizontal offset is the one that can push it off-screen near\n // the left/right edge of a narrow viewport.\n const centerLeft = useAutoAdjustedCenteredLeft(badgeRef, Boolean(isActive && rect), rect?.left);\n\n if (!isActive || !rect || centerLeft == null) return null;\n\n const isProcessing = voice.status === 'processing';\n\n return createPortal(\n <div\n ref={badgeRef}\n className={`be-voice-indicator${isProcessing ? ' be-voice-indicator-processing' : ''}`}\n contentEditable={false}\n style={{ position: 'fixed', top: rect.top - 8, left: centerLeft, transform: 'translate(-50%, -100%)' }}\n >\n <span className=\"be-voice-indicator-dot\" />\n <MicIcon size={12} />\n <span className=\"be-voice-indicator-label\">{isProcessing ? 'Processing…' : 'Listening…'}</span>\n </div>,\n document.body,\n );\n}\n","import { useMemo } from 'react';\nimport { Modal } from './Modal.jsx';\nimport { useBlockRegistry, useInlineRegistry } from './EditorProvider.jsx';\n\n/**\n * The \"+\" button's target in MobileActionBar — a bottom sheet listing every\n * insertable block/inline command, tap-friendly instead of the small\n * hover-oriented SlashMenu popover. Lists the exact same union\n * useSlashMenuTrigger.js builds (registry + inlineRegistry's own\n * listSlashCommands()) so this is never a second, drifting copy of \"what\n * can be inserted\" — it's the discoverable, always-reachable mobile\n * entry point to insertion, coexisting with (not replacing) typing \"/\" or\n * \"@\" directly, which still works via the existing trigger hooks.\n *\n * `onSelectCommand(command)` is called with the raw command object;\n * MobileActionBar resolves the current caret position itself (via\n * resolveCollapsedCaret, same as this sheet has no live selection of its\n * own once it's open — tapping into the sheet doesn't move the editor's\n * caret) and calls `command.run(store, {...})`.\n */\nexport function MobileBlockPickerSheet({ isOpen, onClose, onSelectCommand }) {\n const registry = useBlockRegistry();\n const inlineRegistry = useInlineRegistry();\n\n const commands = useMemo(\n () => [...(registry?.listSlashCommands() ?? []), ...(inlineRegistry?.listSlashCommands() ?? [])],\n [registry, inlineRegistry],\n );\n\n return (\n <Modal isOpen={isOpen} onClose={onClose} title=\"Add a block\" variant=\"sheet\">\n <div className=\"be-mobile-picker-list\" role=\"listbox\" aria-label=\"Insertable blocks\">\n {commands.map((command) => {\n const Icon = command.icon;\n return (\n <button\n key={command.label}\n type=\"button\"\n role=\"option\"\n className=\"be-mobile-picker-item\"\n onClick={() => onSelectCommand(command)}\n >\n {Icon && (\n <span className=\"be-mobile-picker-item-icon\">\n <Icon size={18} />\n </span>\n )}\n <span className=\"be-mobile-picker-item-label\">{command.label}</span>\n </button>\n );\n })}\n </div>\n </Modal>\n );\n}\n","import { useCallback } from 'react';\nimport { Modal } from './Modal.jsx';\nimport { announce } from './liveAnnouncer.js';\nimport { duplicateBlock, moveBlockUp, moveBlockDown, deleteBlockAndFocusSibling } from '../blocks/shared/blockActions.js';\nimport { updateBlockProps } from '../store/operations.js';\nimport { CopyIcon, ArrowUpIcon, ArrowDownIcon, TrashIcon, EyeIcon, EyeOffIcon } from './icons.jsx';\n\n/**\n * The mobile counterpart to BlockGutterRow's own \"grip handle\" menu\n * (Duplicate / Move up / Move down / Hide-Show / Delete) — same actions,\n * same underlying handlers (duplicateBlock/moveBlockUp/moveBlockDown/\n * deleteBlockAndFocusSibling from blocks/shared/blockActions.js), just\n * reachable from MobileActionBar's \"block options\" button instead of a\n * hover-revealed gutter icon that has nothing to be revealed by on touch.\n *\n * `blockId` is always the TOP-LEVEL ancestor of wherever the caret\n * currently is (see MobileActionBar's findTopLevelAncestor) — matching\n * BlockGutterRow's own scope restriction to top-level blocks only; a caret\n * inside a table cell or callout still acts on the containing top-level\n * block, not the cell/callout itself.\n */\nexport function MobileBlockOptionsSheet({ isOpen, onClose, store, blockId }) {\n const block = blockId ? store.getBlock(blockId) : null;\n const isHidden = Boolean(block?.props?.hidden);\n\n const run = useCallback(\n (action) => {\n action();\n onClose();\n },\n [onClose],\n );\n\n return (\n <Modal isOpen={isOpen} onClose={onClose} title=\"Block options\" variant=\"sheet\">\n <div className=\"be-mobile-picker-list\" role=\"menu\" aria-label=\"Block options\">\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-mobile-picker-item\"\n onClick={() => run(() => {\n duplicateBlock(store, blockId);\n announce('Block duplicated');\n })}\n >\n <span className=\"be-mobile-picker-item-icon\">\n <CopyIcon size={18} />\n </span>\n <span className=\"be-mobile-picker-item-label\">Duplicate</span>\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-mobile-picker-item\"\n onClick={() => run(() => {\n if (moveBlockUp(store, blockId)) announce('Block moved up');\n })}\n >\n <span className=\"be-mobile-picker-item-icon\">\n <ArrowUpIcon size={18} />\n </span>\n <span className=\"be-mobile-picker-item-label\">Move up</span>\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-mobile-picker-item\"\n onClick={() => run(() => {\n if (moveBlockDown(store, blockId)) announce('Block moved down');\n })}\n >\n <span className=\"be-mobile-picker-item-icon\">\n <ArrowDownIcon size={18} />\n </span>\n <span className=\"be-mobile-picker-item-label\">Move down</span>\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-mobile-picker-item\"\n onClick={() => run(() => {\n store.applyOperation(updateBlockProps(blockId, { hidden: !isHidden }));\n announce(isHidden ? 'Block shown in preview' : 'Block hidden in preview');\n })}\n >\n <span className=\"be-mobile-picker-item-icon\">\n {isHidden ? <EyeIcon size={18} /> : <EyeOffIcon size={18} />}\n </span>\n <span className=\"be-mobile-picker-item-label\">{isHidden ? 'Show in preview' : 'Hide in preview'}</span>\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-mobile-picker-item be-mobile-picker-item-danger\"\n onClick={() => run(() => {\n deleteBlockAndFocusSibling(store, blockId);\n announce('Block deleted');\n })}\n >\n <span className=\"be-mobile-picker-item-icon\">\n <TrashIcon size={18} />\n </span>\n <span className=\"be-mobile-picker-item-label\">Delete</span>\n </button>\n </div>\n </Modal>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useEditorStore } from './EditorProvider.jsx';\nimport { useHistory } from './useHistory.js';\nimport { useCoarsePointer } from './useCoarsePointer.js';\nimport { useVirtualKeyboardInset } from './useVirtualKeyboardInset.js';\nimport { useTextFormattingActions } from '../commands/useTextFormattingActions.js';\nimport { resolveCollapsedCaret, resolveMultiRunSelection, resolveCrossBlockSelection } from './selectionResolve.js';\nimport { getMarksSummaryOverSelection, getMarksSummaryOverBlockRange } from '../inline/markCommands.js';\nimport { updateBlockProps } from '../store/operations.js';\nimport { insertRowAfter, insertColumnAfter } from '../blocks/table/tableEditCommands.js';\nimport { LANGUAGES } from '../blocks/code/CodeBlock.jsx';\nimport { CALLOUT_COLORS } from '../blocks/callout/CalloutBlock.jsx';\nimport { Select } from './Select.jsx';\nimport { MobileBlockPickerSheet } from './MobileBlockPickerSheet.jsx';\nimport { MobileBlockOptionsSheet } from './MobileBlockOptionsSheet.jsx';\nimport { BoldIcon, ItalicIcon, UnderlineIcon, LinkIcon, PlusIcon, MoreHorizontalIcon, ChevronDownIcon } from './icons.jsx';\n\nconst LANGUAGE_OPTIONS = LANGUAGES.map((lang) => ({ value: lang, label: lang }));\n\n/**\n * Watches focus + the live Selection to decide what MobileActionBar should\n * show: null while focus isn't inside the editor at all, 'selection' with a\n * resolved same-block/cross-block shape + marks summary while there's a\n * real (non-collapsed) text selection, or 'caret' with a resolved\n * {blockId, runId, offset} while the caret is simply parked somewhere.\n * Mirrors useFloatingToolbarTrigger's own selectionchange-driven recompute,\n * generalized to also track the collapsed-caret case that hook doesn't need.\n */\nfunction useMobileBarState(containerRef, store) {\n const [isFocused, setIsFocused] = useState(false);\n const [mode, setMode] = useState(null);\n const [selectionState, setSelectionState] = useState(null);\n const [caretState, setCaretState] = useState(null);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return undefined;\n const handleFocusIn = () => setIsFocused(true);\n const handleFocusOut = (event) => {\n if (!container.contains(event.relatedTarget)) setIsFocused(false);\n };\n container.addEventListener('focusin', handleFocusIn);\n container.addEventListener('focusout', handleFocusOut);\n return () => {\n container.removeEventListener('focusin', handleFocusIn);\n container.removeEventListener('focusout', handleFocusOut);\n };\n }, [containerRef]);\n\n useEffect(() => {\n if (!isFocused) {\n setMode(null);\n return undefined;\n }\n\n const recompute = () => {\n const container = containerRef.current;\n const selection = window.getSelection?.();\n if (!container || !selection || selection.rangeCount === 0) {\n setMode(null);\n return;\n }\n\n if (!selection.isCollapsed) {\n if (!container.contains(selection.anchorNode) || !container.contains(selection.focusNode)) {\n setMode(null);\n return;\n }\n const sameBlock = resolveMultiRunSelection();\n if (sameBlock) {\n setSelectionState({\n kind: 'same-block',\n selection: sameBlock,\n crossSelection: null,\n marks: getMarksSummaryOverSelection(store, sameBlock.blockId, sameBlock),\n });\n setMode('selection');\n return;\n }\n const crossBlock = resolveCrossBlockSelection(store);\n if (crossBlock) {\n setSelectionState({\n kind: 'cross-block',\n selection: null,\n crossSelection: crossBlock,\n marks: getMarksSummaryOverBlockRange(store, crossBlock),\n });\n setMode('selection');\n return;\n }\n setMode(null);\n return;\n }\n\n const caret = resolveCollapsedCaret();\n if (!caret || !container.contains(selection.anchorNode)) {\n setMode(null);\n return;\n }\n setCaretState(caret);\n setMode('caret');\n };\n\n recompute();\n document.addEventListener('selectionchange', recompute);\n return () => document.removeEventListener('selectionchange', recompute);\n }, [isFocused, store, containerRef]);\n\n return { isFocused, mode, selectionState, caretState };\n}\n\nfunction FormattingActions({ store, selectionState }) {\n const { kind, selection, crossSelection, marks } = selectionState;\n const { toggleBoolean, openLinkModal } = useTextFormattingActions(store, kind, selection, crossSelection, marks);\n\n return (\n <>\n <button\n type=\"button\"\n className={`be-mobile-bar-btn${marks.bold ? ' be-mobile-bar-btn-active' : ''}`}\n aria-label=\"Bold\"\n onClick={() => toggleBoolean('bold')}\n >\n <BoldIcon size={18} />\n </button>\n <button\n type=\"button\"\n className={`be-mobile-bar-btn${marks.italic ? ' be-mobile-bar-btn-active' : ''}`}\n aria-label=\"Italic\"\n onClick={() => toggleBoolean('italic')}\n >\n <ItalicIcon size={18} />\n </button>\n <button\n type=\"button\"\n className={`be-mobile-bar-btn${marks.underline ? ' be-mobile-bar-btn-active' : ''}`}\n aria-label=\"Underline\"\n onClick={() => toggleBoolean('underline')}\n >\n <UnderlineIcon size={18} />\n </button>\n <button\n type=\"button\"\n className={`be-mobile-bar-btn${marks.link ? ' be-mobile-bar-btn-active' : ''}`}\n aria-label=\"Link\"\n onClick={openLinkModal}\n >\n <LinkIcon size={18} />\n </button>\n </>\n );\n}\n\n/** Table-cell-specific quick actions: insert a row below / a column to the right of the current cell. */\nfunction TableCellActions({ store, blockId }) {\n const handleInsertRow = useCallback(() => {\n const cell = store.getBlock(blockId);\n const row = cell && store.getBlock(cell.parentId);\n if (row) insertRowAfter(store, row.id);\n }, [store, blockId]);\n\n const handleInsertColumn = useCallback(() => {\n const cell = store.getBlock(blockId);\n const row = cell && store.getBlock(cell.parentId);\n const table = row && store.getBlock(row.parentId);\n if (!table || !row) return;\n const colIndex = row.contentIds.indexOf(blockId);\n if (colIndex !== -1) insertColumnAfter(store, table.id, colIndex);\n }, [store, blockId]);\n\n return (\n <>\n <button type=\"button\" className=\"be-mobile-bar-btn\" aria-label=\"Insert row below\" onClick={handleInsertRow}>\n + Row\n </button>\n <button type=\"button\" className=\"be-mobile-bar-btn\" aria-label=\"Insert column right\" onClick={handleInsertColumn}>\n + Column\n </button>\n </>\n );\n}\n\n/** Code-block-specific quick action: change the block's language. */\nfunction CodeBlockActions({ store, blockId }) {\n const block = store.getBlock(blockId);\n const handleLanguageChange = useCallback(\n (language) => store.applyOperation(updateBlockProps(blockId, { language })),\n [store, blockId],\n );\n return (\n <Select\n className=\"be-mobile-bar-select\"\n value={block?.props?.language ?? 'plaintext'}\n options={LANGUAGE_OPTIONS}\n onChange={handleLanguageChange}\n ariaLabel=\"Code language\"\n />\n );\n}\n\n/** Callout-specific quick action: the same color palette CalloutBlock's own picker offers. */\nfunction CalloutActions({ store, blockId }) {\n const block = store.getBlock(blockId);\n const color = block?.props?.color;\n return (\n <div className=\"be-mobile-bar-swatches\">\n {CALLOUT_COLORS.map((c) => (\n <button\n key={c.value}\n type=\"button\"\n className={`be-callout-color-option be-callout-color-option-${c.value}${c.value === color ? ' be-callout-color-option-active' : ''}`}\n aria-label={c.label}\n title={c.label}\n onClick={() => store.applyOperation(updateBlockProps(blockId, { color: c.value }))}\n />\n ))}\n </div>\n );\n}\n\nconst BLOCK_TYPE_ACTIONS = {\n tableCell: TableCellActions,\n code: CodeBlockActions,\n callout: CalloutActions,\n};\n\n/**\n * Walks up from the caret's own (leaf) block to find the nearest ancestor\n * with type-specific quick actions — needed because not every \"context\" is\n * itself a leaf: a table cell IS the leaf the caret resolves to directly,\n * but a callout's caret always resolves to a *nested paragraph* (callout is\n * a plain container, same mechanism as a page/layout column — see\n * CalloutBlock.jsx), so checking only the immediate leaf's own type would\n * never match 'callout' at all.\n */\nfunction findActionableAncestor(store, blockId) {\n let current = store.getBlock(blockId);\n while (current) {\n if (BLOCK_TYPE_ACTIONS[current.type]) return current;\n current = current.parentId ? store.getBlock(current.parentId) : null;\n }\n return null;\n}\n\n/**\n * Walks up to the TOP-LEVEL ancestor of `blockId` — the same block\n * BlockGutterRow's own hover gutter would act on for this content, since\n * that gutter (and its Duplicate/Move/Hide/Delete menu) is only ever\n * mounted for top-level blocks, never nested content (a table cell, a\n * callout's children, ...). MobileActionBar's \"block options\" button\n * mirrors that exact scope: a caret in a table cell duplicates/moves/\n * deletes the whole table, not just that one cell.\n */\nfunction findTopLevelAncestor(store, blockId) {\n const rootId = store.getRootId();\n let current = store.getBlock(blockId);\n while (current && current.parentId !== rootId) {\n current = store.getBlock(current.parentId);\n }\n return current;\n}\n\n/**\n * Persistent action surface pinned above the on-screen keyboard on touch\n * devices — the mobile counterpart to typing \"/\"/\"@\" or hovering the block\n * gutter, neither of which is a reliable or discoverable way to act on\n * this editor from a phone/tablet (see the mobile UX audit this was built\n * from). Mount once alongside the other trigger hooks (useSlashMenuTrigger,\n * etc.) in the same container.\n *\n * Deliberately a no-op (renders nothing) on a fine (mouse) pointer, or\n * whenever focus isn't currently inside the editor — this never appears\n * on desktop, and never lingers after the user taps away.\n *\n * \"Block options\" (a horizontal-dots icon — the conventional mobile \"more\n * actions\" affordance, not desktop's own grip-handle glyph, which reads\n * oddly outside a drag-handle context) sits at the right end of the bar,\n * next to the dismiss-keyboard button, and shows whenever the caret or\n * selection is inside any block: opens MobileBlockOptionsSheet (Duplicate/\n * Move up/Move down/Hide/Delete) — the mobile home for BlockGutterRow's\n * own grip-handle menu, which this codebase deliberately hides entirely on\n * touch input instead (see .be-touch-input in style.css) since there's no\n * hover state to reveal it by and its desktop position sits in a page\n * margin that doesn't exist on a narrow viewport.\n *\n * The rest of the bar swaps based on what's currently selected/focused:\n * - a real text selection -> formatting actions (bold/italic/underline/\n * link), reusing the exact same useTextFormattingActions hook\n * FloatingToolbar (desktop) uses — one shared implementation, not two.\n * - a collapsed caret -> \"+\" (opens MobileBlockPickerSheet), Undo/Redo,\n * plus type-specific quick actions when the caret is in a table cell,\n * code block, or callout (see BLOCK_TYPE_ACTIONS) — the \"smarter than a\n * single static bar everywhere\" piece.\n */\nexport function MobileActionBar({ containerRef }) {\n const store = useEditorStore();\n const history = useHistory();\n const isCoarsePointer = useCoarsePointer();\n const keyboardInset = useVirtualKeyboardInset();\n const { isFocused, mode, selectionState, caretState } = useMobileBarState(containerRef, store);\n const [isPickerOpen, setIsPickerOpen] = useState(false);\n const [isOptionsOpen, setIsOptionsOpen] = useState(false);\n\n const openPicker = useCallback(() => setIsPickerOpen(true), []);\n const closePicker = useCallback(() => setIsPickerOpen(false), []);\n const openOptions = useCallback(() => setIsOptionsOpen(true), []);\n const closeOptions = useCallback(() => setIsOptionsOpen(false), []);\n\n const handleSelectCommand = useCallback(\n (command) => {\n const caret = resolveCollapsedCaret() ?? caretState;\n if (!caret) return;\n command.run(store, {\n blockId: caret.blockId,\n runId: caret.runId,\n sliceStart: caret.offset,\n sliceEnd: caret.offset,\n });\n closePicker();\n },\n [store, caretState, closePicker],\n );\n\n const handleDismissKeyboard = useCallback(() => {\n document.activeElement?.blur?.();\n }, []);\n\n if (!isCoarsePointer || !isFocused) return null;\n\n const actionableBlock = mode === 'caret' && caretState ? findActionableAncestor(store, caretState.blockId) : null;\n const TypeActions = actionableBlock ? BLOCK_TYPE_ACTIONS[actionableBlock.type] : null;\n\n // Whichever block the caret/selection is currently in, regardless of\n // mode — \"block options\" (duplicate/move/hide/delete) makes sense either\n // way, unlike \"+\", which only means something for a collapsed caret.\n const currentBlockId =\n mode === 'caret' && caretState\n ? caretState.blockId\n : (selectionState?.selection?.blockId ?? selectionState?.crossSelection?.startBlockId ?? null);\n const topLevelBlock = currentBlockId ? findTopLevelAncestor(store, currentBlockId) : null;\n\n return (\n <>\n <div\n className=\"be-mobile-action-bar\"\n role=\"toolbar\"\n aria-label=\"Editor actions\"\n style={{ bottom: keyboardInset }}\n onMouseDown={(event) => event.preventDefault()}\n >\n {mode === 'selection' && selectionState && <FormattingActions store={store} selectionState={selectionState} />}\n\n {mode !== 'selection' && (\n <>\n <button type=\"button\" className=\"be-mobile-bar-btn\" aria-label=\"Add block\" onClick={openPicker}>\n <PlusIcon size={18} />\n </button>\n {TypeActions && actionableBlock && <TypeActions store={store} blockId={actionableBlock.id} />}\n {history && (\n <>\n <button\n type=\"button\"\n className=\"be-mobile-bar-btn\"\n aria-label=\"Undo\"\n disabled={!history.canUndo}\n onClick={history.undo}\n >\n ↶\n </button>\n <button\n type=\"button\"\n className=\"be-mobile-bar-btn\"\n aria-label=\"Redo\"\n disabled={!history.canRedo}\n onClick={history.redo}\n >\n ↷\n </button>\n </>\n )}\n </>\n )}\n\n <span className=\"be-mobile-bar-spacer\" />\n {topLevelBlock && (\n <button type=\"button\" className=\"be-mobile-bar-btn\" aria-label=\"Block options\" onClick={openOptions}>\n <MoreHorizontalIcon size={18} />\n </button>\n )}\n <button type=\"button\" className=\"be-mobile-bar-btn\" aria-label=\"Dismiss keyboard\" onClick={handleDismissKeyboard}>\n <ChevronDownIcon size={18} />\n </button>\n </div>\n <MobileBlockPickerSheet isOpen={isPickerOpen} onClose={closePicker} onSelectCommand={handleSelectCommand} />\n <MobileBlockOptionsSheet\n isOpen={isOptionsOpen}\n onClose={closeOptions}\n store={store}\n blockId={topLevelBlock?.id}\n />\n </>\n );\n}\n","import { genId } from '../utils/idGen.js';\nimport { runsToHTML } from '../inline/marks.js';\nimport { domInlineToRuns } from '../inline/runOps.js';\nimport { resolveColumns } from '../blocks/table/tableColumns.js';\n\n/**\n * A second, optional, additive document format — self-contained blocks in\n * an array (`children` for nesting instead of id-references, `data`\n * holding each block's own fields) instead of the internal engine's\n * normalized `{ blocks, runs }` graph (id-referenced blocks + a separate\n * runs collection, which is what `exportDocumentJSON`/`EditorStore` use).\n * The internal shape is what it is for real reasons (per-run reactivity,\n * O(1) structural edits, real nesting) — this format exists purely to give\n * a simpler shape for storage/API/CRUD use, converting to/from the\n * internal shape at the boundary; it never changes how the editor itself\n * works.\n *\n * Rich text (`data.text`) is an HTML string produced by `runsToHTML` (the\n * same per-run serialization every block type's own `toHTML` already\n * uses) — carries marks (bold/italic/.../link) and atomic inline chips\n * (checkbox/date/select/...) inline, via the same `data-inline-type=\"...\"`\n * convention those types already use for clipboard copy/paste. Import\n * reverses this with `domInlineToRuns`, the same function clipboard paste\n * already relies on to reconstruct marks and atomic runs from HTML — nothing\n * new is invented here, both directions reuse existing, already-tested\n * machinery.\n *\n * Known, by-design limitation (same as clipboard paste today): an atomic\n * inline type's core value round-trips (checkbox's checked+label, date's\n * ISO date, select's selected value+label) but not its full `options`\n * list — that's inherent to `fromHTML`'s existing behavior, not something\n * unique to this format.\n */\n\n// Which of a block's own `props` fields are meaningful to a host reading\n// this format — everything else in `props` is either absent for these\n// types or an internal bookkeeping field (e.g. `titleRunIds`) already\n// represented some other way here (`data.text`/`children`).\nconst PROPS_ALLOWLIST = {\n heading: ['level'],\n listItem: ['ordered', 'checked', 'collapsed'],\n toggleHeading: ['level', 'collapsed'],\n code: ['language'],\n button: ['href', 'color', 'customAttrs'],\n embed: ['kind', 'src', 'name', 'alt', 'mimeType', 'align', 'width'],\n callout: ['icon'],\n};\n\n// listItem/toggleHeading: own text lives in props.titleRunIds, contentIds\n// points at nested child *blocks* (both a \"data.text\" and \"children\" type).\nconst TITLE_RUN_TYPES = new Set(['listItem', 'toggleHeading']);\n// Leaf types with no meaningful text content at all (contentIds is always empty).\nconst NO_TEXT_LEAF_TYPES = new Set(['divider', 'embed']);\n\nfunction exportBlock(store, registry, block, ctx) {\n const type = block.type;\n const data = {};\n for (const key of PROPS_ALLOWLIST[type] ?? []) {\n if (block.props?.[key] !== undefined) data[key] = block.props[key];\n }\n\n if (type === 'table') {\n const firstRow = block.contentIds[0] && store.getBlock(block.contentIds[0]);\n data.columns = resolveColumns(block, firstRow?.contentIds?.length ?? 0);\n data.rows = block.contentIds.map((rowId) => {\n const row = store.getBlock(rowId);\n return row.contentIds.map((cellId) => {\n const cell = store.getBlock(cellId);\n return runsToHTML(cell.contentIds.map((runId) => store.getRun(runId)), ctx);\n });\n });\n return { id: block.id, type, data };\n }\n\n if (TITLE_RUN_TYPES.has(type)) {\n const runIds = block.props?.titleRunIds ?? [];\n data.text = runsToHTML(runIds.map((id) => store.getRun(id)), ctx);\n } else if (registry.isLeaf(type) && !NO_TEXT_LEAF_TYPES.has(type)) {\n data.text = runsToHTML(block.contentIds.map((id) => store.getRun(id)), ctx);\n }\n\n const result = { id: block.id, type, data };\n if (!registry.isLeaf(type)) {\n result.children = block.contentIds.map((childId) => exportBlock(store, registry, store.getBlock(childId), ctx));\n }\n return result;\n}\n\n/**\n * Exports the whole document as the simple format described above.\n * Returns a JSON string (matching `exportDocumentJSON`'s own `{ pretty }`\n * convention) — pass `{ pretty: false }` for a compact single-line string.\n */\nexport function exportDocumentSimpleJSON(store, registry, inlineRegistry, { pretty = true } = {}) {\n const ctx = { store, registry, inlineRegistry };\n const root = store.getBlock(store.getRootId());\n const blocks = root.contentIds.map((id) => exportBlock(store, registry, store.getBlock(id), ctx));\n return JSON.stringify({ version: 1, blocks }, null, pretty ? 2 : 0);\n}\n\nfunction textToRuns(html, ctx) {\n const doc = new DOMParser().parseFromString(`<div>${html ?? ''}</div>`, 'text/html');\n return domInlineToRuns(doc.body.firstChild, ctx);\n}\n\nfunction importTable(simpleBlock, parentId, blocksOut, runsOut, ctx) {\n const { id = genId(), data = {} } = simpleBlock;\n const rowIds = (data.rows ?? []).map((rowCells) => {\n const rowId = genId();\n const cellIds = rowCells.map((cellHTML) => {\n const cellId = genId();\n const runs = textToRuns(cellHTML, ctx);\n runsOut.push(...runs);\n blocksOut.push({ id: cellId, type: 'tableCell', parentId: rowId, contentIds: runs.map((r) => r.id), props: {} });\n return cellId;\n });\n blocksOut.push({ id: rowId, type: 'tableRow', parentId, contentIds: cellIds, props: {} });\n return rowId;\n });\n const block = { id, type: 'table', parentId, contentIds: rowIds, props: { columns: data.columns ?? [] } };\n blocksOut.push(block);\n return block;\n}\n\nfunction importBlock(simpleBlock, parentId, registry, ctx, blocksOut, runsOut) {\n const { id = genId(), type, data = {}, children = [] } = simpleBlock;\n\n if (type === 'table') return importTable(simpleBlock, parentId, blocksOut, runsOut, ctx);\n\n const props = {};\n for (const key of PROPS_ALLOWLIST[type] ?? []) {\n if (data[key] !== undefined) props[key] = data[key];\n }\n\n const block = { id, type, parentId, contentIds: [], props };\n blocksOut.push(block);\n\n if (TITLE_RUN_TYPES.has(type)) {\n const runs = textToRuns(data.text, ctx);\n runsOut.push(...runs);\n block.props.titleRunIds = runs.map((r) => r.id);\n block.contentIds = children.map((child) => importBlock(child, id, registry, ctx, blocksOut, runsOut).id);\n } else if (registry.isLeaf(type)) {\n if (!NO_TEXT_LEAF_TYPES.has(type)) {\n const runs = textToRuns(data.text, ctx);\n runsOut.push(...runs);\n block.contentIds = runs.map((r) => r.id);\n }\n } else {\n block.contentIds = children.map((child) => importBlock(child, id, registry, ctx, blocksOut, runsOut).id);\n }\n\n return block;\n}\n\n/**\n * Reverses `exportDocumentSimpleJSON` — returns a plain `{ rootId, blocks,\n * runs }` object, the same shape `new EditorStore(doc)` already accepts\n * (this function deliberately doesn't construct a store itself, matching\n * how the rest of this library hands back plain data rather than\n * pre-wrapping it). `json` may be a JSON string or an already-parsed object.\n */\nexport function importDocumentSimpleJSON(json, registry, inlineRegistry) {\n const doc = typeof json === 'string' ? JSON.parse(json) : json;\n const ctx = { registry, inlineRegistry };\n const rootId = genId();\n const blocksOut = [];\n const runsOut = [];\n const topIds = (doc.blocks ?? []).map((b) => importBlock(b, rootId, registry, ctx, blocksOut, runsOut).id);\n blocksOut.push({ id: rootId, type: 'page', parentId: null, contentIds: topIds, props: {} });\n return { rootId, blocks: blocksOut, runs: runsOut };\n}\n","import { useCallback, useMemo, useState } from 'react';\nimport { Modal } from './Modal.jsx';\nimport { useEditorStore, useBlockRegistry, useInlineRegistry } from './EditorProvider.jsx';\nimport { exportDocumentJSON, exportDocumentHTML, exportDocumentText } from '../clipboard/exportDocument.js';\nimport { exportDocumentSimpleJSON } from '../clipboard/simpleFormat.js';\nimport { CodeIcon } from './icons.jsx';\n\nconst FORMATS = [\n { value: 'json', label: 'JSON' },\n { value: 'simpleJson', label: 'Simple JSON' },\n { value: 'html', label: 'HTML' },\n { value: 'text', label: 'Text' },\n];\n\n/**\n * Drop-in \"view source\" button + modal — mount it once anywhere under\n * <EditorProvider> to give a host app (or its own end users, if exposed)\n * a way to inspect the live document as JSON, HTML, or plain text, without\n * having to hand-roll the export/modal/copy plumbing themselves.\n *\n * These formats aren't different features — JSON/HTML/Text are the same\n * export pulled through the three existing serialization paths every\n * other document-reading feature (clipboard, in particular) already goes\n * through (see clipboard/exportDocument.js). \"Simple JSON\" is a separate,\n * optional, flatter shape (see clipboard/simpleFormat.js) — self-contained\n * blocks with `children` for nesting instead of the internal engine's own\n * id-referenced graph — meant for storage/API/CRUD use where \"JSON\" tab's\n * raw internal shape is more structure than a host actually wants to work\n * with directly. All four are just packaged behind one button so each host\n * app doesn't need to wire its own; a host that wants the raw strings\n * without any UI can call exportDocumentJSON/exportDocumentSimpleJSON/HTML/\n * Text directly instead of using this component at all.\n *\n * Recomputes the export fresh every time the modal opens (not on every\n * keystroke while it's closed) — cheap enough for real documents, and\n * guarantees what's shown always matches the live store exactly, with no\n * separate cache to keep in sync.\n */\nexport function DocumentExportButton({ label = 'View source', className = '' }) {\n const store = useEditorStore();\n const registry = useBlockRegistry();\n const inlineRegistry = useInlineRegistry();\n const [isOpen, setIsOpen] = useState(false);\n const [format, setFormat] = useState('json');\n const [copied, setCopied] = useState(false);\n\n const open = useCallback(() => {\n setCopied(false);\n setIsOpen(true);\n }, []);\n const close = useCallback(() => setIsOpen(false), []);\n\n const content = useMemo(() => {\n if (!isOpen) return '';\n if (format === 'json') return exportDocumentJSON(store);\n if (format === 'simpleJson') return exportDocumentSimpleJSON(store, registry, inlineRegistry);\n if (format === 'html') return exportDocumentHTML(store, registry, inlineRegistry);\n return exportDocumentText(store, registry, inlineRegistry);\n }, [isOpen, format, store, registry, inlineRegistry]);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(content);\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n } catch {\n // Clipboard permission denied/unavailable (e.g. insecure context) —\n // the content is still fully visible and selectable in the <pre>,\n // so this is a soft failure, not a dead end.\n }\n }, [content]);\n\n return (\n <>\n <button type=\"button\" className={`be-export-trigger ${className}`.trim()} onClick={open}>\n <CodeIcon size={14} /> {label}\n </button>\n <Modal isOpen={isOpen} onClose={close} title=\"Document source\" size=\"large\">\n <div className=\"be-export-tabs\" role=\"tablist\">\n {FORMATS.map((f) => (\n <button\n key={f.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={format === f.value}\n className={`be-export-tab${format === f.value ? ' be-export-tab-active' : ''}`}\n onClick={() => setFormat(f.value)}\n >\n {f.label}\n </button>\n ))}\n </div>\n <pre className=\"be-export-pre\">\n <code>{content}</code>\n </pre>\n <div className=\"be-modal-actions\">\n <button type=\"button\" className=\"be-modal-cancel\" onClick={close}>\n Close\n </button>\n <button type=\"button\" className=\"be-modal-save\" onClick={handleCopy}>\n {copied ? 'Copied!' : 'Copy'}\n </button>\n </div>\n </Modal>\n </>\n );\n}\n","import { useCallback } from 'react';\r\nimport { useRun } from '../../react/useBlock.js';\r\nimport { useEditorStore } from '../../react/EditorProvider.jsx';\r\nimport { updateRun } from '../../store/operations.js';\r\nimport { Select } from '../../react/Select.jsx';\r\n\r\n/**\r\n * The atomic chip for one instance of a named custom select field type\r\n * (see createSelectFieldType) — same mounting contract as SelectInlineNode\r\n * (host+portal, contentEditable=false, stopPropagation on mousedown/\r\n * keydown so the surrounding paragraph never steals focus/keys from it).\r\n *\r\n * Unlike SelectInlineNode, `options` here comes from the field type's OWN\r\n * config (closed over by the factory), not from `run.data` — every chip of\r\n * a given field type shares the same options source, matching how a\r\n * table's select column works (one shared list, not one per cell). Only\r\n * the resolved selection is ever written back to the run.\r\n */\r\nexport function CustomSelectInlineNode({ id, label, placeholder, variant, options, onManage, mention = false }) {\r\n const store = useEditorStore();\r\n const run = useRun(id);\r\n\r\n const handleChange = useCallback(\r\n (selectedValue, option) => {\r\n store.applyOperation(\r\n updateRun(id, {\r\n data: { selectedValue, selectedLabel: option?.label ?? '', selectedColor: option?.color },\r\n }),\r\n );\r\n },\r\n [store, id],\r\n );\r\n\r\n if (!run) return null;\r\n const { selectedValue = '', selectedLabel = '', selectedColor } = run.data ?? {};\r\n\r\n return (\r\n <span\r\n className=\"be-inline-select\"\r\n onMouseDown={(event) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }}\r\n onKeyDown={(event) => event.stopPropagation()}\r\n >\r\n <Select\r\n value={selectedValue}\r\n selectedLabel={selectedLabel}\r\n selectedColor={selectedColor}\r\n options={options}\r\n onChange={handleChange}\r\n placeholder={placeholder}\r\n variant={variant}\r\n ariaLabel={label}\r\n onManageOptions={onManage}\r\n mention={mention}\r\n />\r\n </span>\r\n );\r\n}\r\n","import { CustomSelectInlineNode } from './CustomSelectInlineNode.jsx';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { insertInlineRunAtCursor } from '../shared/insertInlineRun.js';\r\nimport { SelectIcon } from '../../react/icons.jsx';\r\n\r\nfunction escapeHTML(str) {\r\n return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\r\n}\r\n\r\nfunction escapeAttr(str) {\r\n return escapeHTML(str).replace(/\"/g, '&quot;');\r\n}\r\n\r\n/**\r\n * Builds a full InlineRegistry entry for one named \"select field type\" —\r\n * the mechanism behind BOTH halves of the custom-field-type system:\r\n *\r\n * - a host app calling this directly at setup time with its own `options`\r\n * (a plain array, OR a `(query) => Option[] | Promise<Option[]>`\r\n * resolver for DB/API-backed search — see Select.jsx) — never persisted,\r\n * the host re-registers it every load, same as registering any other\r\n * built-in inline type;\r\n * - the in-editor \"new field type\" UI (see FieldTypeEditorModal), which\r\n * can only ever produce STATIC options (there's no way to author a\r\n * fetch function through a form) and whose definition IS persisted via\r\n * the store's fieldTypes collection — see registerStoredFieldTypes,\r\n * which calls this same factory to re-register each one after load.\r\n *\r\n * Only the resolved `{ value, label }` of whatever got picked is ever\r\n * stored on the run (`data.selectedValue`/`data.selectedLabel`, plus\r\n * `data.selectedColor` for the tag variant) — never the live options list\r\n * itself, so a dynamic (DB-backed) type's run never embeds a stale\r\n * snapshot of someone else's database. This is exactly tableSelect's own\r\n * denormalized-label convention, applied here per-field-type instead of\r\n * per-table-column.\r\n *\r\n * `onManage`, if given, is threaded down to every chip as a \"Manage\r\n * options…\" footer entry in its popover (see Select's onManageOptions) —\r\n * registerStoredFieldTypes passes one that opens FieldTypeEditorModal\r\n * pre-filled for this type's stored id, so any chip can jump straight to\r\n * editing/deleting the type it belongs to. Not something a host app\r\n * calling this directly typically needs, since its own config lives in\r\n * code, not the store.\r\n *\r\n * `triggers` (default `['slash']`) decides which trigger-character menu(s)\r\n * this type's command shows up under — `'slash'` for useSlashMenuTrigger's\r\n * \"/\" menu, `'at'` for useAtMenuTrigger's \"@\" menu, or both. The command\r\n * object itself (label/icon/keywords/run) is identical either way — only\r\n * which InlineRegistry list (slashCommand vs atCommand) it's assigned to\r\n * differs — so opting a type into \"@\" is a one-line config change, not a\r\n * separate implementation. Left slash-only by default since not every\r\n * field type reads naturally after \"@\" (an \"Assignee\" or \"Reviewer\" type\r\n * does; a generic \"Priority\"/\"Status\" dropdown usually doesn't).\r\n */\r\nexport function createSelectFieldType({\r\n type,\r\n label,\r\n placeholder = 'Select…',\r\n variant = 'default',\r\n icon,\r\n options,\r\n onManage,\r\n triggers = ['slash'],\r\n // Defaults to true for an @-reachable type (Assignee, Reviewer, ...): a\r\n // picked chip renders as \"@Name\" in a fixed accent color rather than each\r\n // option's own tag color, matching how @mentions read everywhere else —\r\n // a consistent mention style, not a per-person palette. Pass\r\n // `mention: false` to opt an @-triggered type out of this\r\n // (e.g. it's reachable via \"@\" but isn't really a \"who\" mention).\r\n mention = triggers.includes('at'),\r\n}) {\r\n function toHTML(run) {\r\n const label = run.data?.selectedLabel || '';\r\n const text = mention && label ? `@${label}` : label;\r\n return `<span data-inline-type=\"${escapeAttr(type)}\" data-selected-value=\"${escapeAttr(run.data?.selectedValue ?? '')}\">${escapeHTML(text)}</span>`;\r\n }\r\n\r\n function toPlainText(run) {\r\n const label = run.data?.selectedLabel ?? '';\r\n return mention && label ? `@${label}` : label;\r\n }\r\n\r\n function fromHTML(node) {\r\n if (node.getAttribute?.('data-inline-type') !== type) return null;\r\n const text = node.textContent ?? '';\r\n // toHTML prepends \"@\" for a mention type — strip it back off so\r\n // selectedLabel stays the bare name; otherwise re-rendering the pasted\r\n // chip would prepend a second \"@\" on top of the one already baked into\r\n // the round-tripped text.\r\n const selectedLabel = mention && text.startsWith('@') ? text.slice(1) : text;\r\n return {\r\n id: genId(),\r\n type,\r\n value: '',\r\n marks: {},\r\n data: {\r\n selectedValue: node.getAttribute('data-selected-value') ?? '',\r\n selectedLabel,\r\n },\r\n };\r\n }\r\n\r\n function Component({ id }) {\r\n return (\r\n <CustomSelectInlineNode\r\n id={id}\r\n label={label}\r\n placeholder={placeholder}\r\n variant={variant}\r\n options={options}\r\n onManage={onManage}\r\n mention={mention}\r\n />\r\n );\r\n }\r\n\r\n const command = {\r\n label,\r\n // Falls back to the same icon the built-in generic `select` inline\r\n // type's own slash command uses (see inlineTypes/select/index.js) —\r\n // every custom field type (host-defined or created in-editor via\r\n // FieldTypeEditorModal, which has no way to let a user pick an icon at\r\n // all) gets a consistent, non-blank glyph in the \"/\"/\"@\" menu instead\r\n // of silently rendering with no icon at all next to every other entry\r\n // that has one. A host can still override it by passing its own\r\n // `icon` in the config, same as before.\r\n icon: icon ?? SelectIcon,\r\n keywords: [label.toLowerCase(), 'select', 'field'],\r\n run: (store, { blockId, runId, sliceStart, sliceEnd }) =>\r\n insertInlineRunAtCursor(store, { blockId, runId, sliceStart, sliceEnd }, () => ({\r\n id: genId(),\r\n type,\r\n value: '',\r\n marks: {},\r\n data: { selectedValue: '', selectedLabel: '', selectedColor: undefined },\r\n })),\r\n };\r\n\r\n return {\r\n component: Component,\r\n isAtomic: true,\r\n toHTML,\r\n toPlainText,\r\n fromHTML,\r\n slashCommand: triggers.includes('slash') ? command : undefined,\r\n atCommand: triggers.includes('at') ? command : undefined,\r\n };\r\n}\r\n","import { createSelectFieldType } from './createSelectFieldType.jsx';\r\n\r\n/**\r\n * Re-registers every persisted, user-created field type (store.getFieldTypes())\r\n * into the given inline registry — the rehydration step that makes a\r\n * previously-created custom select type usable again after a fresh page\r\n * load/store construction, without the host app needing to know what\r\n * types exist ahead of time (unlike code-defined types, which the host\r\n * itself registers via createSelectFieldType at setup time).\r\n *\r\n * `onManage(id)`, if given, becomes each type's \"Manage options…\" chip\r\n * affordance (see createSelectFieldType's own `onManage` param) — pass\r\n * `useFieldTypeEditor().openEdit` from React (see useRegisterFieldTypes,\r\n * which wraps this reactively). Safe to call directly, outside React too\r\n * (e.g. right after `new EditorStore(doc)`, or in tests) when no \"manage\"\r\n * UI is needed.\r\n */\r\nexport function registerStoredFieldTypes(store, inlineRegistry, { onManage } = {}) {\r\n for (const fieldType of store.getFieldTypes()) {\r\n inlineRegistry.register(\r\n fieldType.id,\r\n createSelectFieldType({\r\n type: fieldType.id,\r\n label: fieldType.label,\r\n placeholder: fieldType.placeholder,\r\n variant: fieldType.variant,\r\n options: fieldType.options ?? [],\r\n onManage: onManage ? () => onManage(fieldType.id) : undefined,\r\n }),\r\n );\r\n }\r\n}\r\n","import { useEffect, useRef } from 'react';\r\nimport { useEditorStore, useInlineRegistry, useFieldTypeEditor } from '../../react/EditorProvider.jsx';\r\nimport { useFieldTypes } from '../../react/useFieldTypes.js';\r\nimport { registerStoredFieldTypes } from './registerStoredFieldTypes.js';\r\n\r\n/**\r\n * Keeps the inline registry in sync with the store's persisted field types\r\n * for the lifetime of a mounted editor: re-registers on every add/rename/\r\n * options-edit (registerStoredFieldTypes overwrites in place, cheap), and\r\n * unregisters any id that's disappeared from the list (a deleted type) so\r\n * its InlineRegistry entry doesn't linger with a \"Manage options…\" pointing\r\n * at a record that no longer exists. Each chip's onManage opens\r\n * FieldTypeEditorModal via useFieldTypeEditor().openEdit.\r\n *\r\n * Called once by FieldTypeEditorModal itself, so mounting that single\r\n * component is enough to get both the create/edit UI and this rehydration/\r\n * live-sync behavior — a host app never needs to call this directly.\r\n */\r\nexport function useRegisterFieldTypes() {\r\n const store = useEditorStore();\r\n const inlineRegistry = useInlineRegistry();\r\n const fieldTypes = useFieldTypes();\r\n const { openEdit } = useFieldTypeEditor();\r\n const previousIdsRef = useRef([]);\r\n\r\n useEffect(() => {\r\n if (!inlineRegistry) return;\r\n const currentIds = new Set(fieldTypes.map((f) => f.id));\r\n for (const id of previousIdsRef.current) {\r\n if (!currentIds.has(id)) inlineRegistry.unregister(id);\r\n }\r\n registerStoredFieldTypes(store, inlineRegistry, { onManage: openEdit });\r\n previousIdsRef.current = [...currentIds];\r\n }, [store, inlineRegistry, fieldTypes, openEdit]);\r\n}\r\n","import { useCallback, useEffect, useState } from 'react';\r\nimport { Modal } from '../../react/Modal.jsx';\r\nimport { useEditorStore, useFieldTypeEditor } from '../../react/EditorProvider.jsx';\r\nimport { addFieldType, updateFieldType, removeFieldType } from '../../store/operations.js';\r\nimport { genId } from '../../utils/idGen.js';\r\nimport { XIcon } from '../../react/icons.jsx';\r\nimport { pickTagColor } from '../../blocks/table/tagColors.js';\r\nimport { useRegisterFieldTypes } from './useRegisterFieldTypes.js';\r\n\r\n/**\r\n * Create/edit/delete UI for a user-created custom select field type — the\r\n * in-editor counterpart to a host app's code-only createSelectFieldType\r\n * calls. Mount this once anywhere under EditorProvider (it reads\r\n * useFieldTypeEditor() itself, so no props are required); wire a \"+ New\r\n * field type\" button to `useFieldTypeEditor().openCreate()`, and each\r\n * type's own chips reach the edit flow via their popover's \"Manage\r\n * options…\" entry (see createSelectFieldType's `onManage`).\r\n *\r\n * Reuses the same add/rename/remove-option-row shape as the table\r\n * column's SelectOptionsManager, plus a name field and Save/Cancel/Delete\r\n * — closer to ButtonEditModal's \"load a draft, commit on Save\" flow than\r\n * SelectOptionsManager's instant-write one, since creating a brand-new\r\n * type has no store record to write into until Save.\r\n *\r\n * Also owns useRegisterFieldTypes() — mounting this component is what\r\n * keeps the inline registry in sync with the store's fieldTypes list for\r\n * the whole session (rehydration + live add/edit/delete), not just what\r\n * renders the dialog.\r\n */\r\nexport function FieldTypeEditorModal() {\r\n useRegisterFieldTypes();\r\n const store = useEditorStore();\r\n const { target, close } = useFieldTypeEditor();\r\n const isOpen = target !== null;\r\n const isEditing = isOpen && target !== 'new';\r\n\r\n const [name, setName] = useState('');\r\n const [options, setOptions] = useState([]);\r\n const [draft, setDraft] = useState('');\r\n\r\n useEffect(() => {\r\n if (!isOpen) return;\r\n if (isEditing) {\r\n const existing = store.getFieldType(target);\r\n setName(existing?.label ?? '');\r\n setOptions(existing?.options ?? []);\r\n } else {\r\n setName('');\r\n setOptions([]);\r\n }\r\n setDraft('');\r\n }, [isOpen, isEditing, target, store]);\r\n\r\n const handleRename = useCallback((value, label) => {\r\n setOptions((rows) => rows.map((o) => (o.value === value ? { ...o, label } : o)));\r\n }, []);\r\n\r\n const handleRemoveOption = useCallback((value) => {\r\n setOptions((rows) => rows.filter((o) => o.value !== value));\r\n }, []);\r\n\r\n const handleAddOption = useCallback(() => {\r\n const label = draft.trim();\r\n setDraft('');\r\n if (!label) return;\r\n setOptions((rows) => [...rows, { value: genId(), label, color: pickTagColor(rows.length) }]);\r\n }, [draft]);\r\n\r\n const handleSave = useCallback(() => {\r\n const label = name.trim();\r\n if (!label) return;\r\n if (isEditing) {\r\n store.applyOperation(updateFieldType(target, { label, options }));\r\n } else {\r\n store.applyOperation(\r\n addFieldType({ id: genId(), label, placeholder: 'Select…', variant: 'tag', options }),\r\n );\r\n }\r\n close();\r\n }, [store, isEditing, target, name, options, close]);\r\n\r\n const handleDelete = useCallback(() => {\r\n if (isEditing) store.applyOperation(removeFieldType(target));\r\n close();\r\n }, [store, isEditing, target, close]);\r\n\r\n return (\r\n <Modal isOpen={isOpen} onClose={close} title={isEditing ? 'Edit field type' : 'New field type'}>\r\n <label className=\"be-modal-field\">\r\n <span>Name</span>\r\n <input\r\n type=\"text\"\r\n value={name}\r\n onChange={(event) => setName(event.target.value)}\r\n placeholder=\"e.g. Priority, Status…\"\r\n autoFocus\r\n />\r\n </label>\r\n\r\n <div className=\"be-modal-field\">\r\n <span>Options</span>\r\n {options.map((option, i) => (\r\n <div key={option.value} className=\"be-table-header-menu-option-row\">\r\n <span\r\n className=\"be-table-header-menu-option-swatch\"\r\n style={{ background: (option.color ?? pickTagColor(i)).bg }}\r\n aria-hidden=\"true\"\r\n />\r\n <input\r\n className=\"be-table-header-menu-option-input\"\r\n value={option.label}\r\n onChange={(event) => handleRename(option.value, event.target.value)}\r\n aria-label={`Rename option ${option.label}`}\r\n />\r\n <button\r\n type=\"button\"\r\n className=\"be-table-header-menu-option-remove\"\r\n onClick={() => handleRemoveOption(option.value)}\r\n aria-label={`Remove option ${option.label}`}\r\n >\r\n <XIcon size={14} />\r\n </button>\r\n </div>\r\n ))}\r\n <div className=\"be-table-header-menu-option-row\">\r\n <input\r\n className=\"be-table-header-menu-option-input\"\r\n value={draft}\r\n onChange={(event) => setDraft(event.target.value)}\r\n placeholder=\"New option…\"\r\n onKeyDown={(event) => {\r\n if (event.key === 'Enter') {\r\n event.preventDefault();\r\n handleAddOption();\r\n }\r\n }}\r\n />\r\n <button type=\"button\" className=\"be-table-header-menu-option-add\" onClick={handleAddOption} aria-label=\"Add option\">\r\n +\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div className=\"be-modal-actions\">\r\n {isEditing && (\r\n <button type=\"button\" className=\"be-modal-delete\" onClick={handleDelete}>\r\n Delete field type\r\n </button>\r\n )}\r\n <button type=\"button\" className=\"be-modal-cancel\" onClick={close}>\r\n Cancel\r\n </button>\r\n <button type=\"button\" className=\"be-modal-save\" onClick={handleSave}>\r\n Save\r\n </button>\r\n </div>\r\n </Modal>\r\n );\r\n}\r\n"],"names":["OP","insertBlock","block","parentId","index","subtree","removeBlock","id","moveBlock","toParentId","toIndex","updateBlockProps","patch","changeBlockType","blockType","props","updateRun","editRunChars","tombstoneIds","restoreIds","previousValue","setBlockContentIds","blockId","contentIds","replaceRunSpan","oldRunIds","newRuns","setBlockRuns","runs","addFieldType","fieldType","updateFieldType","removeFieldType","addCommentThread","thread","removeCommentThread","commentId","addCommentReply","message","removeCommentReply","messageId","resolveComment","resolved","HLC","peerId","now","remote","maxWall","a","b","genPeerId","ListCrdtState","ids","state","prev","slot","afterId","clock","oldOriginId","other","remoteSlots","local","count","beforeClock","removed","age","childrenByOrigin","bucket","result","stack","children","i","FieldClockRegistry","field","remoteClock","current","diffCodePoints","oldValue","newValue","oldChars","newChars","start","maxStart","oldEnd","newEnd","genId","FIELD_TYPES_KEY","COMMENTS_KEY","EditorStore","doc","r","f","c","order","runId","run","chars","ch","charId","value","currentIds","deletedCharIds","insertedChars","charEdit","d","listener","set","touchedIds","rootId","blocks","walk","childId","_a","op","patchKeys","previousPatch","clocks","key","previousType","previousProps","parent","currentArray","target","deleteClock","fromParentId","fromOrder","fromIndex","toOrder","toArray","ts","touched","previousContentIds","inContentIds","sourceArray","startIndex","removedRuns","newArray","usesTitleRunIds","previousRunIds","previousRuns","newRunIds","existing","removedMessage","m","previousResolved","ops","envelope","hadSlot","_b","maxAgeMs","threshold","IDLE_MS","diffValueOffsets","endA","endB","previousValueFromInverse","inverse","computeEntrySelection","entry","firstOp","lastOp","oldestInverse","beforeOffset","afterOffset","extractAffectedBlockIds","collect","History","store","idleMs","trackChanges","maxChangeLogSize","defaultActorId","meta","hasPatch","canUndo","canRedo","options","actorId","timestamp","inverses","batchKey","withinIdle","selection","DEFAULT_INTERVAL_MS","DEFAULT_MAX_AGE_MS","createPeriodicTombstoneGC","intervalMs","onPrune","onError","timer","err","MESSAGE_TYPE","encodeMessage","decodeMessage","raw","helloMessage","opMessage","syncRequestMessage","syncResponseMessage","presenceMessage","data","SYNC_LABEL","DEFAULT_RTC_CONFIG","MAX_CHUNK_PAYLOAD","BUFFERED_AMOUNT_HIGH_WATERMARK","BUFFERED_AMOUNT_LOW_WATERMARK","genMessageId","PeerConnection","signaling","remotePeerId","initiator","rtcConfig","event","offer","fromPeerId","answer","channel","cb","marker","rest","firstColon","secondColon","thirdColon","total","piece","buffer","full","frame","resolve","handler","DEFAULT_PRESENCE_THROTTLE_MS","CollabSession","history","presenceThrottleMs","originalApplyOperation","originals","methodName","original","args","envelopes","peer","snapshot","createWebSocketSignaling","url","roomId","WebSocketImpl","messageHandlers","peerJoinedHandlers","peerLeftHandlers","pendingSends","connectUrl","socket","toPeerId","payload","sendSignal","otherId","DB_NAME","STORE_NAME","TEMPLATES_STORE_NAME","VERSIONS_STORE_NAME","DB_VERSION","dbPromise","openDatabase","reject","request","savePersistedDocument","docId","db","tx","loadPersistedDocument","deletePersistedDocument","listPersistedDocumentIds","saveTemplate","template","loadTemplate","deleteTemplate","listTemplates","saveDocumentVersion","version","loadDocumentVersion","deleteDocumentVersion","listDocumentVersions","all","v","DEFAULT_DEBOUNCE_MS","createAutoPersistence","debounceMs","saveNow","flush","unsubscribe","stop","serializeBlockRange","registry","blockIds","inlineRegistry","ctx","serializeHTML","captureSubtree","html","ordered","itemsHTML","j","candidate","tag","linesHTML","remapSubtreeIds","idMap","remap","newBlocks","newRootId","applyOps","captureBlockTemplate","insertBlockTemplate","nextIndex","root","subtreeBlocks","applyDocumentTemplate","rawStore","registerBlockTemplates","templates","sliceStart","sliceEnd","useTemplates","scope","setTemplates","useState","isLoaded","setIsLoaded","refresh","useCallback","t","useEffect","cancelled","TemplatePicker","onSelect","emptyLabel","jsx","jsxs","exportDocumentJSON","pretty","exportDocumentHTML","exportDocumentText","DEFAULT_IDLE_MS","DEFAULT_MAX_VERSIONS","createAutoVersionHistory","maxVersions","onSnapshot","idleTimer","windowStart","hasPendingActivity","clearIdleTimer","finalizeWindow","log","entries","e","authorIds","authorId","excess","diffWords","oldText","newText","oldTokens","tokenize","newTokens","n","dp","segments","push","type","text","last","ESCAPE_MAP","escapeHtml","extractTextBlocks","blockById","runById","textFromRunIds","titleRunIds","cid","EMPTY_DOC","diffDocumentsHTML","prevDoc","nextDoc","prevBlocks","nextBlocks","prevById","nextIds","parts","prevBlock","seg","escaped","useDocumentVersions","versions","setVersions","defaultThemeCSS","STYLE_TAG_ID","injectDefaultStyles","style","EditorContext","createContext","EditorProvider","className","theme","getBlockClassName","commentAuthorId","isWholeDocumentSelected","setIsWholeDocumentSelected","hoveredCommentId","setHoveredCommentId","selectedBlockRange","setSelectedBlockRange","isPreviewMode","setIsPreviewMode","fieldTypeEditorTarget","setFieldTypeEditorTarget","openCreateFieldType","openEditFieldType","closeFieldTypeEditor","selectedBlockIdRef","useRef","getSelectedBlockId","setSelectedBlockId","prevId","useMemo","content","useEditorContext","useContext","useEditorStore","useBlockRegistry","useInlineRegistry","useWholeDocumentSelection","useBlockRangeSelection","useSelectedBlock","usePreviewMode","useBlockClassName","baseClassName","extra","useCommentAuthorId","useHoveredComment","useFieldTypeEditor","AVATAR_COLORS","getAvatarColor","hash","str","getInitials","MINUTE_MS","HOUR_MS","DAY_MS","formatRelativeTime","diff","h","CommentAvatar","size","Icon","strokeWidth","ChevronRightIcon","ChevronDownIcon","XIcon","MoreHorizontalIcon","PaperclipIcon","PlusIcon","BoldIcon","ItalicIcon","UnderlineIcon","PencilIcon","ScribbleIcon","LinkIcon","CommentIcon","ClockHistoryIcon","RestoreIcon","CheckIcon","SendIcon","StrikethroughIcon","AlignLeftIcon","AlignCenterIcon","AlignRightIcon","GripVerticalIcon","cy","cx","TrashIcon","CopyIcon","ArrowUpIcon","ArrowDownIcon","SquareIcon","CircleIcon","ArrowDiagonalIcon","DiamondIcon","TriangleIcon","StarIcon","CursorIcon","EraserIcon","DownloadIcon","MagnetIcon","ScissorsIcon","TextIcon","HeadingIcon","level","Heading1Icon","Heading2Icon","Heading3Icon","QuoteIcon","CodeIcon","DividerIcon","CalloutIcon","ButtonIcon","TableIcon","ColumnsIcon","BulletedListIcon","NumberedListIcon","CheckboxIcon","DateIcon","SelectIcon","ImageIcon","VideoIcon","EyeIcon","EyeOffIcon","AudioIcon","MicIcon","formatDayLabel","startOfDay","date","diffDays","VersionHistory","isOpen","setIsOpen","selectedId","setSelectedId","viewMode","setViewMode","drawerRef","autoHistory","close","handleKeyDown","selectedIndex","selected","previousVersion","previewHtml","previewStore","diffHtml","handleRestore","groups","label","group","Fragment","createPortal","getBlockRunIds","appendCommentMark","marks","removeCommentMark","next","remaining","appendCommentToSingleRunOp","from","to","nextMarks","before","middle","after","addCommentMarkOverRange","startRunId","startOffset","endRunId","endOffset","runIds","endIndex","fromOffset","toOffset","rangeRunIds","rangeRuns","isFirst","isLast","removeCommentMarkEverywhere","addComment","range","markOp","addCommentThreadOp","replyToComment","addCommentReplyOp","resolveCommentOp","deleteComment","markRemovalOps","removeCommentThreadOp","useComments","subscribe","onStoreChange","getSnapshot","useSyncExternalStore","CommentComposer","placeholder","autoFocus","onSubmit","onCancel","setText","textareaRef","trimmed","resizeToContent","el","handleChange","handleSubmit","CommentMessageRow","CommentThreadCard","onJumpToText","isReplying","setIsReplying","rootMessage","replies","handleReplySubmit","findAnchorEl","_c","scrollToComment","CommentsPanel","comments","listRef","positions","setPositions","sorted","useLayoutEffect","recompute","list","listTop","cursor","natural","top","totalHeight","max","BlockRegistry","commands","createBlockRegistry","InlineRegistry","createInlineRegistry","useBlock","useRun","EMPTY_RUN_PLACEHOLDER","ZERO_WIDTH_SPACE_RE","stripEmptyRunPlaceholder","readRunText","node","reconcileDomToRuns","containerEl","currentRuns","byId","seen","nextRuns","sameIdentityAndOrder","changed","isRunBlank","isRunsEmpty","isContentlessBlock","hasRuns","hasTitleRuns","setCaretAtOffsetNow","offset","textNode","clamped","focusRunAt","atStart","focusRunEnd","focusRunStart","focusRunAtOffset","setCaretSync","FOCUSABLE_SELECTOR","Modal","onClose","title","variant","panelRef","previouslyFocusedRef","panel","isSheet","LinkEditModal","initialHref","initialTarget","hasExistingLink","onSave","onRemove","href","setHref","setTarget","trimmedHref","MARGIN","clampLeftToViewport","left","width","maxLeft","clampTopToViewport","height","maxTop","useAutoAdjustedPosition","menuRef","position","setPosition","rect","clampedLeft","clampedTop","LinkHoverCard","containerRef","hovered","setHovered","isModalOpen","setIsModalOpen","hideTimerRef","cardRef","clearHideTimer","scheduleHide","container","handleMouseOver","runEl","handleMouseOut","openModal","closeModal","saveLink","removeLink","link","isCardOpen","CommentPopoverHeader","CommentPopover","pinned","setPinned","popoverRef","findCommentRun","commentIds","found","handleClick","handlePointerDown","closePopover","threads","syncEmptyAttr","wrapper","marksToStyle","setHostText","host","displayValue","onlyChild","TextRunSpan","onValueSynced","_d","_e","findAdjacentAtomicRunId","getRun","backward","anchorNode","anchorOffset","neighborAtomicId","caretRunId","idx","neighborId","neighborRun","child","findWhollySelectedAtomicRunId","resolveRangeBoundary","childIndex","charOffset","computeRunsAfterRangeDeletion","end","touchesAtomic","insertionIndex","beforeStart","afterEnd","isStartChild","isEndChild","survivor","prefix","suffix","isCaretAtContainerStart","firstChild","probe","maxStartOffset","isCaretAtContainerEnd","lastChild","textLength","findAdjacentContentlessSiblingId","direction","adjacentIndex","adjacentId","RunNode","Component","getOrCreateHost","hostsMap","EditableBlockContent","dir","onEnter","onBackspaceAtStart","onDeleteAtEnd","onArrowUp","onArrowDown","onTab","onShiftTab","onAutoformat","isComposingRef","hostsRef","liveIds","previous","expectedNext","handleInput","onlyValueChanges","syncEmptyFromStore","handleCompositionStart","handleCompositionEnd","removeRun","selectOrDeleteContentlessNeighbor","handleBeforeInput","inputType","isDelete","isReplaceTyped","targetRanges","focusRunId","focusAtStart","typedRun","finalRuns","landingRunId","wholeId","atomicId","adjacentSiblingId","resolveAdjacentFocusTarget","currentId","resolveBlockLastRun","resolveBlockFirstRun","focusAdjacentBlock","targetRunId","firstId","focusBlockStart","lastId","focusBlockEnd","resolveRunSelection","blockEl","rawText","resolveContainerLevelSelection","atEnd","resolveRunAndOffset","containerLevel","resolveCollapsedCaret","resolveMultiRunSelection","anchor","focus","resolveCrossBlockSelection","startBlock","i1","i2","insertSiblingAfter","currentBlockId","factory","insertSiblingAfterAndFocus","newBlockId","insertFirstChildAndFocus","parentBlockId","splitRunsAtCaret","caretOffset","caretRun","leftValue","rightValue","leftRuns","rightRuns","insertSiblingSplitAtCaretAndFocus","currentRunIds","splitAndInsertAtCaret","insertFirstChildSplitAtCaretAndFocus","insertParentId","insertIndex","fallback","caret","split","survivingLeftRuns","getOwnRunIds","hasNestedChildren","replaceBlockInPlace","trimSlashQueryAndInsertAfter","ownRunIds","createTextLeafBlock","initialRuns","ensureRootNonEmpty","UNWRAP_WHEN_SOLE_CHILD_EMPTIED","MERGEABLE_TEXT_TYPES","canMergeTypes","prevType","mergeWithPreviousOrDelete","isEmpty","isBlankRun","unwrapEmptyContainer","fallbackBlock","mergedContentIds","grandParent","nextId","fallbackId","focusAfterMerge","focusBlockId","lastRunId","resolveBlockDir","convertBlockType","targetUsesTitleRunIds","sourceUsesTitleRunIds","sourceHasChildren","targetCanHoldChildren","keepChildren","RULES","applyMarkdownShortcut","rule","match","strippedValue","EXITABLE_PARENT_TYPES","ParagraphBlock","handleEnter","isLastChild","handleBackspaceAtStart","isSoleChild","lastTitleRunId","handleArrowUp","handleArrowDown","handleAutoformat","escapeHTML","escapeAttr","runToHTML","targetAttrs","runsToHTML","runToPlainText","TAG_TO_MARK","domInlineToRuns","activeMarks","markName","toHTML","toPlainText","fromHTML","paragraphBlockType","HeadingBlock","Tag","HEADING_ICONS","TAG_TO_LEVEL","headingBlockType","EMPTY_CONTENT_IDS","useBlockChildren","BlockErrorBoundary","__publicField","error","info","s","BlockRenderer","memo","useOutsideClickAndEscape","refs","refList","ref","useMenuKeyboardNav","triggerRef","wasOpenRef","didFocusRef","menu","items","focusItem","currentIndex","LIVE_REGION_ID","getOrCreateLiveRegion","region","announce","DEFAULT_CALLOUT_ICON","DEFAULT_CALLOUT_COLOR","createCalloutBlock","icon","color","calloutId","paragraphBlock","TEXT_FAMILY_TARGETS","TEXT_FAMILY_TYPES","isTurnIntoEligible","turnBlockInto","convertOps","TurnIntoSubmenu","menuClassName","itemClassName","setRect","setMenuRef","open","handleSelect","handleTriggerKeyDown","handleSubmenuKeyDown","duplicateBlock","moveBlockUp","moveBlockDown","deleteBlockAndFocusSibling","targetId","BlockGutterRow","isMenuOpen","setIsMenuOpen","turnIntoMenuRef","outsideRefs","isRangeSelected","closeMenu","openMenu","handleAdd","handleDuplicate","handleMoveUp","handleMoveDown","handleDelete","isHidden","handleToggleHidden","isRtl","handleToggleDir","handleTurnInto","BlockChildren","isTopLevel","visibleIds","ALPHA_START","ROMAN_TABLE","toAlpha","out","toRoman","symbol","isPlainMarkerItem","listItemDepth","depth","orderedItemIndex","siblingIds","pos","sibling","orderedMarkerText","BULLET_GLYPHS","bulletMarkerText","createListItemBlock","checked","collapsed","allRuns","childBlock","childRuns","indentListItem","outdentListItem","currentParent","grandParentId","parentIndex","isBlankTitle","isBodyEmpty","childIds","mergeListItemOrOutdent","empty","mergedTitleRunIds","exitListItemToParagraph","ListItemBlock","isTodo","isToggle","handleTab","handleShiftTab","toggleChecked","toggleCollapsed","titleText","titleHTML","childrenHTML","nested","fromLiNode","liNode","inlineNodes","nestedListNodes","titleRuns","childBlocks","listNode","li","listItemBlockType","COLUMN_TYPES","DEFAULT_COLUMN_TYPE","DEFAULT_COLUMN_WIDTH","MIN_COLUMN_WIDTH","defaultColumnLabel","createDefaultColumns","_","resolveColumns","table","colCount","columns","blankRunForType","createCellForColumn","column","convertRunToType","newType","parsed","isoDate","removeTableAndFocusSibling","tableIndex","fallbackParagraphId","parentAfter","siblingId","insertRowAfter","rowId","row","rowIndex","newRowId","cellBlocks","cell","newRow","deleteRow","updatedTable","targetRowIndex","targetRowId","insertColumnAfter","tableId","colIndex","currentColumns","newColumn","firstNewCellId","nextColumns","deleteColumn","firstRow","updatedFirstRow","targetColIndex","targetCellId","setColumnWidth","renameColumn","cellRunsForColumn","cellId","runPlainText","buildSelectColumnConversion","cellRuns","optionByLabel","option","setColumnType","oldRun","newRun","setColumnOptions","optionById","o","selectedValue","nextSelectedValue","nextSelectedLabel","useHorizontalAutoAdjustedLeft","rawLeft","setLeft","useAutoAdjustedCenteredLeft","rawCenterLeft","centerLeft","setCenterLeft","half","nextCenter","useAutoAdjustedRightLeft","rawRightEdgeLeft","rightLeft","setRightLeft","nextRightLeft","computeInset","vv","inset","useVirtualKeyboardInset","setInset","ESTIMATED_POPOVER_HEIGHT","matchesQuery","query","Select","onChange","ariaLabel","selectedLabel","selectedColor","onManageOptions","manageOptionsLabel","mention","setQuery","activeIndex","setActiveIndex","keyboardInset","asyncOptions","setAsyncOptions","isLoading","setIsLoading","loadError","setLoadError","rootRef","buttonRef","inputRef","activeOptionRef","isTag","isDynamic","staticSelected","filtered","adjustedLeft","selectOption","handleSearchKeyDown","TAG_COLORS","pickTagColor","TYPE_LABELS","TYPE_OPTIONS","MAX_COLUMN_WIDTH_HINT","SelectOptionsManager","draft","setDraft","handleRename","optionValue","handleRemove","ColumnHeaderCell","dragWidth","setDragWidth","thRef","handleLabelChange","handleInsertLeft","handleInsertRight","handleTypeChange","handleResizeStart","col","startWidth","startX","computeWidth","moveEvent","handleMouseMove","handleMouseUp","upEvent","TableHeaderRow","TableBlock","handleAddRow","lastRowId","TableRowBlock","handleDeleteRow","locateCell","resolveAdjacentCellTarget","delta","nextColIndex","nextRowIndex","targetRow","exitTableForward","moveToAdjacentCell","targetCell","TableCellBlock","createRow","createTableBlock","rows","cols","rowIds","cellToHTML","cellToPlainText","cellFromHTML","rowToHTML","cellBlock","rowToPlainText","rowFromHTML","cellNodes","cellNode","tableToHTML","theadHTML","rowsHTML","rowBlock","tableToPlainText","tableFromHTML","theadRow","bodyRowNodes","tr","rowNode","headerCells","tableCellBlockType","tableRowBlockType","tableBlockType","LayoutBlock","LayoutColumnBlock","createLayoutBlock","layoutId","columnIds","columnId","columnBlock","containerToHTML","tagOpen","tagClose","containerToPlainText","layoutColumnBlockType","layoutBlockType","DividerBlock","createDividerBlock","dividerBlockType","dividerId","CALLOUT_COLORS","CalloutBlock","editingIcon","setEditingIcon","isColorPickerOpen","setIsColorPickerOpen","colorTriggerRef","colorPickerRef","colorOutsideRefs","closeColorPicker","commitIcon","handleIconKeyDown","handleColorChange","childrenToHTML","inner","calloutBlockType","BlockquoteBlock","blockquoteBlockType","LANGUAGES","LANGUAGE_OPTIONS","lang","insertLiteralTextAtCaret","CodeBlock","focusBlock","handleLanguageChange","language","codeEl","codeBlockType","mergeToggleHeadingOrNoop","ToggleHeadingBlock","createToggleHeadingBlock","summary","headingEl","pBlock","toggleHeadingBlockType","COLORS","ButtonEditModal","setLabel","setColor","attrs","setAttrs","existingAttrs","updateAttrRow","removeAttrRow","handleSave","customAttrs","DEFAULT_COLOR","ButtonBlock","isEditModalOpen","setIsEditModalOpen","openLink","dataAttrs","createButtonBlock","MARKER_CLASS","attrHTML","attr","buttonBlockType","readFileAsDataURL","file","reader","KIND_LABEL","KIND_ACCEPT","MIN_WIDTH","MAX_WIDTH","ALIGN_OPTIONS","clampWidth","pct","EmbedPreview","kind","src","name","alt","EmbedBlock","urlInput","setUrlInput","isDragOver","setIsDragOver","isAltTextOpen","setIsAltTextOpen","altDraft","setAltDraft","previewRef","frameRef","setMedia","openAltText","closeAltText","saveAltText","handleFileChange","handleDrop","handleDragOver","handleDragLeave","commitUrl","clearMedia","frameEl","containerWidth","computePct","align","canResize","effectiveWidth","createEmbedBlock","mimeType","KIND_ICONS","FILE_MARKER_CLASS","alignWidthStyle","declarations","parseAlignWidth","styleWidth","blockOf","insertEmbedCommand","embedId","embedBlockType","DEFAULT_SIZE","DEFAULT_THINNING","DEFAULT_SMOOTHING","TAPER_POINT_COUNT","MIN_RADIUS_FACTOR","SPEED_NORM","dist","clamp","min","round","DEFAULT_PRESSURE","hasRealPressureVariation","points","pressure","computeRadii","thinning","baseRadius","radii","speed","step","speedFactor","pressureFactor","radius","taperCount","factor","smoothPoints","smoothing","midX","midY","x","y","computeOffsets","right","ty","len","nx","ny","pathFromPolygon","poly","dotPath","angle","getStrokeOutlinePath","rawPoints","smoothed","polygon","strokeBoundingBox","minX","minY","maxX","maxY","computeViewTransform","svgEl","rectWidth","rectHeight","scale","offsetX","offsetY","clientToLocal","view","localPixelScale","zoomAnchoredView","prevView","nextSize","cursorLocalX","cursorLocalY","zoomCenteredView","centerX","centerY","clampViewOffset","boundsSize","centered","boxesIntersect","padding","normalizeRect","x1","y1","x2","y2","rotatePoint","px","py","angleDeg","radians","cos","sin","dx","dy","pointInRect","pointInEllipse","rx","ry","distanceToSegment","lengthSquared","projX","projY","pointNearSegment","tolerance","diamondPoints","trianglePoints","starPoints","spikes","outerRx","outerRy","innerRatio","isOuter","pointInPolygon","vertices","inside","xi","yi","xj","yj","arrowheadPoints","length","ux","uy","backX","backY","halfWidth","useDragResize","compute","onCommit","dragValue","setDragValue","startDrag","DEFAULT_CANVAS_WIDTH","DEFAULT_CANVAS_HEIGHT","createCanvasBlock","strokes","shapes","LEGACY_Z_BASE","effectiveZ","item","isShape","orderedDrawables","nextZIndex","maxZ","minZIndex","minZ","POLYGON_POINTS_BY_TYPE","shapeToHTML","shape","headSize","fill","fontSize","pointsFn","buildCanvasSVGMarkup","markup","VIEW_SIZE","DEFAULT_STROKE_SIZE","COLOR_SWATCHES","MIN_STROKE_SIZE","MAX_STROKE_SIZE","ERASER_RADIUS","ERASER_RADIUS_PRECISE","MIN_CANVAS_WIDTH","MIN_CANVAS_HEIGHT","MIN_ZOOM","MAX_ZOOM","ZOOM_STEP","MARQUEE_MIN_DRAG","PASTE_OFFSET","NUDGE_STEP","NUDGE_STEP_LARGE","NUDGE_DELTAS","DEFAULT_TEXT_WIDTH","DEFAULT_TEXT_HEIGHT","DEFAULT_TEXT_FONT_SIZE","MIN_TEXT_FONT_SIZE","MAX_TEXT_FONT_SIZE","SNAP_GRID_SIZE","SNAP_ROTATION_STEP","SNAP_GRID_VISUAL_SPACING","snapValue","snapAngle","deg","useStrokePathCache","cacheRef","stroke","cache","path","pointBox","touchCentroid","pointsMap","sumX","sumY","point","strokeNearPoint","SHAPE_TOOLS","SHAPE_TOOL_LIST","ERASER_MODE_LIST","buildDraftShape","fillColor","ARROW_HIT_TOLERANCE","hitTestOneShape","testX","testY","shapeCenter","hitTestShapeAt","applyShapeOffset","shapeBoundingBox","box","applyStrokeOffset","splitStrokePoints","erasedIndices","strokeBoxRect","selectableBoundingBox","findSelectable","selId","hitTestSelectableAt","HANDLE_HIT_RADIUS","HANDLE_VISUAL_SIZE","rectCorners","OPPOSITE_CORNER","ROTATE_HANDLE_OFFSET","rotateHandlePoint","localX","localY","hitTestHandle","rhx","rhy","corner","buildResizedShape","ShapeElement","opacity","head","CanvasBlock","getStrokePath","tool","setTool","eraserMode","setEraserMode","strokeSize","setStrokeSize","setFill","snapEnabled","setSnapEnabled","textFontSize","setTextFontSize","lastShapeTool","setLastShapeTool","isFillPickerOpen","setIsFillPickerOpen","isSizePickerOpen","setIsSizePickerOpen","isShapePickerOpen","setIsShapePickerOpen","isFontSizePickerOpen","setIsFontSizePickerOpen","isEraserPickerOpen","setIsEraserPickerOpen","colorPopoverRef","fillTriggerRef","fillPopoverRef","sizeTriggerRef","sizePopoverRef","shapeTriggerRef","shapePopoverRef","fontSizeTriggerRef","fontSizePopoverRef","eraserTriggerRef","eraserPopoverRef","colorRefs","fillRefs","sizeRefs","shapeRefs","fontSizeRefs","eraserRefs","closeFillPicker","closeSizePicker","closeShapePicker","closeFontSizePicker","closeEraserPicker","svgRef","pointsRef","drawingRef","rafRef","previewPath","setPreviewPath","erasedStrokeIdsRef","erasedShapeIdsRef","erasedPointIndicesRef","erasingRef","eraseRafRef","erasingIds","setErasingIds","erasingShapeIds","setErasingShapeIds","shapeDraftRef","shapeDraftPreview","setShapeDraftPreview","selectedIds","setSelectedIds","moveDraftRef","moveOverride","setMoveOverride","marqueeDraftRef","marqueeRect","setMarqueeRect","clipboardRef","textEditDraft","setTextEditDraft","resizeDraftRef","resizePreviewShape","setResizePreviewShape","setView","viewSize","panRef","touchPointsRef","touchPanRef","dragSize","startResize","schedulePreviewUpdate","stopDrawing","commitStroke","currentStrokes","currentShapes","newStroke","scheduleErasingPreview","hitTestEraserAt","eraserBox","indices","shapeBox","stopErasing","commitErase","hasWholeStrokeErase","hasPartialErase","nextStrokes","stopShapeDraft","commitShapeDraft","newShape","stopMove","commitMove","idSet","nextShapes","stopMarquee","commitMarquee","marqueeBox","hitIds","copySelection","pasteClipboard","nextZ","newStrokes","newShapes","newIds","newId","z","reorderSelection","toFront","selectedStrokes","selectedShapes","selectedOrdered","baseZ","zById","stampZ","handleBringToFront","handleSendToBack","startNewTextEdit","startExistingTextEdit","cancelTextEdit","commitTextEdit","shapeId","nextShape","stopResize","commitResize","resized","cancelActiveSingleGesture","pointerId","svg","dirX","dirY","currentView","handleWheel","zoomFactor","nextZoom","handleZoomIn","handleZoomOut","handleZoomReset","handleExportPNG","svgMarkup","svgDataUrl","img","exportCanvas","handleDoubleClick","hitId","center","textX","textY","_f","_g","startY","strokesList","_h","shapesList","_i","singleSelectedShape","handle","startAngle","fixedX","fixedY","hit","handlePointerMove","startCenterX","startCenterY","startViewX","startViewY","startClientX","startClientY","currentAngle","rawRotation","releaseCapture","handlePointerUp","handlePointerCancel","effectiveHeight","SELECTION_PADDING","selectionBoxes","singleSelectedShapeEntry","selectedDisplayShape","selectionHandlePoints","rotateHandle","ActiveEraserIcon","mode","ActiveShapeIcon","swatch","displayShape","rotation","insertCanvasCommand","canvasId","canvasBlockType","registerBuiltInBlocks","registerBlocks","TABLE_BLOCKS","LAYOUT_BLOCKS","blocksByType","SelectInlineNode","insertInlineRunAtCursor","createInlineRun","currentRun","beforeText","afterText","inlineRun","beforeRun","afterRun","opt","selectInlineType","DateInlineNode","formatDate","todayIso","dateInlineType","CheckboxInlineNode","handleCheckedChange","checkboxInlineType","TableSelectInlineNode","tableSelectInlineType","emojiInlineType","registerBuiltInInlineTypes","registerInlineTypes","TABLE_SELECT_INLINE_TYPES","typesByType","defaultDoc","useEditor","currentUserId","customRegisterBlocks","customRegisterInlineTypes","EditorTrailingSpace","minHeight","lastBlock","copyBlockRangeToClipboard","deleteBlockRange","moveBlockRangeUp","first","precedingId","moveBlockRangeDown","followingId","isEntireBlockRangeHidden","setBlockRangeHidden","hidden","convertBlockRangeType","eligibleIds","allOps","reorderBlockRangeFromStore","BlockRangeActionMenu","clear","blockWord","handleCopy","handleCut","hasEligibleBlock","APP_MIME","textToParagraphs","line","walkDomToBlocks","matchers","results","consumeList","consumeBlockquote","bqNode","paragraphs","p","matched","deserializeClipboard","dataTransfer","types","json","deserializeAppJSON","blankRun","deleteRunRangeInBlock","beforeRuns","afterRuns","spanRuns","survivors","prefixRun","suffixValue","suffixRun","blank","lastBefore","deleteOverBlockRange","crossSelection","startBlockId","endBlockId","startBlockIndex","endBlockIndex","fromBlockIndex","toBlockIndex","firstIsStart","firstRunId","firstOffset","lastOffset","firstBlockId","lastBlockId","firstBlock","firstRunIds","firstIdx","firstPrefixRuns","firstRun","firstPrefixSurvivor","lastRunIds","lastIdx","lastSuffixRuns","lastRun","lastSuffixSurvivor","firstSurvivors","lastSurvivors","mergeable","removedCount","wouldBeOnlyChild","survivingBlockId","merged","firstFinalRuns","deleteEntireDocument","replacementText","closestBlockId","resolveSelectedBlockIds","startId","endId","deleteCurrentSelection","same","cross","insertTextAtCaret","useClipboardHandlers","onCopy","onCut","onPaste","inserts","rootIndex","deleteResult","atBlockId","insertOps","BOOLEAN_MARK_NAMES","VALUE_MARK_NAMES","sameMarkValue","summarizeMarks","getMarksSummaryOverSelection","getMarksSummaryOverBlockRange","applyMarksPatch","marksPatch","applyPatchToSingleRun","middleRun","applyMarksPatchOverRunSpan","lastNewRunId","computeShouldEnableForRange","textRuns","toggleMarkOnRunRange","shouldEnable","setMarksOverSelection","toggleMarkOverSelection","toggleMarkOverBlockRange","setMarksOverBlockRange","allMarked","marksPatchOrFn","markNameForDecision","sawText","blockFirstRunId","blockLastRunId","blockLastRun","blockLastOffset","isEntireBlockSelected","lastLength","isCurrentBlockEmpty","deleteSelectedBlockAndRefocus","landId","landBlock","restoreSelectionAfterHistoryChange","targetBlockId","MARK_KEYS","useEditorKeyboardShortcuts","sameBlockSelection","newRunId","crossBlockSelection","handleMouseDown","DRAG_THRESHOLD_PX","computeRange","anchorId","hoverId","anchorBlock","anchorIndex","hoverIndex","isCoarsePointer","useBlockRangeDrag","anchorIdRef","isArmedRef","startPointRef","armDrag","ESTIMATED_MENU_HEIGHT","useActiveDescendantWiring","activeOptionId","menuId","SlashMenu","activeItemRef","availableBottom","positionStyle","command","q","k","caretOffsetInRun","rawOffset","rawTextBeforeCaret","useTriggerMenu","regex","getCommands","setState","textBeforeCaret","cmd","selectCommand","SLASH_RE","useSlashMenuTrigger","EMOJI_LIST","insertPlainTextAtCursor","EMOJI_COMMANDS","char","keywords","EMOJI_RE","getEmojiCommands","useEmojiMenuTrigger","AT_RE","useAtMenuTrigger","getAtCommands","useTextFormattingActions","isLinkModalOpen","setIsLinkModalOpen","applyPatch","toggleBoolean","setSubSuper","opposite","enable","pendingLinkRef","openLinkModal","closeLinkModal","applyLinkPatch","pending","handleSaveLink","handleRemoveLink","TOUCH_INPUT_CLASS","matchesCoarsePointer","useCoarsePointer","isTouch","setIsTouch","BOOLEAN_BUTTONS","TEXT_COLORS","HIGHLIGHT_COLORS","FloatingToolbar","onComment","openPicker","setOpenPicker","pendingComment","setPendingComment","pendingCommentRef","closeFloatingSelection","openCommentComposer","discardPendingComment","submitCommentComposer","cancelCommentComposer","isComposingComment","useFloatingToolbarTrigger","sameBlock","crossBlock","EditorSurface","slashMenu","emojiMenu","atMenu","floatingToolbar","NoteloomEditor","editor","showCommentsPanel","useFieldTypes","STABLE_STATE","useHistory","usePersistedDocument","usePresence","session","presence","setPresence","useServiceWorkerUpdate","updateAvailable","setUpdateAvailable","waitingWorker","setWaitingWorker","watchRegistration","registration","noteWaiting","installing","applyUpdate","reloadOnceControllerChanges","COMMANDS","PHRASE_TO_ACTION","phrases","action","phrase","normalizeUtterance","matchVoiceCommand","listVoiceCommands","description","applyVoiceAction","getSpeechRecognitionCtor","PERMISSION_DENIED_MESSAGE","useVoiceTyping","shortcut","isListening","setIsListening","status","setStatus","permissionState","setPermissionState","setError","recognitionRef","sessionAnchorRef","expectedCaretRef","liveEntryRef","committedCountRef","isSupported","permissionStatus","createEntryAtAnchor","writeEntryText","beforeChar","insertedText","flushSync","nextOffset","revertEntryText","restored","removeEntryTextSilently","handleRecognitionResult","interimText","hasInterim","transcript","handleSelectionChange","expected","initialCaret","Ctor","recognition","VoicePermissionModal","voice","dismissed","setDismissed","useCaretRect","isActive","nextRect","VoiceListeningIndicator","badgeRef","isProcessing","MobileBlockPickerSheet","onSelectCommand","MobileBlockOptionsSheet","useMobileBarState","isFocused","setIsFocused","setMode","selectionState","setSelectionState","caretState","setCaretState","handleFocusIn","handleFocusOut","FormattingActions","TableCellActions","handleInsertRow","handleInsertColumn","CodeBlockActions","CalloutActions","BLOCK_TYPE_ACTIONS","findActionableAncestor","findTopLevelAncestor","MobileActionBar","isPickerOpen","setIsPickerOpen","isOptionsOpen","setIsOptionsOpen","closePicker","openOptions","closeOptions","handleSelectCommand","handleDismissKeyboard","actionableBlock","TypeActions","topLevelBlock","PROPS_ALLOWLIST","TITLE_RUN_TYPES","NO_TEXT_LEAF_TYPES","exportBlock","exportDocumentSimpleJSON","textToRuns","importTable","simpleBlock","blocksOut","runsOut","rowCells","cellIds","cellHTML","importBlock","importDocumentSimpleJSON","topIds","FORMATS","DocumentExportButton","format","setFormat","copied","setCopied","CustomSelectInlineNode","onManage","createSelectFieldType","triggers","registerStoredFieldTypes","useRegisterFieldTypes","fieldTypes","openEdit","previousIdsRef","FieldTypeEditorModal","isEditing","setName","setOptions","handleRemoveOption","handleAddOption"],"mappings":"yUAAaA,EAAK,CAChB,aAAc,cACd,aAAc,cACd,WAAY,YACZ,kBAAmB,kBACnB,mBAAoB,mBACpB,WAAY,YACZ,sBAAuB,qBACvB,iBAAkB,iBAClB,eAAgB,eAChB,eAAgB,eAChB,eAAgB,eAChB,kBAAmB,kBACnB,kBAAmB,kBACnB,mBAAoB,mBACpB,sBAAuB,sBACvB,kBAAmB,kBACnB,qBAAsB,qBACtB,gBAAiB,gBACnB,EAEO,SAASC,GAAYC,EAAOC,EAAUC,EAAOC,EAAS,CAC3D,MAAO,CAAE,KAAML,EAAG,aAAc,MAAAE,EAAO,SAAAC,EAAU,MAAAC,EAAO,QAAAC,EAC1D,CAEO,SAASC,GAAYC,EAAI,CAC9B,MAAO,CAAE,KAAMP,EAAG,aAAc,GAAAO,CAAE,CACpC,CAEO,SAASC,GAAUD,EAAIE,EAAYC,EAAS,CACjD,MAAO,CAAE,KAAMV,EAAG,WAAY,GAAAO,EAAI,WAAAE,EAAY,QAAAC,EAChD,CAEO,SAASC,EAAiBJ,EAAIK,EAAO,CAC1C,MAAO,CAAE,KAAMZ,EAAG,mBAAoB,GAAAO,EAAI,MAAAK,CAAK,CACjD,CAYO,SAASC,GAAgBN,EAAIO,EAAWC,EAAO,CACpD,MAAO,CAAE,KAAMf,EAAG,kBAAmB,GAAAO,EAAI,UAAAO,EAAW,MAAAC,EACtD,CAEO,SAASC,GAAUT,EAAIK,EAAO,CACnC,MAAO,CAAE,KAAMZ,EAAG,WAAY,GAAAO,EAAI,MAAAK,CAAK,CACzC,CAkBO,SAASK,GAAaV,EAAIW,EAAcC,EAAYC,EAAe,CACxE,MAAO,CAAE,KAAMpB,EAAG,eAAgB,GAAAO,EAAI,aAAAW,EAAc,WAAAC,EAAY,cAAAC,EAClE,CAGO,SAASC,GAAmBC,EAASC,EAAY,CACtD,MAAO,CAAE,KAAMvB,EAAG,sBAAuB,QAAAsB,EAAS,WAAAC,CAAU,CAC9D,CAQO,SAASC,GAAeF,EAASG,EAAWC,EAAS,CAC1D,MAAO,CAAE,KAAM1B,EAAG,iBAAkB,QAAAsB,EAAS,UAAAG,EAAW,QAAAC,EAC1D,CAUO,SAASC,GAAaL,EAASM,EAAM,CAC1C,MAAO,CAAE,KAAM5B,EAAG,eAAgB,QAAAsB,EAAS,KAAAM,CAAI,CACjD,CAUO,SAASC,GAAaC,EAAW,CACtC,MAAO,CAAE,KAAM9B,EAAG,eAAgB,UAAA8B,CAAS,CAC7C,CAEO,SAASC,GAAgBxB,EAAIK,EAAO,CACzC,MAAO,CAAE,KAAMZ,EAAG,kBAAmB,GAAAO,EAAI,MAAAK,CAAK,CAChD,CAEO,SAASoB,GAAgBzB,EAAI,CAClC,MAAO,CAAE,KAAMP,EAAG,kBAAmB,GAAAO,CAAE,CACzC,CAWO,SAAS0B,GAAiBC,EAAQ,CACvC,MAAO,CAAE,KAAMlC,EAAG,mBAAoB,OAAAkC,CAAM,CAC9C,CAEO,SAASC,GAAoBC,EAAW,CAC7C,MAAO,CAAE,KAAMpC,EAAG,sBAAuB,UAAAoC,CAAS,CACpD,CAGO,SAASC,GAAgBD,EAAWE,EAAS,CAClD,MAAO,CAAE,KAAMtC,EAAG,kBAAmB,UAAAoC,EAAW,QAAAE,CAAO,CACzD,CAGO,SAASC,GAAmBH,EAAWI,EAAW,CACvD,MAAO,CAAE,KAAMxC,EAAG,qBAAsB,UAAAoC,EAAW,UAAAI,CAAS,CAC9D,CAEO,SAASC,GAAeL,EAAWM,EAAU,CAClD,MAAO,CAAE,KAAM1C,EAAG,gBAAiB,UAAAoC,EAAW,SAAAM,CAAQ,CACxD,4aC/IO,MAAMC,EAAI,CACf,YAAYC,EAAQ,CAClB,KAAK,OAASA,EACd,KAAK,SAAW,EAChB,KAAK,QAAU,CACjB,CAGA,MAAO,CACL,MAAMC,EAAM,KAAK,IAAG,EACpB,OAAIA,EAAM,KAAK,UACb,KAAK,SAAWA,EAChB,KAAK,QAAU,GAEf,KAAK,SAAW,EAEX,CAAE,SAAU,KAAK,SAAU,QAAS,KAAK,QAAS,OAAQ,KAAK,MAAM,CAC9E,CAOA,QAAQC,EAAQ,CACd,MAAMD,EAAM,KAAK,IAAG,EACdE,EAAU,KAAK,IAAIF,EAAK,KAAK,SAAUC,EAAO,QAAQ,EAC5D,OAAIC,IAAY,KAAK,UAAYA,IAAYD,EAAO,SAClD,KAAK,QAAU,KAAK,IAAI,KAAK,QAASA,EAAO,OAAO,EAAI,EAC/CC,IAAY,KAAK,SAC1B,KAAK,SAAW,EACPA,IAAYD,EAAO,SAC5B,KAAK,QAAUA,EAAO,QAAU,EAEhC,KAAK,QAAU,EAEjB,KAAK,SAAWC,EACT,CAAE,SAAU,KAAK,SAAU,QAAS,KAAK,QAAS,OAAQ,KAAK,MAAM,CAC9E,CAGA,OAAO,QAAQC,EAAGC,EAAG,CACnB,OAAID,EAAE,WAAaC,EAAE,SAAiBD,EAAE,SAAWC,EAAE,SACjDD,EAAE,UAAYC,EAAE,QAAgBD,EAAE,QAAUC,EAAE,QAC9CD,EAAE,SAAWC,EAAE,OAAe,EAC3BD,EAAE,OAASC,EAAE,OAAS,GAAK,CACpC,CACF,CAEO,SAASC,IAAY,CAC1B,OAAI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WACzD,OAAO,WAAU,EAEnB,QAAQ,KAAK,IAAG,CAAE,IAAI,KAAK,OAAM,EAAG,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,EAClE,CCxCO,MAAMC,EAAc,CACzB,aAAc,CACZ,KAAK,MAAQ,IAAI,GACnB,CAGA,OAAO,UAAUC,EAAK,CAAE,OAAAR,EAAS,QAAQ,EAAK,CAAA,EAAI,CAChD,MAAMS,EAAQ,IAAIF,GAClB,IAAIG,EAAO,KACX,UAAW/C,KAAM6C,EACfC,EAAM,MAAM,IAAI9C,EAAI,CAClB,GAAAA,EACA,SAAU+C,EACV,OAAAV,EACA,MAAO,CAAE,SAAU,EAAG,QAAS,EAAG,OAAAA,CAAM,EACxC,QAAS,EACjB,CAAO,EACDU,EAAO/C,EAET,OAAO8C,CACT,CAEA,IAAI9C,EAAI,CACN,OAAO,KAAK,MAAM,IAAIA,CAAE,CAC1B,CAGA,QAAQA,EAAI,CACV,OAAO,KAAK,MAAM,IAAIA,CAAE,CAC1B,CAEA,UAAUA,EAAI,CACZ,MAAMgD,EAAO,KAAK,MAAM,IAAIhD,CAAE,EAC9B,MAAO,CAACgD,GAAQA,EAAK,OACvB,CAOA,OAAOhD,EAAIiD,EAASC,EAAOb,EAAQ,CAC7B,KAAK,MAAM,IAAIrC,CAAE,GACrB,KAAK,MAAM,IAAIA,EAAI,CAAE,GAAAA,EAAI,SAAUiD,EAAS,OAAAZ,EAAQ,MAAAa,EAAO,QAAS,EAAK,CAAE,CAC7E,CAWA,OAAOlD,EAAIkD,EAAO,CAChB,MAAMF,EAAO,KAAK,MAAM,IAAIhD,CAAE,EACzBgD,IACLA,EAAK,QAAU,GACXE,IAAOF,EAAK,aAAeE,GACjC,CAGA,QAAQlD,EAAI,CACV,MAAMgD,EAAO,KAAK,MAAM,IAAIhD,CAAE,EACzBgD,IACLA,EAAK,QAAU,GACjB,CAoBA,KAAKhD,EAAIiD,EAASC,EAAOb,EAAQ,CAC/B,GAAIY,IAAYjD,EAAI,OACpB,MAAMgD,EAAO,KAAK,MAAM,IAAIhD,CAAE,EAC9B,GAAI,CAACgD,EAAM,OACX,MAAMG,EAAcH,EAAK,SACzB,UAAWI,KAAS,KAAK,MAAM,OAAM,EAC/BA,EAAM,WAAapD,IAAIoD,EAAM,SAAWD,GAE9CH,EAAK,SAAWC,EAChBD,EAAK,OAASX,EACdW,EAAK,MAAQE,EACbF,EAAK,QAAU,EACjB,CAQA,MAAMK,EAAa,CACjB,UAAWd,KAAUc,EAAa,CAChC,MAAMC,EAAQ,KAAK,MAAM,IAAIf,EAAO,EAAE,EACjCe,EAEMf,EAAO,SAAW,CAACe,EAAM,UAClCA,EAAM,QAAU,IAFhB,KAAK,MAAM,IAAIf,EAAO,GAAI,CAAE,GAAGA,EAAQ,CAQ3C,CACF,CAGA,aAAc,CACZ,OAAO,MAAM,KAAK,KAAK,MAAM,OAAM,CAAE,CACvC,CAGA,gBAAiB,CACf,IAAIgB,EAAQ,EACZ,UAAWP,KAAQ,KAAK,MAAM,OAAM,EAC9BA,EAAK,UAASO,GAAS,GAE7B,OAAOA,CACT,CAuBA,gBAAgBC,EAAa,CAC3B,IAAIC,EAAU,EACd,SAAW,CAACzD,EAAIgD,CAAI,IAAK,KAAK,MAAO,CACnC,GAAI,CAACA,EAAK,QAAS,SAKnB,MAAMU,EAAMV,EAAK,cAAgBA,EAAK,MACtC,GAAI,EAAAZ,GAAI,QAAQsB,EAAKF,CAAW,GAAK,GACrC,WAAWJ,KAAS,KAAK,MAAM,OAAM,EAC/BA,EAAM,WAAapD,IAAIoD,EAAM,SAAWJ,EAAK,UAEnD,KAAK,MAAM,OAAOhD,CAAE,EACpByD,GAAW,EACb,CACA,OAAOA,CACT,CAOA,SAAU,CACR,MAAME,EAAmB,IAAI,IAC7B,UAAWX,KAAQ,KAAK,MAAM,OAAM,EAAI,CACtC,MAAMY,EAASD,EAAiB,IAAIX,EAAK,QAAQ,EAC7CY,EAAQA,EAAO,KAAKZ,CAAI,EACvBW,EAAiB,IAAIX,EAAK,SAAU,CAACA,CAAI,CAAC,CACjD,CACA,UAAWY,KAAUD,EAAiB,SACpCC,EAAO,KAAK,CAACnB,EAAGC,IAAMN,GAAI,QAAQM,EAAE,MAAOD,EAAE,KAAK,CAAC,EAGrD,MAAMoB,EAAS,CAAA,EAKTC,EAAQ,CAAC,GAAIH,EAAiB,IAAI,IAAI,GAAK,CAAA,CAAG,EAAE,QAAO,EAC7D,KAAOG,EAAM,OAAS,GAAG,CACvB,MAAMd,EAAOc,EAAM,IAAG,EACjBd,EAAK,SAASa,EAAO,KAAKb,EAAK,EAAE,EACtC,MAAMe,EAAWJ,EAAiB,IAAIX,EAAK,EAAE,EAC7C,GAAIe,EACF,QAASC,EAAID,EAAS,OAAS,EAAGC,GAAK,EAAGA,GAAK,EAAGF,EAAM,KAAKC,EAASC,CAAC,CAAC,CAE5E,CACA,OAAOH,CACT,CACF,CC5NO,MAAMI,EAAmB,CAC9B,aAAc,CACZ,KAAK,OAAS,IAAI,GACpB,CAEA,OAAO,aAAajE,EAAIkE,EAAO,CAC7B,MAAO,GAAGlE,CAAE,IAAIkE,CAAK,EACvB,CAEA,IAAIlE,EAAIkE,EAAO,CACb,OAAO,KAAK,OAAO,IAAID,GAAmB,aAAajE,EAAIkE,CAAK,CAAC,GAAK,IACxE,CAGA,YAAYlE,EAAIkE,EAAOhB,EAAO,CAC5B,KAAK,OAAO,IAAIe,GAAmB,aAAajE,EAAIkE,CAAK,EAAGhB,CAAK,CACnE,CAOA,kBAAkBlD,EAAIkE,EAAOC,EAAa,CACxC,MAAMC,EAAU,KAAK,IAAIpE,EAAIkE,CAAK,EAClC,OAAKE,EACEhC,GAAI,QAAQ+B,EAAaC,CAAO,EAAI,EADtB,EAEvB,CAEA,aAAapE,EAAIkE,EAAOC,EAAa,CACnC,KAAK,OAAO,IAAIF,GAAmB,aAAajE,EAAIkE,CAAK,EAAGC,CAAW,CACzE,CACF,CC9BO,SAASE,GAAeC,EAAUC,EAAU,CACjD,MAAMC,EAAW,MAAM,KAAKF,GAAY,EAAE,EACpCG,EAAW,MAAM,KAAKF,GAAY,EAAE,EAC1C,IAAIG,EAAQ,EACZ,MAAMC,EAAW,KAAK,IAAIH,EAAS,OAAQC,EAAS,MAAM,EAC1D,KAAOC,EAAQC,GAAYH,EAASE,CAAK,IAAMD,EAASC,CAAK,GAAGA,GAAS,EAEzE,IAAIE,EAASJ,EAAS,OAClBK,EAASJ,EAAS,OACtB,KAAOG,EAASF,GAASG,EAASH,GAASF,EAASI,EAAS,CAAC,IAAMH,EAASI,EAAS,CAAC,GACrFD,GAAU,EACVC,GAAU,EAGZ,MAAO,CAAE,MAAAH,EAAO,OAAAE,EAAQ,OAAAC,EAAQ,SAAAL,EAAU,SAAAC,CAAQ,CACpD,CC3BO,SAASK,GAAQ,CACtB,OAAI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WACzD,OAAO,aAET,MAAM,KAAK,IAAG,CAAE,IAAI,KAAK,OAAM,EAAG,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,EAChE,CCuBA,MAAMC,GAAkB,cAGlBC,GAAe,YAgBd,MAAMC,EAAY,CACvB,YAAYC,EAAK,CACf,KAAK,OAAS,IAAI,MAAKA,GAAA,YAAAA,EAAK,SAAU,CAAA,GAAI,IAAKxC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAC/D,KAAK,KAAO,IAAI,MAAKwC,GAAA,YAAAA,EAAK,OAAQ,CAAA,GAAI,IAAKC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAC3D,KAAK,QAASD,GAAA,YAAAA,EAAK,SAAU,KAC7B,KAAK,WAAa,IAAI,MAAKA,GAAA,YAAAA,EAAK,aAAc,CAAA,GAAI,IAAKE,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACvE,KAAK,oBAAsB,KAC3B,KAAK,SAAW,IAAI,MAAKF,GAAA,YAAAA,EAAK,WAAY,CAAA,GAAI,IAAKG,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACnE,KAAK,kBAAoB,KACzB,KAAK,WAAa,IAAI,IACtB,KAAK,iBAAmB,IAAI,IAS5B,KAAK,QAAU1C,KACf,KAAK,OAAS,IAAIP,GAAI,KAAK,OAAO,EAClC,KAAK,aAAe,IAAI6B,GACxB,KAAK,QAAU,IAAI,IAYnB,KAAK,WAAa,IAAI,IACtB,KAAK,UAAY,IAAI,IACrB,KAAK,mBAAqB,IAAI,GAChC,CAGA,UAAUrE,EAAU,CAClB,IAAI0F,EAAQ,KAAK,QAAQ,IAAI1F,CAAQ,EACrC,GAAI,CAAC0F,EAAO,CACV,MAAM3F,EAAQ,KAAK,OAAO,IAAIC,CAAQ,EACtC0F,EAAQ1C,GAAc,WAAUjD,GAAA,YAAAA,EAAO,aAAc,CAAA,EAAI,CAAE,OAAQ,QAAQ,CAAE,EAC7E,KAAK,QAAQ,IAAIC,EAAU0F,CAAK,CAClC,CACA,OAAOA,CACT,CAuBA,aAAaC,EAAO,CAClB,IAAID,EAAQ,KAAK,WAAW,IAAIC,CAAK,EACrC,GAAI,CAACD,EAAO,CACV,MAAME,EAAM,KAAK,KAAK,IAAID,CAAK,EACzBE,EAAQ,IAAI,IAClBH,EAAQ,IAAI1C,GACZ,IAAIG,EAAO,KACPlD,EAAQ,EACZ,UAAW6F,KAAM,MAAM,MAAKF,GAAA,YAAAA,EAAK,QAAS,EAAE,EAAG,CAC7C,MAAMG,EAAS,GAAGJ,CAAK,eAAe1F,CAAK,GAC3C4F,EAAM,IAAIE,EAAQD,CAAE,EACpBJ,EAAM,OAAOK,EAAQ5C,EAAM,CAAE,SAAU,EAAG,QAAS,EAAG,OAAQ,QAAQ,EAAI,QAAQ,EAClFA,EAAO4C,EACP9F,GAAS,CACX,CACA,KAAK,WAAW,IAAI0F,EAAOD,CAAK,EAChC,KAAK,UAAU,IAAIC,EAAOE,CAAK,CACjC,CACA,OAAOH,CACT,CAGA,qBAAqBC,EAAO,CAC1B,IAAIK,EAAQ,KAAK,mBAAmB,IAAIL,CAAK,EAC7C,GAAIK,IAAU,OAAW,CACvB,MAAMN,EAAQ,KAAK,aAAaC,CAAK,EAC/BE,EAAQ,KAAK,UAAU,IAAIF,CAAK,EACtCK,EAAQN,EAAM,UAAU,IAAKK,GAAWF,EAAM,IAAIE,CAAM,CAAC,EAAE,KAAK,EAAE,EAClE,KAAK,mBAAmB,IAAIJ,EAAOK,CAAK,CAC1C,CACA,OAAOA,CACT,CAWA,aAAaL,EAAOhB,EAAU,CAC5B,MAAMD,EAAW,KAAK,qBAAqBiB,CAAK,EAC1C,CAAE,MAAAb,EAAO,OAAAE,EAAQ,OAAAC,EAAQ,SAAAJ,CAAQ,EAAKJ,GAAeC,EAAUC,CAAQ,EACvEe,EAAQ,KAAK,aAAaC,CAAK,EAC/BE,EAAQ,KAAK,UAAU,IAAIF,CAAK,EAChCM,EAAaP,EAAM,UACnBpC,EAAQ,KAAK,OAAO,KAAI,EAExB4C,EAAiB,CAAA,EACvB,QAAS9B,EAAIU,EAAOV,EAAIY,EAAQZ,GAAK,EAAG,CACtC,MAAMhE,EAAK6F,EAAW7B,CAAC,EACvBsB,EAAM,OAAOtF,EAAIkD,CAAK,EACtB4C,EAAe,KAAK,CAAE,GAAA9F,EAAI,MAAAkD,CAAK,CAAE,CACnC,CAEA,MAAM6C,EAAgB,CAAA,EACtB,IAAI9C,EAAUyB,EAAQ,EAAImB,EAAWnB,EAAQ,CAAC,EAAI,KAClD,QAASV,EAAIU,EAAOV,EAAIa,EAAQb,GAAK,EAAG,CACtC,MAAMhE,EAAK8E,IACLY,EAAKjB,EAAST,CAAC,EACrByB,EAAM,IAAIzF,EAAI0F,CAAE,EAChBJ,EAAM,OAAOtF,EAAIiD,EAASC,EAAO,KAAK,OAAO,EAC7C6C,EAAc,KAAK,CAAE,GAAA/F,EAAI,KAAM0F,EAAI,QAAAzC,EAAS,MAAAC,CAAK,CAAE,EACnDD,EAAUjD,CACZ,CAEA,YAAK,mBAAmB,OAAOuF,CAAK,EAC7B,CAAE,SAAAjB,EAAU,cAAAyB,EAAe,eAAAD,EAAgB,MAAA5C,CAAK,CACzD,CAcA,mBAAmBqC,EAAOS,EAAU,CAClC,MAAMV,EAAQ,KAAK,aAAaC,CAAK,EAC/BE,EAAQ,KAAK,UAAU,IAAIF,CAAK,EACtC,UAAWF,KAAKW,EAAS,cACnBV,EAAM,IAAID,EAAE,EAAE,EAAGC,EAAM,QAAQD,EAAE,EAAE,GAErCI,EAAM,IAAIJ,EAAE,GAAIA,EAAE,IAAI,EACtBC,EAAM,OAAOD,EAAE,GAAIA,EAAE,QAASA,EAAE,MAAO,KAAK,OAAO,GAGvD,UAAWY,KAAKD,EAAS,eAAgBV,EAAM,OAAOW,EAAE,GAAIA,EAAE,KAAK,EACnE,KAAK,mBAAmB,OAAOV,CAAK,CACtC,CAEA,SAASvF,EAAI,CACX,OAAO,KAAK,OAAO,IAAIA,CAAE,CAC3B,CAEA,OAAOA,EAAI,CACT,OAAO,KAAK,KAAK,IAAIA,CAAE,CACzB,CASA,eAAgB,CACd,OAAK,KAAK,sBAAqB,KAAK,oBAAsB,CAAC,GAAG,KAAK,WAAW,OAAM,CAAE,GAC/E,KAAK,mBACd,CAEA,aAAaA,EAAI,CACf,OAAO,KAAK,WAAW,IAAIA,CAAE,CAC/B,CAQA,aAAc,CACZ,OAAK,KAAK,oBAAmB,KAAK,kBAAoB,CAAC,GAAG,KAAK,SAAS,OAAM,CAAE,GACzE,KAAK,iBACd,CAEA,WAAWA,EAAI,CACb,OAAO,KAAK,SAAS,IAAIA,CAAE,CAC7B,CAQA,cAAe,CACb,MAAO,CAAC,GAAG,KAAK,KAAK,KAAI,CAAE,CAC7B,CAEA,WAAY,CACV,OAAO,KAAK,MACd,CAEA,UAAUA,EAAIkG,EAAU,CACtB,IAAIC,EAAM,KAAK,WAAW,IAAInG,CAAE,EAChC,OAAKmG,IACHA,EAAM,IAAI,IACV,KAAK,WAAW,IAAInG,EAAImG,CAAG,GAE7BA,EAAI,IAAID,CAAQ,EACT,IAAM,CACXC,EAAI,OAAOD,CAAQ,EACfC,EAAI,OAAS,GAAG,KAAK,WAAW,OAAOnG,CAAE,CAC/C,CACF,CAWA,aAAakG,EAAU,CACrB,YAAK,iBAAiB,IAAIA,CAAQ,EAC3B,IAAM,KAAK,iBAAiB,OAAOA,CAAQ,CACpD,CAEA,QAAQE,EAAY,CAClB,UAAWpG,KAAMoG,EAAY,CAC3B,MAAMD,EAAM,KAAK,WAAW,IAAInG,CAAE,EAClC,GAAKmG,EAEL,UAAWD,IAAY,CAAC,GAAGC,CAAG,EAAGD,EAAQ,CAC3C,CACA,GAAI,KAAK,iBAAiB,KAAO,EAC/B,UAAWA,IAAY,CAAC,GAAG,KAAK,gBAAgB,EAAGA,GAEvD,CAGA,gBAAgBG,EAAQ,CACtB,MAAMC,EAAS,CAAA,EACTjF,EAAO,CAAA,EACPkF,EAAQvG,GAAO,OACnB,GAAI,KAAK,KAAK,IAAIA,CAAE,EAAG,CACrBqB,EAAK,KAAK,KAAK,KAAK,IAAIrB,CAAE,CAAC,EAC3B,MACF,CACA,MAAML,EAAQ,KAAK,OAAO,IAAIK,CAAE,EAChC,GAAKL,EACL,CAAA2G,EAAO,KAAK3G,CAAK,EACjB,UAAW6G,KAAW7G,EAAM,WAAY4G,EAAKC,CAAO,EAIpD,UAAWjB,MAASkB,EAAA9G,EAAM,QAAN,YAAA8G,EAAa,cAAe,GAAIF,EAAKhB,CAAK,EAChE,EACA,OAAAgB,EAAKF,CAAM,EACJ,CAAE,OAAAC,EAAQ,KAAAjF,EACnB,CAEA,eAAegF,EAAQ,CACrB,MAAME,EAAQvG,GAAO,OACnB,GAAI,KAAK,KAAK,IAAIA,CAAE,EAAG,CACrB,KAAK,KAAK,OAAOA,CAAE,EACnB,MACF,CACA,MAAML,EAAQ,KAAK,OAAO,IAAIK,CAAE,EAChC,GAAKL,EACL,WAAW6G,KAAW7G,EAAM,WAAY4G,EAAKC,CAAO,EACpD,UAAWjB,MAASkB,EAAA9G,EAAM,QAAN,YAAA8G,EAAa,cAAe,GAAIF,EAAKhB,CAAK,EAC9D,KAAK,OAAO,OAAOvF,CAAE,EACvB,EACAuG,EAAKF,CAAM,CACb,CAOA,eAAeK,EAAI,OACjB,OAAQA,EAAG,KAAI,CACb,KAAKjH,EAAG,WAAY,CAClB,MAAM+F,EAAM,KAAK,KAAK,IAAIkB,EAAG,EAAE,EACzBC,EAAY,OAAO,KAAKD,EAAG,KAAK,EAatC,GAAIC,EAAU,SAAW,GAAKA,EAAU,CAAC,IAAM,QAAS,CACtD,IAAIX,EAAWU,EAAG,UAClB,GAAIV,EACF,KAAK,mBAAmBU,EAAG,GAAIV,CAAQ,MAClC,CACL,KAAM,CAAE,SAAA1B,EAAU,cAAAyB,EAAe,eAAAD,EAAgB,MAAA5C,CAAK,EAAK,KAAK,aAAawD,EAAG,GAAIA,EAAG,MAAM,KAAK,EAClGV,EAAW,CAAE,SAAA1B,EAAU,cAAAyB,EAAe,eAAAD,EAAgB,MAAA5C,CAAK,EAC3DwD,EAAG,UAAYV,CACjB,CACA,MAAMzB,EAAW,KAAK,qBAAqBmC,EAAG,EAAE,EAChD,YAAK,KAAK,IAAIA,EAAG,GAAI,CAAE,GAAGlB,EAAK,MAAOjB,CAAQ,CAAE,EAChD,KAAK,cAAgB,CACnB,KAAM,cACN,MAAOmC,EAAG,GACV,cAAeV,EAAS,cACxB,eAAgBA,EAAS,eACzB,MAAOA,EAAS,KAC5B,EACU,KAAK,QAAQ,CAACU,EAAG,EAAE,CAAC,EACbhG,GACLgG,EAAG,GACHV,EAAS,cAAc,IAAKX,GAAMA,EAAE,EAAE,EACtCW,EAAS,eAAe,IAAKX,GAAMA,EAAE,EAAE,EACvCW,EAAS,QACrB,CACQ,CAEA,MAAMY,EAAgB,CAAA,EAChBC,EAAS,CAAA,EACf,UAAWC,KAAOH,EAChBC,EAAcE,CAAG,EAAItB,EAAIsB,CAAG,EAC5BD,EAAOC,CAAG,EAAI,KAAK,OAAO,KAAI,EAC9B,KAAK,aAAa,YAAYJ,EAAG,GAAII,EAAKD,EAAOC,CAAG,CAAC,EAEvD,YAAK,KAAK,IAAIJ,EAAG,GAAI,CAAE,GAAGlB,EAAK,GAAGkB,EAAG,KAAK,CAAE,EAC5C,KAAK,cAAgB,CAAE,KAAM,aAAc,OAAQ,MAAO,GAAIA,EAAG,GAAI,MAAOA,EAAG,MAAO,OAAAG,CAAM,EAC5F,KAAK,QAAQ,CAACH,EAAG,EAAE,CAAC,EACbjG,GAAUiG,EAAG,GAAIE,CAAa,CACvC,CAEA,KAAKnH,EAAG,eAAgB,CACtB,MAAM6F,EAAQ,KAAK,aAAaoB,EAAG,EAAE,EAC/BxD,EAAQ,KAAK,OAAO,KAAI,EAC9B,UAAWyC,KAAUe,EAAG,aAAcpB,EAAM,OAAOK,EAAQzC,CAAK,EAChE,UAAWyC,KAAUe,EAAG,WAAYpB,EAAM,QAAQK,CAAM,EACxD,KAAK,mBAAmB,OAAOe,EAAG,EAAE,EACpC,MAAMlB,EAAM,KAAK,KAAK,IAAIkB,EAAG,EAAE,EACzBnC,EAAW,KAAK,qBAAqBmC,EAAG,EAAE,EAChD,YAAK,KAAK,IAAIA,EAAG,GAAI,CAAE,GAAGlB,EAAK,MAAOjB,CAAQ,CAAE,EAChD,KAAK,cAAgB,CAAE,KAAM,cAAe,MAAOmC,EAAG,GAAI,aAAcA,EAAG,aAAc,WAAYA,EAAG,WAAY,MAAAxD,GACpH,KAAK,QAAQ,CAACwD,EAAG,EAAE,CAAC,EACbhG,GAAagG,EAAG,GAAIA,EAAG,WAAYA,EAAG,YAAY,CAC3D,CAEA,KAAKjH,EAAG,mBAAoB,CAC1B,MAAME,EAAQ,KAAK,OAAO,IAAI+G,EAAG,EAAE,EAC7BE,EAAgB,CAAA,EAChBC,EAAS,CAAA,EACf,UAAWC,KAAO,OAAO,KAAKJ,EAAG,KAAK,EACpCE,EAAcE,CAAG,EAAInH,EAAM,MAAMmH,CAAG,EACpCD,EAAOC,CAAG,EAAI,KAAK,OAAO,KAAI,EAC9B,KAAK,aAAa,YAAYJ,EAAG,GAAI,SAASI,CAAG,GAAID,EAAOC,CAAG,CAAC,EAElE,YAAK,OAAO,IAAIJ,EAAG,GAAI,CAAE,GAAG/G,EAAO,MAAO,CAAE,GAAGA,EAAM,MAAO,GAAG+G,EAAG,KAAK,CAAE,CAAE,EAC3E,KAAK,cAAgB,CAAE,KAAM,aAAc,OAAQ,aAAc,GAAIA,EAAG,GAAI,MAAOA,EAAG,MAAO,OAAAG,CAAM,EACnG,KAAK,QAAQ,CAACH,EAAG,EAAE,CAAC,EACbtG,EAAiBsG,EAAG,GAAIE,CAAa,CAC9C,CAEA,KAAKnH,EAAG,kBAAmB,CACzB,MAAME,EAAQ,KAAK,OAAO,IAAI+G,EAAG,EAAE,EAC7BK,EAAepH,EAAM,KACrBqH,EAAgBrH,EAAM,MACtBuD,EAAQ,KAAK,OAAO,KAAI,EAC9B,YAAK,aAAa,YAAYwD,EAAG,GAAI,OAAQxD,CAAK,EAClD,KAAK,OAAO,IAAIwD,EAAG,GAAI,CAAE,GAAG/G,EAAO,KAAM+G,EAAG,UAAW,MAAOA,EAAG,KAAK,CAAE,EACxE,KAAK,cAAgB,CAAE,KAAM,aAAc,OAAQ,YAAa,GAAIA,EAAG,GAAI,UAAWA,EAAG,UAAW,MAAOA,EAAG,MAAO,MAAAxD,GACrH,KAAK,QAAQ,CAACwD,EAAG,EAAE,CAAC,EACbpG,GAAgBoG,EAAG,GAAIK,EAAcC,CAAa,CAC3D,CAEA,KAAKvH,EAAG,aAAc,CACpB,GAAIiH,EAAG,QAAS,CACd,UAAWhE,KAAKgE,EAAG,QAAQ,OAAQ,KAAK,OAAO,IAAIhE,EAAE,GAAIA,CAAC,EAC1D,UAAWyC,KAAKuB,EAAG,QAAQ,KAAM,KAAK,KAAK,IAAIvB,EAAE,GAAIA,CAAC,CACxD,MACE,KAAK,OAAO,IAAIuB,EAAG,MAAM,GAAIA,EAAG,KAAK,EAEvC,MAAMO,EAAS,KAAK,OAAO,IAAIP,EAAG,QAAQ,EACpCpB,EAAQ,KAAK,UAAUoB,EAAG,QAAQ,EACxC,GAAIpB,EAAM,IAAIoB,EAAG,MAAM,EAAE,EAIvBpB,EAAM,QAAQoB,EAAG,MAAM,EAAE,MACpB,CACL,MAAMQ,EAAe5B,EAAM,UACrBzF,EAAQ6G,EAAG,OAASQ,EAAa,OACjCjE,EAAUpD,EAAQ,EAAIqH,EAAarH,EAAQ,CAAC,EAAI,KACtDyF,EAAM,OAAOoB,EAAG,MAAM,GAAIzD,EAAS,KAAK,OAAO,KAAI,EAAI,KAAK,OAAO,CACrE,CACA,YAAK,OAAO,IAAIyD,EAAG,SAAU,CAAE,GAAGO,EAAQ,WAAY3B,EAAM,QAAO,CAAE,CAAE,EACvE,KAAK,cAAgB,CACnB,KAAM,aACN,SAAUoB,EAAG,SACb,QAASA,EAAG,MAAM,GAClB,KAAMpB,EAAM,QAAQoB,EAAG,MAAM,EAAE,EAC/B,QAASA,EAAG,SAAW,CAAE,OAAQ,CAACA,EAAG,KAAK,EAAG,KAAM,EAAE,CAC/D,EACQ,KAAK,QAAQ,CAACA,EAAG,MAAM,GAAIA,EAAG,QAAQ,CAAC,EAChC3G,GAAY2G,EAAG,MAAM,EAAE,CAChC,CAEA,KAAKjH,EAAG,aAAc,CACpB,MAAM0H,EAAS,KAAK,OAAO,IAAIT,EAAG,EAAE,EAC9B9G,EAAWuH,EAAO,SAClBF,EAAS,KAAK,OAAO,IAAIrH,CAAQ,EACjC0F,EAAQ,KAAK,UAAU1F,CAAQ,EAC/BC,EAAQyF,EAAM,QAAO,EAAG,QAAQoB,EAAG,EAAE,EACrC5G,EAAU,KAAK,gBAAgB4G,EAAG,EAAE,EAC1C,KAAK,eAAeA,EAAG,EAAE,EACzB,MAAMU,EAAc,KAAK,OAAO,KAAI,EACpC,OAAA9B,EAAM,OAAOoB,EAAG,GAAIU,CAAW,EAC/B,KAAK,OAAO,IAAIxH,EAAU,CAAE,GAAGqH,EAAQ,WAAY3B,EAAM,QAAO,CAAE,CAAE,EACpE,KAAK,cAAgB,CAAE,KAAM,aAAc,SAAA1F,EAAU,QAAS8G,EAAG,GAAI,MAAOU,CAAW,EACvF,KAAK,QAAQ,CAACxH,CAAQ,CAAC,EAChB,CAAE,KAAMH,EAAG,aAAc,MAAO0H,EAAQ,SAAAvH,EAAU,MAAAC,EAAO,QAAAC,EAClE,CAEA,KAAKL,EAAG,WAAY,CAElB,MAAM4H,EADS,KAAK,OAAO,IAAIX,EAAG,EAAE,EACR,SACtBY,EAAY,KAAK,UAAUD,CAAY,EACvCE,EAAYD,EAAU,QAAO,EAAG,QAAQZ,EAAG,EAAE,EAQnDY,EAAU,OAAOZ,EAAG,GAAI,KAAK,OAAO,KAAI,CAAE,EAC1C,KAAK,OAAO,IAAIW,EAAc,CAAE,GAAG,KAAK,OAAO,IAAIA,CAAY,EAAG,WAAYC,EAAU,QAAO,CAAE,CAAE,EAEnG,MAAME,EAAU,KAAK,UAAUd,EAAG,UAAU,EACtCe,EAAUD,EAAQ,UAClBrH,EAAUuG,EAAG,SAAWe,EAAQ,OAChCxE,EAAU9C,EAAU,EAAIsH,EAAQtH,EAAU,CAAC,EAAI,KAC/CuH,EAAK,KAAK,OAAO,KAAI,EACvBF,EAAQ,IAAId,EAAG,EAAE,EAGnBc,EAAQ,KAAKd,EAAG,GAAIzD,EAASyE,EAAI,KAAK,OAAO,EAE7CF,EAAQ,OAAOd,EAAG,GAAIzD,EAASyE,EAAI,KAAK,OAAO,EAEjD,KAAK,OAAO,IAAIhB,EAAG,WAAY,CAAE,GAAG,KAAK,OAAO,IAAIA,EAAG,UAAU,EAAG,WAAYc,EAAQ,QAAO,CAAE,CAAE,EAEnG,KAAK,OAAO,IAAId,EAAG,GAAI,CAAE,GAAG,KAAK,OAAO,IAAIA,EAAG,EAAE,EAAG,SAAUA,EAAG,UAAU,CAAE,EAE7E,KAAK,cAAgB,CACnB,KAAM,WACN,aAAAW,EACA,WAAYX,EAAG,WACf,QAASA,EAAG,GACZ,KAAMc,EAAQ,QAAQd,EAAG,EAAE,CACrC,EACQ,MAAMiB,EAAU,IAAI,IAAI,CAACjB,EAAG,GAAIW,EAAcX,EAAG,UAAU,CAAC,EAC5D,YAAK,QAAQiB,CAAO,EACb1H,GAAUyG,EAAG,GAAIW,EAAcE,CAAS,CACjD,CAEA,KAAK9H,EAAG,sBAAuB,CAC7B,MAAME,EAAQ,KAAK,OAAO,IAAI+G,EAAG,OAAO,EAClCkB,EAAqBjI,EAAM,WACjC,YAAK,OAAO,IAAI+G,EAAG,QAAS,CAAE,GAAG/G,EAAO,WAAY+G,EAAG,UAAU,CAAE,EAInE,KAAK,QAAQ,IAAIA,EAAG,QAAS9D,GAAc,UAAU8D,EAAG,WAAY,CAAE,OAAQ,QAAQ,CAAE,CAAC,EACzF,KAAK,cAAgB,KACrB,KAAK,QAAQ,CAACA,EAAG,OAAO,CAAC,EAClB5F,GAAmB4F,EAAG,QAASkB,CAAkB,CAC1D,CAEA,KAAKnI,EAAG,iBAAkB,CACxB,MAAME,EAAQ,KAAK,OAAO,IAAI+G,EAAG,OAAO,EAIlCmB,EAAelI,EAAM,WAAW,QAAQ+G,EAAG,UAAU,CAAC,CAAC,IAAM,GAC7DoB,EAAcD,EAAelI,EAAM,aAAa8G,EAAA9G,EAAM,QAAN,YAAA8G,EAAa,cAAe,GAC5EsB,EAAaD,EAAY,QAAQpB,EAAG,UAAU,CAAC,CAAC,EAEhDsB,EAActB,EAAG,UAAU,IAAK1G,GAAO,KAAK,KAAK,IAAIA,CAAE,CAAC,EAC9D,UAAWA,KAAM0G,EAAG,UAAW,KAAK,KAAK,OAAO1G,CAAE,EAClD,UAAWmF,KAAKuB,EAAG,QAAS,KAAK,KAAK,IAAIvB,EAAE,GAAIA,CAAC,EAEjD,MAAM8C,EAAW,CAAC,GAAGH,CAAW,EAChC,OAAAG,EAAS,OAAOF,EAAYrB,EAAG,UAAU,OAAQ,GAAGA,EAAG,QAAQ,IAAKvB,GAAMA,EAAE,EAAE,CAAC,EAE3E0C,EACF,KAAK,OAAO,IAAInB,EAAG,QAAS,CAAE,GAAG/G,EAAO,WAAYsI,CAAQ,CAAE,EAE9D,KAAK,OAAO,IAAIvB,EAAG,QAAS,CAAE,GAAG/G,EAAO,MAAO,CAAE,GAAGA,EAAM,MAAO,YAAasI,CAAQ,CAAE,CAAE,EAE5F,KAAK,cAAgB,KACrB,KAAK,QAAQ,CAACvB,EAAG,QAAS,GAAGA,EAAG,UAAW,GAAGA,EAAG,QAAQ,IAAKvB,GAAMA,EAAE,EAAE,CAAC,CAAC,EACnElE,GACLyF,EAAG,QACHA,EAAG,QAAQ,IAAKvB,GAAMA,EAAE,EAAE,EAC1B6C,CACV,CACM,CAEA,KAAKvI,EAAG,eAAgB,CACtB,MAAME,EAAQ,KAAK,OAAO,IAAI+G,EAAG,OAAO,EAIlCwB,EAAkBvI,EAAM,OAAS,gBAAiBA,EAAM,MACxDwI,EAAiBD,EAAkBvI,EAAM,MAAM,YAAcA,EAAM,WACnEyI,EAAeD,EAAe,IAAKnI,GAAO,KAAK,KAAK,IAAIA,CAAE,CAAC,EAAE,OAAO,OAAO,EAEjF,UAAWA,KAAMmI,EAAgB,KAAK,KAAK,OAAOnI,CAAE,EACpD,UAAWmF,KAAKuB,EAAG,KAAM,KAAK,KAAK,IAAIvB,EAAE,GAAIA,CAAC,EAC9C,MAAMkD,EAAY3B,EAAG,KAAK,IAAKvB,GAAMA,EAAE,EAAE,EAEzC,OAAI+C,EACF,KAAK,OAAO,IAAIxB,EAAG,QAAS,CAAE,GAAG/G,EAAO,MAAO,CAAE,GAAGA,EAAM,MAAO,YAAa0I,CAAS,CAAE,CAAE,EAE3F,KAAK,OAAO,IAAI3B,EAAG,QAAS,CAAE,GAAG/G,EAAO,WAAY0I,CAAS,CAAE,EAEjE,KAAK,cAAgB,KACrB,KAAK,QAAQ,CAAC3B,EAAG,QAAS,GAAGyB,EAAgB,GAAGE,CAAS,CAAC,EACnDjH,GAAasF,EAAG,QAAS0B,CAAY,CAC9C,CAEA,KAAK3I,EAAG,eACN,YAAK,WAAW,IAAIiH,EAAG,UAAU,GAAIA,EAAG,SAAS,EACjD,KAAK,oBAAsB,KAC3B,KAAK,QAAQ,CAAC3B,EAAe,CAAC,EACvBtD,GAAgBiF,EAAG,UAAU,EAAE,EAGxC,KAAKjH,EAAG,kBAAmB,CACzB,MAAM6I,EAAW,KAAK,WAAW,IAAI5B,EAAG,EAAE,EACpCE,EAAgB,CAAA,EACtB,UAAWE,KAAO,OAAO,KAAKJ,EAAG,KAAK,EAAGE,EAAcE,CAAG,EAAIwB,EAASxB,CAAG,EAC1E,YAAK,WAAW,IAAIJ,EAAG,GAAI,CAAE,GAAG4B,EAAU,GAAG5B,EAAG,KAAK,CAAE,EACvD,KAAK,oBAAsB,KAC3B,KAAK,QAAQ,CAAC3B,EAAe,CAAC,EACvBvD,GAAgBkF,EAAG,GAAIE,CAAa,CAC7C,CAEA,KAAKnH,EAAG,kBAAmB,CACzB,MAAM6I,EAAW,KAAK,WAAW,IAAI5B,EAAG,EAAE,EAC1C,YAAK,WAAW,OAAOA,EAAG,EAAE,EAC5B,KAAK,oBAAsB,KAC3B,KAAK,QAAQ,CAAC3B,EAAe,CAAC,EACvBzD,GAAagH,CAAQ,CAC9B,CAEA,KAAK7I,EAAG,mBACN,YAAK,SAAS,IAAIiH,EAAG,OAAO,GAAIA,EAAG,MAAM,EACzC,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CAAE,KAAM,eAAgB,GAAI,YAAa,OAAQA,EAAG,QACzE,KAAK,QAAQ,CAAC1B,EAAY,CAAC,EACpBpD,GAAoB8E,EAAG,OAAO,EAAE,EAGzC,KAAKjH,EAAG,sBAAuB,CAC7B,MAAM6I,EAAW,KAAK,SAAS,IAAI5B,EAAG,SAAS,EAC/C,YAAK,SAAS,OAAOA,EAAG,SAAS,EACjC,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CAAE,KAAM,eAAgB,GAAI,eAAgB,UAAWA,EAAG,WAC/E,KAAK,QAAQ,CAAC1B,EAAY,CAAC,EACpBtD,GAAiB4G,CAAQ,CAClC,CAEA,KAAK7I,EAAG,kBAAmB,CACzB,MAAMkC,EAAS,KAAK,SAAS,IAAI+E,EAAG,SAAS,EAC7C,YAAK,SAAS,IAAIA,EAAG,UAAW,CAAE,GAAG/E,EAAQ,SAAU,CAAC,GAAGA,EAAO,SAAU+E,EAAG,OAAO,CAAC,CAAE,EACzF,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CAAE,KAAM,eAAgB,GAAI,WAAY,UAAWA,EAAG,UAAW,QAASA,EAAG,OAAO,EACzG,KAAK,QAAQ,CAAC1B,EAAY,CAAC,EACpBhD,GAAmB0E,EAAG,UAAWA,EAAG,QAAQ,EAAE,CACvD,CAEA,KAAKjH,EAAG,qBAAsB,CAC5B,MAAMkC,EAAS,KAAK,SAAS,IAAI+E,EAAG,SAAS,EACvC6B,EAAiB5G,EAAO,SAAS,KAAM6G,GAAMA,EAAE,KAAO9B,EAAG,SAAS,EACxE,YAAK,SAAS,IAAIA,EAAG,UAAW,CAAE,GAAG/E,EAAQ,SAAUA,EAAO,SAAS,OAAQ6G,GAAMA,EAAE,KAAO9B,EAAG,SAAS,CAAC,CAAE,EAC7G,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CAAE,KAAM,eAAgB,GAAI,cAAe,UAAWA,EAAG,UAAW,UAAWA,EAAG,SAAS,EAChH,KAAK,QAAQ,CAAC1B,EAAY,CAAC,EACpBlD,GAAgB4E,EAAG,UAAW6B,CAAc,CACrD,CAEA,KAAK9I,EAAG,gBAAiB,CACvB,MAAMkC,EAAS,KAAK,SAAS,IAAI+E,EAAG,SAAS,EACvC+B,EAAmB9G,EAAO,SAChC,YAAK,SAAS,IAAI+E,EAAG,UAAW,CAAE,GAAG/E,EAAQ,SAAU+E,EAAG,QAAQ,CAAE,EACpE,KAAK,kBAAoB,KACzB,KAAK,cAAgB,CAAE,KAAM,eAAgB,GAAI,UAAW,UAAWA,EAAG,UAAW,SAAUA,EAAG,QAAQ,EAC1G,KAAK,QAAQ,CAAC1B,EAAY,CAAC,EACpB9C,GAAewE,EAAG,UAAW+B,CAAgB,CACtD,CAEA,QACE,MAAM,IAAI,MAAM,2BAA2B/B,EAAG,IAAI,EAAE,CAC5D,CACE,CAGA,gBAAgBgC,EAAK,CACnB,OAAOA,EAAI,IAAKhC,GAAO,KAAK,eAAeA,CAAE,CAAC,CAChD,CASA,iBAAkB,CAChB,OAAO,KAAK,aACd,CAUA,qBAAqBiC,EAAU,SAC7B,GAAKA,EACL,OAAQA,EAAS,KAAI,CACnB,IAAK,aAAc,CACjB,UAAWjG,KAAKiG,EAAS,QAAQ,OAAa,KAAK,OAAO,IAAIjG,EAAE,EAAE,GAAG,KAAK,OAAO,IAAIA,EAAE,GAAIA,CAAC,EAC5F,UAAWyC,KAAKwD,EAAS,QAAQ,KAAW,KAAK,KAAK,IAAIxD,EAAE,EAAE,GAAG,KAAK,KAAK,IAAIA,EAAE,GAAIA,CAAC,EACtF,MAAMG,EAAQ,KAAK,UAAUqD,EAAS,QAAQ,EAC9CrD,EAAM,MAAM,CAACqD,EAAS,IAAI,CAAC,EAC3B,MAAM1B,EAAS,KAAK,OAAO,IAAI0B,EAAS,QAAQ,EAChD,KAAK,OAAO,IAAIA,EAAS,SAAU,CAAE,GAAG1B,EAAQ,WAAY3B,EAAM,QAAO,CAAE,CAAE,EAC7E,KAAK,OAAO,QAAQqD,EAAS,KAAK,KAAK,EACvC,KAAK,QAAQ,CAACA,EAAS,QAASA,EAAS,QAAQ,CAAC,EAClD,MACF,CAEA,IAAK,aAAc,CACjB,MAAMrD,EAAQ,KAAK,UAAUqD,EAAS,QAAQ,EAC1C,KAAK,OAAO,IAAIA,EAAS,OAAO,GAAG,KAAK,eAAeA,EAAS,OAAO,EAC3ErD,EAAM,OAAOqD,EAAS,QAASA,EAAS,KAAK,EACzCA,EAAS,OAAO,KAAK,OAAO,QAAQA,EAAS,KAAK,EACtD,MAAM1B,EAAS,KAAK,OAAO,IAAI0B,EAAS,QAAQ,EAChD,KAAK,OAAO,IAAIA,EAAS,SAAU,CAAE,GAAG1B,EAAQ,WAAY3B,EAAM,QAAO,CAAE,CAAE,EAC7E,KAAK,QAAQ,CAACqD,EAAS,QAAQ,CAAC,EAChC,MACF,CAEA,IAAK,WAAY,CACf,MAAMrB,EAAY,KAAK,UAAUqB,EAAS,YAAY,EAKtDrB,EAAU,OAAOqB,EAAS,SAASlC,EAAAkC,EAAS,OAAT,YAAAlC,EAAe,KAAK,EACvD,KAAK,OAAO,IAAIkC,EAAS,aAAc,CAAE,GAAG,KAAK,OAAO,IAAIA,EAAS,YAAY,EAAG,WAAYrB,EAAU,QAAO,CAAE,CAAE,EAErH,MAAME,EAAU,KAAK,UAAUmB,EAAS,UAAU,EAC5CC,EAAUpB,EAAQ,IAAImB,EAAS,OAAO,EAC5CnB,EAAQ,MAAM,CAACmB,EAAS,IAAI,CAAC,EAMzBC,GAASpB,EAAQ,KAAKmB,EAAS,QAASA,EAAS,KAAK,SAAUA,EAAS,KAAK,MAAOA,EAAS,KAAK,MAAM,EAC7G,KAAK,OAAO,IAAIA,EAAS,WAAY,CAAE,GAAG,KAAK,OAAO,IAAIA,EAAS,UAAU,EAAG,WAAYnB,EAAQ,QAAO,CAAE,CAAE,EAE3G,KAAK,OAAO,IAAImB,EAAS,OAAO,GAClC,KAAK,OAAO,IAAIA,EAAS,QAAS,CAAE,GAAG,KAAK,OAAO,IAAIA,EAAS,OAAO,EAAG,SAAUA,EAAS,UAAU,CAAE,EAE3G,KAAK,OAAO,QAAQA,EAAS,KAAK,KAAK,EACvC,KAAK,QAAQ,CAACA,EAAS,QAASA,EAAS,aAAcA,EAAS,UAAU,CAAC,EAC3E,MACF,CAEA,IAAK,aAAc,CACjB,GAAIA,EAAS,SAAW,MAAO,CAC7B,MAAMnD,EAAM,KAAK,KAAK,IAAImD,EAAS,EAAE,EACrC,GAAInD,EAAK,CACP,MAAMnF,EAAQ,CAAA,EACd,UAAWyG,KAAO,OAAO,KAAK6B,EAAS,KAAK,EAAG,CAC7C,MAAMxE,EAAcwE,EAAS,OAAO7B,CAAG,EAClC,KAAK,aAAa,kBAAkB6B,EAAS,GAAI7B,EAAK3C,CAAW,IACtE9D,EAAMyG,CAAG,EAAI6B,EAAS,MAAM7B,CAAG,EAC/B,KAAK,aAAa,aAAa6B,EAAS,GAAI7B,EAAK3C,CAAW,EAC9D,CACI,OAAO,KAAK9D,CAAK,EAAE,OAAS,IAC9B,KAAK,KAAK,IAAIsI,EAAS,GAAI,CAAE,GAAGnD,EAAK,GAAGnF,CAAK,CAAE,EAC/C,KAAK,QAAQ,CAACsI,EAAS,EAAE,CAAC,EAE9B,CACF,SAAWA,EAAS,SAAW,aAAc,CAC3C,MAAMhJ,EAAQ,KAAK,OAAO,IAAIgJ,EAAS,EAAE,EACzC,GAAIhJ,EAAO,CACT,MAAMU,EAAQ,CAAA,EACd,UAAWyG,KAAO,OAAO,KAAK6B,EAAS,KAAK,EAAG,CAC7C,MAAMxE,EAAcwE,EAAS,OAAO7B,CAAG,EAClC,KAAK,aAAa,kBAAkB6B,EAAS,GAAI,SAAS7B,CAAG,GAAI3C,CAAW,IACjF9D,EAAMyG,CAAG,EAAI6B,EAAS,MAAM7B,CAAG,EAC/B,KAAK,aAAa,aAAa6B,EAAS,GAAI,SAAS7B,CAAG,GAAI3C,CAAW,EACzE,CACI,OAAO,KAAK9D,CAAK,EAAE,OAAS,IAC9B,KAAK,OAAO,IAAIsI,EAAS,GAAI,CAAE,GAAGhJ,EAAO,MAAO,CAAE,GAAGA,EAAM,MAAO,GAAGU,CAAK,CAAE,CAAE,EAC9E,KAAK,QAAQ,CAACsI,EAAS,EAAE,CAAC,EAE9B,CACF,SAAWA,EAAS,SAAW,YAAa,CAC1C,MAAMhJ,EAAQ,KAAK,OAAO,IAAIgJ,EAAS,EAAE,EACrChJ,GAAS,KAAK,aAAa,kBAAkBgJ,EAAS,GAAI,OAAQA,EAAS,KAAK,IAClF,KAAK,aAAa,aAAaA,EAAS,GAAI,OAAQA,EAAS,KAAK,EAClE,KAAK,OAAO,IAAIA,EAAS,GAAI,CAAE,GAAGhJ,EAAO,KAAMgJ,EAAS,UAAW,MAAOA,EAAS,KAAK,CAAE,EAC1F,KAAK,QAAQ,CAACA,EAAS,EAAE,CAAC,EAE9B,CACA,UAAWjB,KAAM,OAAO,OAAOiB,EAAS,QAAU,CAAA,CAAE,EAAG,KAAK,OAAO,QAAQjB,CAAE,EACzEiB,EAAS,OAAO,KAAK,OAAO,QAAQA,EAAS,KAAK,EACtD,MACF,CAEA,IAAK,cAAe,CAClB,MAAMrD,EAAQ,KAAK,aAAaqD,EAAS,KAAK,EACxClD,EAAQ,KAAK,UAAU,IAAIkD,EAAS,KAAK,EAC/C,UAAWtD,KAAKsD,EAAS,cAClBrD,EAAM,IAAID,EAAE,EAAE,GAAGI,EAAM,IAAIJ,EAAE,GAAIA,EAAE,IAAI,EAC5CC,EAAM,OAAOD,EAAE,GAAIA,EAAE,QAASA,EAAE,OAAOwD,EAAAxD,EAAE,QAAF,YAAAwD,EAAS,MAAM,EAExD,UAAW5C,KAAK0C,EAAS,eAAgBrD,EAAM,OAAOW,EAAE,GAAIA,EAAE,KAAK,EACnE,KAAK,mBAAmB,OAAO0C,EAAS,KAAK,EAC7C,MAAMnD,EAAM,KAAK,KAAK,IAAImD,EAAS,KAAK,EACpCnD,IACF,KAAK,KAAK,IAAImD,EAAS,MAAO,CAAE,GAAGnD,EAAK,MAAO,KAAK,qBAAqBmD,EAAS,KAAK,CAAC,CAAE,EAC1F,KAAK,QAAQ,CAACA,EAAS,KAAK,CAAC,GAE/B,KAAK,OAAO,QAAQA,EAAS,KAAK,EAClC,MACF,CAEA,IAAK,cAAe,CAClB,MAAMrD,EAAQ,KAAK,aAAaqD,EAAS,KAAK,EAC9C,UAAWhD,KAAUgD,EAAS,aAAcrD,EAAM,OAAOK,EAAQgD,EAAS,KAAK,EAC/E,UAAWhD,KAAUgD,EAAS,WAAYrD,EAAM,QAAQK,CAAM,EAC9D,KAAK,mBAAmB,OAAOgD,EAAS,KAAK,EAC7C,MAAMnD,EAAM,KAAK,KAAK,IAAImD,EAAS,KAAK,EACpCnD,IACF,KAAK,KAAK,IAAImD,EAAS,MAAO,CAAE,GAAGnD,EAAK,MAAO,KAAK,qBAAqBmD,EAAS,KAAK,CAAC,CAAE,EAC1F,KAAK,QAAQ,CAACA,EAAS,KAAK,CAAC,GAE/B,KAAK,OAAO,QAAQA,EAAS,KAAK,EAClC,MACF,CAEA,IAAK,eAAgB,CAQnB,GAAIA,EAAS,KAAO,YACb,KAAK,SAAS,IAAIA,EAAS,OAAO,EAAE,IACvC,KAAK,SAAS,IAAIA,EAAS,OAAO,GAAIA,EAAS,MAAM,EACrD,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAAC3D,EAAY,CAAC,WAEpB2D,EAAS,KAAO,eACrB,KAAK,SAAS,OAAOA,EAAS,SAAS,IACzC,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAAC3D,EAAY,CAAC,WAEpB2D,EAAS,KAAO,WAAY,CACrC,MAAMhH,EAAS,KAAK,SAAS,IAAIgH,EAAS,SAAS,EAC/ChH,GAAU,CAACA,EAAO,SAAS,KAAM6G,GAAMA,EAAE,KAAOG,EAAS,QAAQ,EAAE,IACrE,KAAK,SAAS,IAAIA,EAAS,UAAW,CAAE,GAAGhH,EAAQ,SAAU,CAAC,GAAGA,EAAO,SAAUgH,EAAS,OAAO,CAAC,CAAE,EACrG,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAAC3D,EAAY,CAAC,EAE/B,SAAW2D,EAAS,KAAO,cAAe,CACxC,MAAMhH,EAAS,KAAK,SAAS,IAAIgH,EAAS,SAAS,EAC/ChH,GAAUA,EAAO,SAAS,KAAM6G,GAAMA,EAAE,KAAOG,EAAS,SAAS,IACnE,KAAK,SAAS,IAAIA,EAAS,UAAW,CAAE,GAAGhH,EAAQ,SAAUA,EAAO,SAAS,OAAQ6G,GAAMA,EAAE,KAAOG,EAAS,SAAS,CAAC,CAAE,EACzH,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAAC3D,EAAY,CAAC,EAE/B,SAAW2D,EAAS,KAAO,UAAW,CACpC,MAAMhH,EAAS,KAAK,SAAS,IAAIgH,EAAS,SAAS,EAC/ChH,IACF,KAAK,SAAS,IAAIgH,EAAS,UAAW,CAAE,GAAGhH,EAAQ,SAAUgH,EAAS,QAAQ,CAAE,EAChF,KAAK,kBAAoB,KACzB,KAAK,QAAQ,CAAC3D,EAAY,CAAC,EAE/B,CACA,MACF,CAEA,QACE,MAAM,IAAI,MAAM,iCAAiC2D,EAAS,IAAI,EAAE,CACxE,CACE,CAGA,mBAAoB,CAClB,IAAIpF,EAAQ,EACZ,UAAW+B,KAAS,KAAK,QAAQ,OAAM,EAAI/B,GAAS+B,EAAM,iBAC1D,UAAWA,KAAS,KAAK,WAAW,OAAM,EAAI/B,GAAS+B,EAAM,iBAC7D,OAAO/B,CACT,CAaA,gBAAgB,CAAE,SAAAuF,EAAW,GAAK,GAAK,GAAK,IAAM,IAAAxG,EAAM,KAAK,IAAG,CAAE,EAAK,CAAA,EAAI,CACzE,MAAMyG,EAAY,CAAE,SAAUzG,EAAMwG,EAAU,QAAS,EAAG,OAAQ,IAClE,IAAIrF,EAAU,EACd,UAAW6B,KAAS,KAAK,QAAQ,SAAU7B,GAAW6B,EAAM,gBAAgByD,CAAS,EASrF,UAAWzD,KAAS,KAAK,WAAW,SAAU7B,GAAW6B,EAAM,gBAAgByD,CAAS,EACxF,OAAOtF,CACT,CAEA,QAAS,CACP,MAAO,CACL,OAAQ,CAAC,GAAG,KAAK,OAAO,OAAM,CAAE,EAChC,KAAM,CAAC,GAAG,KAAK,KAAK,OAAM,CAAE,EAC5B,OAAQ,KAAK,OACb,WAAY,CAAC,GAAG,KAAK,WAAW,OAAM,CAAE,EACxC,SAAU,CAAC,GAAG,KAAK,SAAS,OAAM,CAAE,CAC1C,CACE,CAEA,OAAO,SAASyB,EAAK,CACnB,OAAO,IAAID,GAAYC,CAAG,CAC5B,CACF,CCp6BA,MAAM8D,GAAU,IAehB,SAASC,GAAiB3E,EAAUC,EAAU,CAC5C,MAAM9B,EAAI6B,GAAY,GAChB5B,EAAI6B,GAAY,GACtB,IAAIG,EAAQ,EACZ,MAAMC,EAAW,KAAK,IAAIlC,EAAE,OAAQC,EAAE,MAAM,EAC5C,KAAOgC,EAAQC,GAAYlC,EAAEiC,CAAK,IAAMhC,EAAEgC,CAAK,GAAGA,GAAS,EAC3D,IAAIwE,EAAOzG,EAAE,OACT0G,EAAOzG,EAAE,OACb,KAAOwG,EAAOxE,GAASyE,EAAOzE,GAASjC,EAAEyG,EAAO,CAAC,IAAMxG,EAAEyG,EAAO,CAAC,GAC/DD,GAAQ,EACRC,GAAQ,EAEV,MAAO,CAAE,aAAcD,EAAM,YAAaC,CAAI,CAChD,CAmBA,SAASC,GAAyBC,EAAS,OACzC,IAAIA,GAAA,YAAAA,EAAS,QAAS,aAAe,QAAO5C,EAAA4C,EAAQ,QAAR,YAAA5C,EAAe,QAAU,SAAU,OAAO4C,EAAQ,MAAM,MACpG,IAAIA,GAAA,YAAAA,EAAS,QAAS,gBAAkB,OAAOA,EAAQ,eAAkB,SAAU,OAAOA,EAAQ,aAEpG,CAEA,SAASC,GAAsBC,EAAO,OACpC,GAAI,CAACA,EAAM,IAAI,QAAU,CAACA,EAAM,SAAS,OAAQ,OAAO,KACxD,MAAMC,EAAUD,EAAM,IAAI,CAAC,EACrBE,EAASF,EAAM,IAAIA,EAAM,IAAI,OAAS,CAAC,EAE7C,GADIC,EAAQ,OAAS,aAAeC,EAAO,OAAS,aAAeD,EAAQ,KAAOC,EAAO,IACrF,QAAOhD,EAAAgD,EAAO,QAAP,YAAAhD,EAAc,QAAU,SAAU,OAAO,KAIpD,MAAMiD,EAAgBH,EAAM,SAASA,EAAM,SAAS,OAAS,CAAC,EACxD1I,EAAgBuI,GAAyBM,CAAa,EAC5D,GAAI7I,IAAkB,OAAW,OAAO,KAExC,KAAM,CAAE,aAAA8I,EAAc,YAAAC,GAAgBX,GAAiBpI,EAAe4I,EAAO,MAAM,KAAK,EACxF,MAAO,CAAE,MAAOD,EAAQ,GAAI,aAAAG,EAAc,YAAAC,CAAW,CACvD,CAgBA,SAASC,GAAwBN,EAAO,CACtC,MAAM1G,EAAM,CAAA,EACNiH,EAAWpD,GAAO,OACjBA,KACDD,EAAAC,EAAG,QAAH,MAAAD,EAAU,IAAI5D,EAAI,KAAK6D,EAAG,MAAM,EAAE,EAClCA,EAAG,SAAS7D,EAAI,KAAK6D,EAAG,OAAO,EAC/BA,EAAG,IAAI7D,EAAI,KAAK6D,EAAG,EAAE,EACrBA,EAAG,UAAU7D,EAAI,KAAK6D,EAAG,QAAQ,EACjCA,EAAG,YAAY7D,EAAI,KAAK6D,EAAG,UAAU,EAC3C,EACA,UAAWA,KAAM6C,EAAM,IAAKO,EAAQpD,CAAE,EACtC,UAAW2C,KAAWE,EAAM,SAAUO,EAAQT,CAAO,EACrD,MAAO,CAAC,GAAG,IAAI,IAAIxG,CAAG,CAAC,CACzB,CAoBO,MAAMkH,EAAQ,CACnB,YAAYC,EAAO,CAAE,OAAAC,EAASjB,GAAS,aAAAkB,EAAe,GAAO,iBAAAC,EAAmB,IAAK,eAAAC,EAAiB,IAAI,EAAK,CAAA,EAAI,CACjH,KAAK,MAAQJ,EACb,KAAK,OAASC,EAWd,KAAK,eAAiBG,EACtB,KAAK,UAAY,GACjB,KAAK,UAAY,GACjB,KAAK,aAAe,KACpB,KAAK,UAAY,KACjB,KAAK,WAAa,GAClB,KAAK,WAAa,IAAI,IACtB,KAAK,kBAAoB,CAAE,QAAS,GAAO,QAAS,IACpD,KAAK,kBAAoB,KACzB,KAAK,yBAA2B,GAOhC,KAAK,aAAeF,EACpB,KAAK,iBAAmBC,EACxB,KAAK,UAAY,EACnB,CAYA,cAAczD,EAAI2C,EAASgB,EAAM,OAC/B,GAAI,CAAC,KAAK,aAAc,OACxB,MAAMC,EAAW5D,EAAG,QAAU,SAAa2C,GAAA,YAAAA,EAAS,SAAU,OAIxDxI,EAAgByJ,EAAW,OAAYlB,GAAyBC,CAAO,EAC7E,KAAK,UAAU,KAAK,CAClB,OAAQ3C,EAAG,KACX,GAAIA,EAAG,IAAMA,EAAG,WAAWD,EAAAC,EAAG,QAAH,YAAAD,EAAU,IACrC,OAAQ6D,EAAWjB,EAAQ,MAAQxI,IAAkB,OAAY,CAAE,MAAOA,CAAa,EAAK,OAC5F,MAAOyJ,GAAsBzJ,IAAkB,OAA7B6F,EAAG,MAAiD,OACtE,QAAS2D,EAAK,SAAW,KACzB,UAAWA,EAAK,WAAa,KAAK,IAAG,CAC3C,CAAK,EACG,KAAK,UAAU,OAAS,KAAK,kBAAkB,KAAK,UAAU,OACpE,CASA,cAAe,CACb,MAAO,CAAC,GAAG,KAAK,SAAS,CAC3B,CAQA,qBAAsB,CACpB,OAAO,KAAK,iBACd,CAUA,4BAA6B,CAC3B,OAAO,KAAK,wBACd,CAOA,qBAAsB,CACpB,MAAME,EAAU,KAAK,UACfC,EAAU,KAAK,UACrB,OAAI,KAAK,kBAAkB,UAAYD,GAAW,KAAK,kBAAkB,UAAYC,KACnF,KAAK,kBAAoB,CAAE,QAAAD,EAAS,QAAAC,CAAO,GAEtC,KAAK,iBACd,CAGA,SAASxK,EAAI,CACX,OAAO,KAAK,MAAM,SAASA,CAAE,CAC/B,CAEA,OAAOA,EAAI,CACT,OAAO,KAAK,MAAM,OAAOA,CAAE,CAC7B,CAEA,WAAY,CACV,OAAO,KAAK,MAAM,WACpB,CAEA,eAAgB,CACd,OAAO,KAAK,MAAM,eACpB,CAEA,aAAaA,EAAI,CACf,OAAO,KAAK,MAAM,aAAaA,CAAE,CACnC,CAEA,aAAc,CACZ,OAAO,KAAK,MAAM,aACpB,CAEA,WAAWA,EAAI,CACb,OAAO,KAAK,MAAM,WAAWA,CAAE,CACjC,CAEA,cAAe,CACb,OAAO,KAAK,MAAM,cACpB,CAEA,UAAUA,EAAIkG,EAAU,CACtB,OAAO,KAAK,MAAM,UAAUlG,EAAIkG,CAAQ,CAC1C,CAEA,aAAaA,EAAU,CACrB,OAAO,KAAK,MAAM,aAAaA,CAAQ,CACzC,CAQA,mBAAoB,CAClB,OAAO,KAAK,MAAM,mBACpB,CAEA,gBAAgBuE,EAAS,CACvB,OAAO,KAAK,MAAM,gBAAgBA,CAAO,CAC3C,CAEA,QAAS,CACP,OAAO,KAAK,MAAM,QACpB,CAGA,eAAe/D,EAAI2D,EAAO,GAAI,CAC5B,OAAO,KAAK,QAAQ3D,EAAI2D,CAAI,CAC9B,CAEA,gBAAgB3B,EAAK2B,EAAO,GAAI,CAC9B,OAAO3B,EAAI,IAAKhC,GAAO,KAAK,QAAQA,EAAI2D,CAAI,CAAC,CAC/C,CAUA,kBAAkBK,EAAS,CACzB,KAAK,eAAiBA,CACxB,CAEA,aAAahC,EAAK2B,EAAO,GAAI,OAC3B,MAAMK,EAAUL,EAAK,SAAW,KAAK,eAC/BM,EAAYN,EAAK,WAAa,KAAK,IAAG,EAC5C,KAAK,oBAAmB,EAExB,MAAMO,EAAW,CAAA,EACjB,UAAWlE,KAAMgC,EAAK,CACpB,MAAMW,EAAU,KAAK,MAAM,eAAe3C,CAAE,EAC5CkE,EAAS,QAAQvB,CAAO,EACxB,KAAK,WAAW,KAAK,CAAE,OAAQ3C,EAAG,KAAM,GAAIA,EAAG,IAAMA,EAAG,WAAWD,EAAAC,EAAG,QAAH,YAAAD,EAAU,IAAI,QAAAiE,EAAS,UAAAC,CAAS,CAAE,EACrG,KAAK,cAAcjE,EAAI2C,EAAS,CAAE,QAAAqB,EAAS,UAAAC,CAAS,CAAE,CACxD,CAEA,KAAK,UAAY,GACjB,KAAK,UAAU,KAAK,CAClB,IAAK,CAAC,GAAGjC,CAAG,EACZ,SAAAkC,EACA,SAAU,KACV,QAAAF,EACA,UAAAC,EACA,cAAeA,EACf,YAAa,EACnB,CAAK,EACD,KAAK,QAAO,CACd,CAEA,QAAQjE,EAAI2D,EAAO,GAAI,CACrB,MAAMK,EAAUL,EAAK,SAAW,KAAK,eAC/BM,EAAYN,EAAK,WAAa,KAAK,IAAG,EACtChB,EAAU,KAAK,MAAM,eAAe3C,CAAE,EAC5C,YAAK,QAAQA,EAAI2C,EAAS,CAAE,QAAAqB,EAAS,UAAAC,CAAS,CAAE,EACzCtB,CACT,CAEA,aAAa3C,EAAI,CAEf,OAAOA,EAAG,OAAS,YAAc,OAAOA,EAAG,EAAE,GAAK,IACpD,CAEA,gBAAgBA,EAAI,OAClB,GAAIA,EAAG,OAAS,YAAa,MAAO,GACpC,MAAMd,GAAQa,EAAAC,EAAG,QAAH,YAAAD,EAAU,MACxB,OAAI,OAAOb,GAAU,UAAYA,EAAM,SAAW,EAAU,GACrD,KAAK,KAAKA,EAAMA,EAAM,OAAS,CAAC,CAAC,CAC1C,CAEA,QAAQc,EAAI2C,EAASgB,EAAM,OACzB,KAAK,UAAY,GACjB,MAAMQ,EAAW,KAAK,aAAanE,CAAE,EAC/BoE,EAAa,KAAK,cAAgBT,EAAK,UAAY,KAAK,aAAa,eAAiB,KAAK,OAE/F,KAAK,cACLQ,IAAa,MACb,KAAK,aAAa,WAAaA,GAC/BC,GACA,CAAC,KAAK,aAAa,aAGnB,KAAK,aAAa,IAAI,KAAKpE,CAAE,EAC7B,KAAK,aAAa,SAAS,QAAQ2C,CAAO,EAC1C,KAAK,aAAa,cAAgBgB,EAAK,UACnC,KAAK,gBAAgB3D,CAAE,IAAG,KAAK,aAAa,YAAc,MAE9D,KAAK,oBAAmB,EACxB,KAAK,aAAe,CAClB,IAAK,CAACA,CAAE,EACR,SAAU,CAAC2C,CAAO,EAClB,SAAAwB,EACA,QAASR,EAAK,QACd,UAAWA,EAAK,UAChB,cAAeA,EAAK,UACpB,YAAa,KAAK,gBAAgB3D,CAAE,CAC5C,GAGI,KAAK,gBAAe,EACpB,KAAK,WAAW,KAAK,CACnB,OAAQA,EAAG,KACX,GAAIA,EAAG,MAAMD,EAAAC,EAAG,QAAH,YAAAD,EAAU,IACvB,QAAS4D,EAAK,QACd,UAAWA,EAAK,SACtB,CAAK,EACD,KAAK,cAAc3D,EAAI2C,EAASgB,CAAI,EACpC,KAAK,QAAO,CACd,CAEA,iBAAkB,CACZ,KAAK,WAAW,aAAa,KAAK,SAAS,EAC/C,KAAK,UAAY,WAAW,IAAM,CAChC,KAAK,oBAAmB,EACxB,KAAK,QAAO,CACd,EAAG,KAAK,MAAM,CAChB,CAEA,qBAAsB,CACf,KAAK,eACV,KAAK,UAAU,KAAK,KAAK,YAAY,EACrC,KAAK,aAAe,KAChB,KAAK,YACP,aAAa,KAAK,SAAS,EAC3B,KAAK,UAAY,MAErB,CAGA,OAAQ,CACN,KAAK,oBAAmB,EACxB,KAAK,QAAO,CACd,CAEA,MAAO,CACL,KAAK,oBAAmB,EACxB,MAAMd,EAAQ,KAAK,UAAU,IAAG,EAChC,GAAI,CAACA,EAAO,MAAO,GACnB,UAAWF,KAAWE,EAAM,SAAU,KAAK,MAAM,eAAeF,CAAO,EACvE,KAAK,UAAU,KAAKE,CAAK,EACzB,MAAMwB,EAAYzB,GAAsBC,CAAK,EAC7C,YAAK,kBAAoBwB,EAAY,CAAE,MAAOA,EAAU,MAAO,OAAQA,EAAU,YAAY,EAAK,KAClG,KAAK,yBAA2BlB,GAAwBN,CAAK,EAC7D,KAAK,QAAO,EACL,EACT,CAEA,MAAO,CACL,MAAMA,EAAQ,KAAK,UAAU,IAAG,EAChC,GAAI,CAACA,EAAO,MAAO,GACnB,UAAW7C,KAAM6C,EAAM,IAAK,KAAK,MAAM,eAAe7C,CAAE,EACxD,KAAK,UAAU,KAAK6C,CAAK,EACzB,MAAMwB,EAAYzB,GAAsBC,CAAK,EAC7C,YAAK,kBAAoBwB,EAAY,CAAE,MAAOA,EAAU,MAAO,OAAQA,EAAU,WAAW,EAAK,KACjG,KAAK,yBAA2BlB,GAAwBN,CAAK,EAC7D,KAAK,QAAO,EACL,EACT,CAEA,SAAU,CACR,OAAO,KAAK,UAAU,OAAS,GAAK,KAAK,eAAiB,IAC5D,CAEA,SAAU,CACR,OAAO,KAAK,UAAU,OAAS,CACjC,CAGA,eAAgB,CACd,MAAO,CAAC,GAAG,KAAK,UAAU,CAC5B,CAEA,mBAAmBrD,EAAU,CAC3B,YAAK,WAAW,IAAIA,CAAQ,EACrB,IAAM,KAAK,WAAW,OAAOA,CAAQ,CAC9C,CAEA,SAAU,CACR,UAAWA,KAAY,KAAK,WAAYA,EAAQ,CAClD,CACF,CC/cA,MAAM8E,GAAsB,GAAK,GAAK,IAChCC,GAAqB,GAAK,GAAK,GAAK,IAanC,SAASC,GAA0B,CAAE,MAAAlB,EAAO,WAAAmB,EAAaH,GAAqB,SAAAlC,EAAWmC,GAAoB,QAAAG,EAAS,QAAAC,GAAW,CACtI,MAAMC,EAAQ,YAAY,IAAM,CAC9B,GAAI,CACF,MAAM7H,EAAUuG,EAAM,gBAAgB,CAAE,SAAAlB,CAAQ,CAAE,EAC9CrF,EAAU,IAAG2H,GAAA,MAAAA,EAAU3H,GAC7B,OAAS8H,EAAK,CACZF,GAAA,MAAAA,EAAUE,EACZ,CACF,EAAGJ,CAAU,EAEb,MAAO,CACL,MAAO,CACL,cAAcG,CAAK,CACrB,CACJ,CACA,CC7BY,MAACE,GAAe,CAC1B,MAAO,QACP,GAAI,KACJ,aAAc,cACd,cAAe,eACf,SAAU,UACZ,EAEO,SAASC,GAAc1J,EAAS,CACrC,OAAO,KAAK,UAAUA,CAAO,CAC/B,CAEO,SAAS2J,GAAcC,EAAK,CACjC,MAAM5J,EAAU,KAAK,MAAM4J,CAAG,EAC9B,GAAI,CAAC5J,GAAW,OAAOA,EAAQ,MAAS,SAAU,MAAM,IAAI,MAAM,oCAAoC,EACtG,OAAOA,CACT,CAGO,SAAS6J,GAAavJ,EAAQ,CACnC,MAAO,CAAE,KAAMmJ,GAAa,MAAO,OAAAnJ,CAAM,CAC3C,CAGO,SAASwJ,GAAUlD,EAAU,CAClC,MAAO,CAAE,KAAM6C,GAAa,GAAI,SAAA7C,CAAQ,CAC1C,CAGO,SAASmD,IAAqB,CACnC,MAAO,CAAE,KAAMN,GAAa,YAAY,CAC1C,CAGO,SAASO,GAAoB7G,EAAK,CACvC,MAAO,CAAE,KAAMsG,GAAa,cAAe,IAAAtG,CAAG,CAChD,CAUO,SAAS8G,GAAgB3J,EAAQ4J,EAAM,CAC5C,MAAO,CAAE,KAAMT,GAAa,SAAU,OAAAnJ,EAAQ,KAAA4J,CAAI,CACpD,CChDA,MAAMC,GAAa,gBACbC,GAAqB,CAAE,WAAY,CAAC,CAAE,KAAM,8BAA8B,CAAE,CAAC,EAU7EC,GAAoB,KAWpBC,GAAiC,IACjCC,GAAgC,MAEtC,SAASC,IAAe,CACtB,MAAO,GAAG,KAAK,IAAG,EAAG,SAAS,EAAE,CAAC,IAAI,KAAK,OAAM,EAAG,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,EAC1E,CAaO,MAAMC,EAAe,CAC1B,YAAY,CAAE,UAAAC,EAAW,aAAAC,EAAc,UAAAC,EAAW,UAAAC,EAAYT,IAAsB,CAClF,KAAK,aAAeO,EACpB,KAAK,WAAaD,EAClB,KAAK,IAAM,IAAI,kBAAkBG,CAAS,EAC1C,KAAK,SAAW,KAChB,KAAK,eAAiB,IAAI,IAC1B,KAAK,gBAAkB,IAAI,IAC3B,KAAK,kBAAoB,IAAI,IAC7B,KAAK,cAAgB,IAAI,IACzB,KAAK,WAAa,GAClB,KAAK,SAAW,GAEhB,KAAK,IAAI,eAAkBC,GAAU,CAO/BA,EAAM,WAAW,KAAK,WAAW,KAAKH,EAAc,CAAE,KAAM,MAAO,UAAWG,EAAM,UAAU,OAAM,CAAE,CAAE,CAC9G,EAEIF,GACF,KAAK,aAAa,KAAK,IAAI,kBAAkBT,EAAU,CAAC,EACxD,KAAK,IACF,YAAW,EACX,KAAMY,GAAU,KAAK,IAAI,oBAAoBA,CAAK,EAAE,KAAK,IAAMA,CAAK,CAAC,EACrE,KAAMA,GAAU,KAAK,WAAW,KAAKJ,EAAc,CAAE,KAAM,QAAS,IAAKI,CAAK,CAAE,CAAC,GAEpF,KAAK,IAAI,cAAiBD,GAAU,KAAK,aAAaA,EAAM,OAAO,EAGrE,KAAK,sBAAwBJ,EAAU,UAAU,CAACM,EAAYhL,IAAY,CACpEgL,IAAeL,GACnB,KAAK,cAAc3K,CAAO,CAC5B,CAAC,CACH,CAEA,MAAM,cAAcA,EAAS,CAC3B,GAAIA,EAAQ,OAAS,QAAS,CAC5B,MAAM,KAAK,IAAI,qBAAqBA,EAAQ,GAAG,EAC/C,MAAMiL,EAAS,MAAM,KAAK,IAAI,aAAY,EAC1C,MAAM,KAAK,IAAI,oBAAoBA,CAAM,EACzC,KAAK,WAAW,KAAK,KAAK,aAAc,CAAE,KAAM,SAAU,IAAKA,EAAQ,CACzE,SAAWjL,EAAQ,OAAS,SAC1B,MAAM,KAAK,IAAI,qBAAqBA,EAAQ,GAAG,UACtCA,EAAQ,OAAS,MAC1B,GAAI,CACF,MAAM,KAAK,IAAI,gBAAgBA,EAAQ,SAAS,CAClD,MAAQ,CAGR,CAEJ,CAEA,aAAakL,EAAS,CACpB,KAAK,SAAWA,EAChBA,EAAQ,2BAA6BX,GACrCW,EAAQ,OAAS,IAAM,CACrB,UAAWC,KAAM,KAAK,eAAgBA,EAAE,CAC1C,EACAD,EAAQ,QAAU,IAAM,CACtB,UAAWC,KAAM,KAAK,gBAAiBA,EAAE,CAC3C,EACAD,EAAQ,UAAaJ,GAAU,KAAK,kBAAkBA,EAAM,IAAI,CAClE,CAUA,kBAAkBlB,EAAK,CACrB,GAAI,OAAOA,GAAQ,UAAYA,EAAI,SAAW,EAAG,OACjD,MAAMwB,EAASxB,EAAI,CAAC,EACpB,GAAIwB,IAAW,IAAK,CAClB,UAAWD,KAAM,KAAK,kBAAmBA,EAAGvB,EAAI,MAAM,CAAC,CAAC,EACxD,MACF,CACA,GAAIwB,IAAW,IAAK,OAEpB,MAAMC,EAAOzB,EAAI,MAAM,CAAC,EAClB0B,EAAaD,EAAK,QAAQ,GAAG,EAC7BE,EAAcF,EAAK,QAAQ,IAAKC,EAAa,CAAC,EAC9CE,EAAaH,EAAK,QAAQ,IAAKE,EAAc,CAAC,EACpD,GAAID,IAAe,IAAMC,IAAgB,IAAMC,IAAe,GAAI,OAClE,MAAMtL,EAAYmL,EAAK,MAAM,EAAGC,CAAU,EACpCxN,EAAQ,OAAOuN,EAAK,MAAMC,EAAa,EAAGC,CAAW,CAAC,EACtDE,EAAQ,OAAOJ,EAAK,MAAME,EAAc,EAAGC,CAAU,CAAC,EACtDE,EAAQL,EAAK,MAAMG,EAAa,CAAC,EAEvC,IAAIG,EAAS,KAAK,cAAc,IAAIzL,CAAS,EAM7C,GALKyL,IACHA,EAAS,CAAE,MAAAF,EAAO,SAAU,IAAI,GAAK,EACrC,KAAK,cAAc,IAAIvL,EAAWyL,CAAM,GAE1CA,EAAO,SAAS,IAAI7N,EAAO4N,CAAK,EAC5BC,EAAO,SAAS,KAAOA,EAAO,MAAO,OAEzC,KAAK,cAAc,OAAOzL,CAAS,EACnC,IAAI0L,EAAO,GACX,QAAS3J,EAAI,EAAGA,EAAI0J,EAAO,MAAO1J,GAAK,EAAG2J,GAAQD,EAAO,SAAS,IAAI1J,CAAC,EACvE,UAAWkJ,KAAM,KAAK,kBAAmBA,EAAGS,CAAI,CAClD,CAWA,KAAKhC,EAAK,OACR,KAAIlF,EAAA,KAAK,WAAL,YAAAA,EAAe,cAAe,OAClC,IAAIkF,EAAI,QAAUS,GAChB,KAAK,WAAW,KAAK,IAAIT,CAAG,EAAE,MACzB,CACL,MAAM1J,EAAYsK,GAAY,EACxBiB,EAAQ,KAAK,KAAK7B,EAAI,OAASS,EAAiB,EACtD,QAASvM,EAAQ,EAAGA,EAAQ2N,EAAO3N,GAAS,EAAG,CAC7C,MAAM4N,EAAQ9B,EAAI,MAAM9L,EAAQuM,IAAoBvM,EAAQ,GAAKuM,EAAiB,EAClF,KAAK,WAAW,KAAK,IAAInK,CAAS,IAAIpC,CAAK,IAAI2N,CAAK,IAAIC,CAAK,EAAE,CACjE,CACF,CACA,KAAK,eAAc,EACrB,CAGA,MAAM,gBAAiB,CACrB,GAAI,MAAK,SACT,MAAK,SAAW,GAChB,GAAI,CACF,KAAO,KAAK,WAAW,OAAS,GAAG,CACjC,GAAI,CAAC,KAAK,UAAY,KAAK,SAAS,aAAe,OAAQ,CACzD,KAAK,WAAW,OAAS,EACzB,KACF,CACA,GAAI,KAAK,SAAS,eAAiBpB,GAAgC,CACjE,MAAM,KAAK,0BAAyB,EACpC,QACF,CACA,MAAMuB,EAAQ,KAAK,WAAW,MAAK,EACnC,GAAI,CACF,KAAK,SAAS,KAAKA,CAAK,CAC1B,OAASrC,EAAK,CAEZ,QAAQ,KAAK,mDAAoD,KAAK,aAAcA,CAAG,EAKvF,KAAK,WAAW,OAAS,EACzB,KACF,CACF,CACF,QAAC,CACC,KAAK,SAAW,EAClB,EACF,CAEA,2BAA4B,CAC1B,OAAO,IAAI,QAASsC,GAAY,CAC9B,GAAI,CAAC,KAAK,SAAU,CAClBA,EAAO,EACP,MACF,CACA,MAAMC,EAAU,IAAM,CACpB,KAAK,SAAS,oBAAoB,oBAAqBA,CAAO,EAC9DD,EAAO,CACT,EACA,KAAK,SAAS,iBAAiB,oBAAqBC,CAAO,CAC7D,CAAC,CACH,CAEA,OAAOZ,EAAI,CACT,YAAK,eAAe,IAAIA,CAAE,EACnB,IAAM,KAAK,eAAe,OAAOA,CAAE,CAC5C,CAEA,QAAQA,EAAI,CACV,YAAK,gBAAgB,IAAIA,CAAE,EACpB,IAAM,KAAK,gBAAgB,OAAOA,CAAE,CAC7C,CAEA,UAAUA,EAAI,CACZ,YAAK,kBAAkB,IAAIA,CAAE,EACtB,IAAM,KAAK,kBAAkB,OAAOA,CAAE,CAC/C,CAEA,OAAQ,SACN,KAAK,cAAc,MAAK,EACxB,KAAK,WAAW,OAAS,GACzBzG,EAAA,KAAK,wBAAL,MAAAA,EAAA,YACAoC,EAAA,KAAK,WAAL,MAAAA,EAAe,QACf,KAAK,IAAI,MAAK,CAChB,CACF,CChPA,MAAMkF,GAA+B,IA2B9B,MAAMC,EAAc,CACzB,YAAY,CAAE,QAAAC,EAAS,UAAAxB,EAAW,mBAAAyB,EAAqBH,EAA4B,EAAI,CACrF,KAAK,SAAWE,EAChB,KAAK,OAASA,EAAQ,MACtB,KAAK,WAAaxB,EAClB,KAAK,OAAS,IAAI,IAClB,KAAK,kBAAoB,KAAK,sBAAqB,EAKnD,KAAK,eAAiB,KACtB,KAAK,gBAAkB,IAAI,IAC3B,KAAK,mBAAqB,IAAI,IAC9B,KAAK,oBAAsByB,EAC3B,KAAK,uBAAyB,KAC9B,KAAK,eAAiB,EACxB,CAmBA,uBAAwB,CACtB,MAAMC,EAAyB,KAAK,OAAO,eAAe,KAAK,KAAK,MAAM,EAC1E,KAAK,kBAAoB,CAAA,EACzB,KAAK,OAAO,eAAkBzH,GAAO,CACnC,MAAM2C,EAAU8E,EAAuBzH,CAAE,EACnCiC,EAAW,KAAK,OAAO,gBAAe,EAC5C,OAAIA,GAAU,KAAK,kBAAkB,KAAKA,CAAQ,EAC3CU,CACT,EAEA,MAAM+E,EAAY,CAAA,EAClB,UAAWC,IAAc,CAAC,UAAW,eAAgB,OAAQ,MAAM,EAAG,CACpE,MAAMC,EAAW,KAAK,SAASD,CAAU,EAAE,KAAK,KAAK,QAAQ,EAC7DD,EAAUC,CAAU,EAAIC,EACxB,KAAK,SAASD,CAAU,EAAI,IAAIE,IAAS,CACvC,MAAM1K,EAASyK,EAAS,GAAGC,CAAI,EAC/B,YAAK,uBAAsB,EACpB1K,CACT,CACF,CAEA,MAAO,IAAM,CACX,UAAWwK,KAAc,OAAO,KAAKD,CAAS,EAAG,KAAK,SAASC,CAAU,EAAID,EAAUC,CAAU,EACjG,KAAK,OAAO,eAAiBF,CAC/B,CACF,CAEA,wBAAyB,CACvB,MAAMK,EAAY,KAAK,kBACvB,KAAK,kBAAoB,CAAA,EACzB,UAAW7F,KAAY6F,EAIrB,KAAK,WAAW3C,GAAUlD,CAAQ,CAAC,CAEvC,CAEA,WAAW5G,EAAS,CAClB,MAAM4J,EAAMF,GAAc1J,CAAO,EACjC,UAAW0M,KAAQ,KAAK,OAAO,OAAM,EAAIA,EAAK,KAAK9C,CAAG,CACxD,CAGA,QAAQe,EAAc,CAAE,UAAAC,GAAa,QACnClG,EAAA,KAAK,OAAO,IAAIiG,CAAY,IAA5B,MAAAjG,EAA+B,QAC/B,MAAMgI,EAAO,IAAIjC,GAAe,CAAE,UAAW,KAAK,WAAY,aAAAE,EAAc,UAAAC,EAAW,EACvF,OAAA8B,EAAK,OAAO,IAAM,CAChBA,EAAK,KAAKhD,GAAcG,GAAa,KAAK,WAAW,WAAW,CAAC,CAAC,EAClE6C,EAAK,KAAKhD,GAAcK,GAAkB,CAAE,CAAC,EAKzC,KAAK,iBAAmB,MAC1B2C,EAAK,KAAKhD,GAAcO,GAAgB,KAAK,WAAW,YAAa,KAAK,cAAc,CAAC,CAAC,CAE9F,CAAC,EACDyC,EAAK,UAAW9C,GAAQ,KAAK,eAAe8C,EAAM9C,CAAG,CAAC,EACtD8C,EAAK,QAAQ,IAAM,CAMjB,KAAK,OAAO,OAAO/B,CAAY,EAC3B,KAAK,gBAAgB,OAAOA,CAAY,GAAG,KAAK,yBAAwB,CAC9E,CAAC,EACD,KAAK,OAAO,IAAIA,EAAc+B,CAAI,EAC3BA,CACT,CAUA,iBAAiBxC,EAAM,CACrB,KAAK,eAAiBA,EACtB,KAAK,eAAiB,GAClB,MAAK,yBAET,KAAK,oBAAmB,EACxB,KAAK,uBAAyB,WAAW,IAAM,CAC7C,KAAK,uBAAyB,KAC1B,KAAK,gBAAgB,KAAK,oBAAmB,CACnD,EAAG,KAAK,mBAAmB,EAC7B,CAEA,qBAAsB,CACpB,KAAK,eAAiB,GACtB,KAAK,WAAWD,GAAgB,KAAK,WAAW,YAAa,KAAK,cAAc,CAAC,CACnF,CAGA,aAAc,CACZ,OAAO,IAAI,IAAI,KAAK,eAAe,CACrC,CAGA,iBAAiBkB,EAAI,CACnB,YAAK,mBAAmB,IAAIA,CAAE,EACvB,IAAM,KAAK,mBAAmB,OAAOA,CAAE,CAChD,CAEA,0BAA2B,CACzB,MAAMwB,EAAW,KAAK,YAAW,EACjC,UAAWxB,KAAM,KAAK,mBAAoBA,EAAGwB,CAAQ,CACvD,CAEA,eAAeD,EAAM9C,EAAK,CACxB,IAAI5J,EACJ,GAAI,CACFA,EAAU2J,GAAcC,CAAG,CAC7B,MAAQ,CACN,MACF,CAEI5J,EAAQ,OAASyJ,GAAa,IAChC,KAAK,OAAO,qBAAqBzJ,EAAQ,QAAQ,EAUjD,KAAK,SAAS,MAAK,GACVA,EAAQ,OAASyJ,GAAa,aACvCiD,EAAK,KAAKhD,GAAcM,GAAoB,KAAK,OAAO,OAAM,CAAE,CAAC,CAAC,EACzDhK,EAAQ,OAASyJ,GAAa,cACvC,KAAK,sBAAsBzJ,EAAQ,GAAG,EAC7BA,EAAQ,OAASyJ,GAAa,WACvC,KAAK,gBAAgB,IAAIzJ,EAAQ,OAAQA,EAAQ,IAAI,EACrD,KAAK,yBAAwB,EAGjC,CAcA,sBAAsBmD,EAAK,CACzB,MAAMmB,EAAS,KAAK,OAAO,UAAS,EAChCA,GAAU,KAAK,OAAO,SAASA,CAAM,IACzC,KAAK,OAAO,OAAS,IAAI,KAAKnB,EAAI,QAAU,CAAA,GAAI,IAAKxC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACrE,KAAK,OAAO,KAAO,IAAI,KAAKwC,EAAI,MAAQ,CAAA,GAAI,IAAK,GAAM,CAAC,EAAE,GAAI,CAAC,CAAC,CAAC,EACjE,KAAK,OAAO,OAASA,EAAI,QAAU,KACnC,KAAK,OAAO,QAAU,IAAI,IAC1B,KAAK,OAAO,QAAQ,CAAC,GAAG,KAAK,OAAO,OAAO,KAAI,EAAI,GAAG,KAAK,OAAO,KAAK,KAAI,CAAE,CAAC,EAChF,CAEA,WAAWwH,EAAc,QACvBjG,EAAA,KAAK,OAAO,IAAIiG,CAAY,IAA5B,MAAAjG,EAA+B,QAC/B,KAAK,OAAO,OAAOiG,CAAY,CACjC,CAEA,SAAU,CACR,KAAK,kBAAiB,EAClB,KAAK,wBAAwB,aAAa,KAAK,sBAAsB,EACzE,UAAW+B,KAAQ,KAAK,OAAO,OAAM,EAAIA,EAAK,MAAK,EACnD,KAAK,OAAO,MAAK,EACjB,KAAK,gBAAgB,MAAK,EAC1B,KAAK,mBAAmB,MAAK,CAC/B,CACF,CC5NO,SAASE,GAAyB,CAAE,IAAAC,EAAK,OAAAC,EAAQ,OAAAxM,EAAQ,cAAAyM,EAAgB,WAAa,CAC3F,MAAMC,EAAkB,IAAI,IACtBC,EAAqB,IAAI,IACzBC,EAAmB,IAAI,IACvBC,EAAe,CAAA,EAEfC,EAAa,GAAGP,CAAG,GAAGA,EAAI,SAAS,GAAG,EAAI,IAAM,GAAG,QAAQ,mBAAmBC,CAAM,CAAC,WAAW,mBAAmBxM,CAAM,CAAC,GAC1H+M,EAAS,IAAIN,EAAcK,CAAU,EAE3CC,EAAO,iBAAiB,OAAQ,IAAM,CACpC,SAAW,CAAE,SAAAC,EAAU,QAAAC,CAAO,IAAMJ,EAAcK,EAAWF,EAAUC,CAAO,EAC9EJ,EAAa,OAAS,CACxB,CAAC,EAEDE,EAAO,iBAAiB,UAAYvC,GAAU,CAC5C,IAAI9K,EACJ,GAAI,CACFA,EAAU,KAAK,MAAM8K,EAAM,IAAI,CACjC,MAAQ,CACN,MACF,CACA,GAAI9K,EAAQ,OAAS,SACnB,UAAWyN,KAAWzN,EAAQ,SAAW,CAAA,EACvC,UAAWmL,KAAM8B,EAAoB9B,EAAGsC,CAAO,UAExCzN,EAAQ,OAAS,cAC1B,UAAWmL,KAAM8B,EAAoB9B,EAAGnL,EAAQ,MAAM,UAC7CA,EAAQ,OAAS,YAC1B,UAAWmL,KAAM+B,EAAkB/B,EAAGnL,EAAQ,MAAM,UAC3CA,EAAQ,OAAS,SAC1B,UAAWmL,KAAM6B,EAAiB7B,EAAGnL,EAAQ,WAAYA,EAAQ,OAAO,CAE5E,CAAC,EAED,SAASwN,EAAWF,EAAUC,EAAS,CACrC,GAAIF,EAAO,aAAeN,EAAc,KAAM,CAC5CI,EAAa,KAAK,CAAE,SAAAG,EAAU,QAAAC,CAAO,CAAE,EACvC,MACF,CACAF,EAAO,KAAK,KAAK,UAAU,CAAE,KAAM,SAAU,SAAAC,EAAU,QAAAC,CAAO,CAAE,CAAC,CACnE,CAEA,MAAO,CACL,YAAajN,EAEb,KAAKgN,EAAUC,EAAS,CACtBC,EAAWF,EAAUC,CAAO,CAC9B,EAEA,UAAUpC,EAAI,CACZ,OAAA6B,EAAgB,IAAI7B,CAAE,EACf,IAAM6B,EAAgB,OAAO7B,CAAE,CACxC,EAGA,iBAAiBA,EAAI,CACnB,OAAA8B,EAAmB,IAAI9B,CAAE,EAClB,IAAM8B,EAAmB,OAAO9B,CAAE,CAC3C,EAGA,WAAWA,EAAI,CACb,OAAA+B,EAAiB,IAAI/B,CAAE,EAChB,IAAM+B,EAAiB,OAAO/B,CAAE,CACzC,EAEA,OAAQ,CACNgC,EAAa,OAAS,EACtBE,EAAO,MAAK,CACd,CACJ,CACA,CChGA,MAAMK,GAAU,qBACVC,GAAa,YACbC,GAAuB,YACvBC,GAAsB,WACtBC,GAAa,EAenB,IAAIC,GAAY,KAEhB,SAASC,IAAe,CACtB,OAAID,KACJA,GAAY,IAAI,QAAQ,CAACjC,EAASmC,IAAW,CAC3C,MAAMC,EAAU,UAAU,KAAKR,GAASI,EAAU,EAClDI,EAAQ,gBAAkB,IAAM,CACzBA,EAAQ,OAAO,iBAAiB,SAASP,EAAU,GACtDO,EAAQ,OAAO,kBAAkBP,EAAU,EAExCO,EAAQ,OAAO,iBAAiB,SAASN,EAAoB,GAIhEM,EAAQ,OAAO,kBAAkBN,GAAsB,CAAE,QAAS,KAAM,EAErEM,EAAQ,OAAO,iBAAiB,SAASL,EAAmB,GAO/DK,EAAQ,OAAO,kBAAkBL,GAAqB,CAAE,QAAS,KAAM,CAE3E,EACAK,EAAQ,UAAY,IAAMpC,EAAQoC,EAAQ,MAAM,EAChDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,EACMH,GACT,CAGO,eAAeI,GAAsBC,EAAOjL,EAAK,CACtD,MAAMkL,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CACtC,MAAMK,EAAKD,EAAG,YAAYV,GAAY,WAAW,EACjDW,EAAG,YAAYX,EAAU,EAAE,IAAIxK,EAAKiL,CAAK,EACzCE,EAAG,WAAa,IAAMxC,EAAO,EAC7BwC,EAAG,QAAU,IAAML,EAAOK,EAAG,KAAK,CACpC,CAAC,CACH,CAGO,eAAeC,GAAsBH,EAAO,CACjD,MAAMC,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CAEtC,MAAMC,EADKG,EAAG,YAAYV,GAAY,UAAU,EAC7B,YAAYA,EAAU,EAAE,IAAIS,CAAK,EACpDF,EAAQ,UAAY,IAAMpC,EAAQoC,EAAQ,QAAU,IAAI,EACxDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAGO,eAAeM,GAAwBJ,EAAO,CACnD,MAAMC,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CACtC,MAAMK,EAAKD,EAAG,YAAYV,GAAY,WAAW,EACjDW,EAAG,YAAYX,EAAU,EAAE,OAAOS,CAAK,EACvCE,EAAG,WAAa,IAAMxC,EAAO,EAC7BwC,EAAG,QAAU,IAAML,EAAOK,EAAG,KAAK,CACpC,CAAC,CACH,CAGO,eAAeG,IAA2B,CAC/C,MAAMJ,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CAEtC,MAAMC,EADKG,EAAG,YAAYV,GAAY,UAAU,EAC7B,YAAYA,EAAU,EAAE,WAAU,EACrDO,EAAQ,UAAY,IAAMpC,EAAQoC,EAAQ,MAAM,EAChDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAWO,eAAeQ,GAAaC,EAAU,CAC3C,MAAMN,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CACtC,MAAMK,EAAKD,EAAG,YAAYT,GAAsB,WAAW,EAC3DU,EAAG,YAAYV,EAAoB,EAAE,IAAIe,CAAQ,EACjDL,EAAG,WAAa,IAAMxC,EAAO,EAC7BwC,EAAG,QAAU,IAAML,EAAOK,EAAG,KAAK,CACpC,CAAC,CACH,CAGO,eAAeM,GAAa3Q,EAAI,CACrC,MAAMoQ,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CAEtC,MAAMC,EADKG,EAAG,YAAYT,GAAsB,UAAU,EACvC,YAAYA,EAAoB,EAAE,IAAI3P,CAAE,EAC3DiQ,EAAQ,UAAY,IAAMpC,EAAQoC,EAAQ,QAAU,IAAI,EACxDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAGO,eAAeW,GAAe5Q,EAAI,CACvC,MAAMoQ,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CACtC,MAAMK,EAAKD,EAAG,YAAYT,GAAsB,WAAW,EAC3DU,EAAG,YAAYV,EAAoB,EAAE,OAAO3P,CAAE,EAC9CqQ,EAAG,WAAa,IAAMxC,EAAO,EAC7BwC,EAAG,QAAU,IAAML,EAAOK,EAAG,KAAK,CACpC,CAAC,CACH,CAGO,eAAeQ,IAAgB,CACpC,MAAMT,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CAEtC,MAAMC,EADKG,EAAG,YAAYT,GAAsB,UAAU,EACvC,YAAYA,EAAoB,EAAE,OAAM,EAC3DM,EAAQ,UAAY,IAAMpC,EAAQoC,EAAQ,MAAM,EAChDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAcO,eAAea,GAAoBC,EAAS,CACjD,MAAMX,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CACtC,MAAMK,EAAKD,EAAG,YAAYR,GAAqB,WAAW,EAC1DS,EAAG,YAAYT,EAAmB,EAAE,IAAImB,CAAO,EAC/CV,EAAG,WAAa,IAAMxC,EAAO,EAC7BwC,EAAG,QAAU,IAAML,EAAOK,EAAG,KAAK,CACpC,CAAC,CACH,CAGO,eAAeW,GAAoBhR,EAAI,CAC5C,MAAMoQ,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CAEtC,MAAMC,EADKG,EAAG,YAAYR,GAAqB,UAAU,EACtC,YAAYA,EAAmB,EAAE,IAAI5P,CAAE,EAC1DiQ,EAAQ,UAAY,IAAMpC,EAAQoC,EAAQ,QAAU,IAAI,EACxDA,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CAGO,eAAegB,GAAsBjR,EAAI,CAC9C,MAAMoQ,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CACtC,MAAMK,EAAKD,EAAG,YAAYR,GAAqB,WAAW,EAC1DS,EAAG,YAAYT,EAAmB,EAAE,OAAO5P,CAAE,EAC7CqQ,EAAG,WAAa,IAAMxC,EAAO,EAC7BwC,EAAG,QAAU,IAAML,EAAOK,EAAG,KAAK,CACpC,CAAC,CACH,CAGO,eAAea,GAAqBf,EAAO,CAChD,MAAMC,EAAK,MAAML,GAAY,EAC7B,OAAO,IAAI,QAAQ,CAAClC,EAASmC,IAAW,CAEtC,MAAMC,EADKG,EAAG,YAAYR,GAAqB,UAAU,EACtC,YAAYA,EAAmB,EAAE,OAAM,EAC1DK,EAAQ,UAAY,IAAM,CACxB,MAAMkB,EAAMlB,EAAQ,OAAO,OAAQmB,GAAMA,EAAE,QAAUjB,CAAK,EAC1DgB,EAAI,KAAK,CAAC1O,EAAGC,IAAMA,EAAE,UAAYD,EAAE,SAAS,EAC5CoL,EAAQsD,CAAG,CACb,EACAlB,EAAQ,QAAU,IAAMD,EAAOC,EAAQ,KAAK,CAC9C,CAAC,CACH,CC1MA,MAAMoB,GAAsB,IAqBrB,SAASC,GAAsB,CAAE,MAAAtH,EAAO,MAAAmG,EAAO,WAAAoB,EAAaF,GAAqB,QAAAhG,GAAW,CACjG,IAAIC,EAAQ,KAEZ,SAASkG,GAAU,CACjBtB,GAAsBC,EAAOnG,EAAM,OAAM,CAAE,EAAE,MAAOuB,GAAQF,GAAA,YAAAA,EAAUE,EAAI,CAC5E,CAEA,SAASkG,GAAQ,CACXnG,IACF,aAAaA,CAAK,EAClBA,EAAQ,KACRkG,EAAO,EAEX,CAEA,MAAME,EAAc1H,EAAM,aAAa,IAAM,CACvCsB,GAAO,aAAaA,CAAK,EAC7BA,EAAQ,WAAW,IAAM,CACvBA,EAAQ,KACRkG,EAAO,CACT,EAAGD,CAAU,CACf,CAAC,EAED,SAASI,GAAO,CACVrG,GAAO,aAAaA,CAAK,EAC7BA,EAAQ,KACRoG,EAAW,CACb,CAEA,MAAO,CAAE,KAAAC,EAAM,MAAAF,CAAK,CACtB,CC3CO,SAASG,GAAoB5H,EAAO6H,EAAUC,EAAUC,EAAgB,CAC7E,MAAMC,EAAM,CAAE,MAAAhI,EAAO,SAAA6H,EAAU,eAAAE,CAAc,EAC7C,MAAO,CACL,KAAME,GAAcjI,EAAO6H,EAAUC,EAAUE,CAAG,EAClD,KAAMF,EACH,IAAK9R,GAAO,CACX,MAAML,EAAQqK,EAAM,SAAShK,CAAE,EAC/B,OAAO6R,EAAS,IAAIlS,EAAM,IAAI,EAAE,YAAYA,EAAOqS,CAAG,CACxD,CAAC,EACA,KAAK;AAAA,CAAI,EACZ,KAAM,KAAK,UAAU,CAAE,QAAS,EAAG,OAAQF,EAAS,IAAK9R,GAAOkS,GAAelI,EAAOhK,CAAE,CAAC,CAAC,CAAE,CAChG,CACA,CAEA,SAASiS,GAAcjI,EAAO6H,EAAUC,EAAUE,EAAK,CACrD,IAAIG,EAAO,GACPnO,EAAI,EACR,KAAOA,EAAI8N,EAAS,QAAQ,CAC1B,MAAMnS,EAAQqK,EAAM,SAAS8H,EAAS9N,CAAC,CAAC,EACxC,GAAIrE,EAAM,OAAS,WAAY,CAC7B,MAAMyS,EAAU,EAAQzS,EAAM,MAAM,QACpC,IAAI0S,EAAY,GACZC,EAAItO,EACR,KAAOsO,EAAIR,EAAS,QAAQ,CAC1B,MAAMS,EAAYvI,EAAM,SAAS8H,EAASQ,CAAC,CAAC,EAC5C,GAAIC,EAAU,OAAS,YAAc,EAAQA,EAAU,MAAM,UAAaH,EAAS,MACnFC,GAAaR,EAAS,IAAI,UAAU,EAAE,OAAOU,EAAWP,CAAG,EAC3DM,GAAK,CACP,CACA,MAAME,EAAMJ,EAAU,KAAO,KAC7BD,GAAQ,IAAIK,CAAG,IAAIH,CAAS,KAAKG,CAAG,IACpCxO,EAAIsO,CACN,SAAW3S,EAAM,OAAS,aAAc,CAOtC,IAAI8S,EAAY,GACZH,EAAItO,EACR,KAAOsO,EAAIR,EAAS,QAAQ,CAC1B,MAAMS,EAAYvI,EAAM,SAAS8H,EAASQ,CAAC,CAAC,EAC5C,GAAIC,EAAU,OAAS,aAAc,MACrCE,GAAaZ,EAAS,IAAI,YAAY,EAAE,OAAOU,EAAWP,CAAG,EAC7DM,GAAK,CACP,CACAH,GAAQ,eAAeM,CAAS,gBAChCzO,EAAIsO,CACN,MACEH,GAAQN,EAAS,IAAIlS,EAAM,IAAI,EAAE,OAAOA,EAAOqS,CAAG,EAClDhO,GAAK,CAET,CACA,OAAOmO,CACT,CAQO,SAASD,GAAelI,EAAO3D,EAAQ,CAC5C,MAAMC,EAAS,CAAA,EACTjF,EAAO,CAAA,EACPkF,EAAQvG,GAAO,OACnB,MAAMwF,EAAMwE,EAAM,OAAOhK,CAAE,EAC3B,GAAIwF,EAAK,CACPnE,EAAK,KAAKmE,CAAG,EACb,MACF,CACA,MAAM7F,EAAQqK,EAAM,SAAShK,CAAE,EAC/B,GAAKL,EACL,CAAA2G,EAAO,KAAK3G,CAAK,EACjB,UAAW6G,KAAW7G,EAAM,WAAY4G,EAAKC,CAAO,EACpD,UAAWjB,MAASkB,EAAA9G,EAAM,QAAN,YAAA8G,EAAa,cAAe,GAAIF,EAAKhB,CAAK,EAChE,EACA,OAAAgB,EAAKF,CAAM,EACJ,CAAE,OAAAA,EAAQ,OAAAC,EAAQ,KAAAjF,EAC3B,CAOO,SAASqR,GAAgB,CAAE,OAAArM,EAAQ,OAAAC,EAAQ,KAAAjF,CAAI,EAAI,CACxD,MAAMsR,EAAQ,IAAI,IAClB,UAAWjQ,KAAK4D,EAAQqM,EAAM,IAAIjQ,EAAE,GAAIoC,EAAK,CAAE,EAC/C,UAAWK,KAAK9D,EAAMsR,EAAM,IAAIxN,EAAE,GAAIL,EAAK,CAAE,EAC7C,MAAM8N,EAAS5S,GAAO2S,EAAM,IAAI3S,CAAE,GAAKA,EAEjC6S,EAAYvM,EAAO,IAAK5D,GAAC,OAAM,OACnC,GAAGA,EACH,GAAIkQ,EAAMlQ,EAAE,EAAE,EACd,SAAUA,EAAE,SAAWkQ,EAAMlQ,EAAE,QAAQ,EAAIA,EAAE,SAC7C,WAAYA,EAAE,WAAW,IAAIkQ,CAAK,EAClC,MAAO,CACL,GAAGlQ,EAAE,MACL,IAAI+D,EAAA/D,EAAE,QAAF,MAAA+D,EAAS,YAAc,CAAE,YAAa/D,EAAE,MAAM,YAAY,IAAIkQ,CAAK,CAAC,EAAK,CAAA,CACnF,CACA,EAAI,EACIzR,EAAUE,EAAK,IAAK8D,IAAO,CAAE,GAAGA,EAAG,GAAIyN,EAAMzN,EAAE,EAAE,CAAC,EAAG,EACrD2N,EAAYF,EAAMvM,CAAM,EAE9B,MAAO,CACL,MAAOwM,EAAU,KAAMnQ,GAAMA,EAAE,KAAOoQ,CAAS,EAC/C,KAAM3R,EACN,cAAe0R,EAAU,OAAQnQ,GAAMA,EAAE,KAAOoQ,CAAS,CAC7D,CACA,CCrHA,SAASC,GAAS/I,EAAOtB,EAAK,CAC5B,GAAI,OAAOsB,EAAM,cAAiB,WAAYA,EAAM,aAAatB,CAAG,MAC/D,WAAWhC,KAAMgC,EAAKsB,EAAM,eAAetD,CAAE,CACpD,CAUO,SAASsM,GAAqBhJ,EAAO8H,EAAU,CACpD,MAAO,CAAE,MAAOA,EAAS,IAAK9R,GAAOkS,GAAelI,EAAOhK,CAAE,CAAC,CAAC,CACjE,CAQO,SAASiT,GAAoBjJ,EAAO0G,EAAU,CAAE,SAAA9Q,EAAU,MAAAC,CAAK,EAAI,CACxE,MAAM6I,EAAM,CAAA,EACZ,IAAIwK,EAAYrT,EAChB,UAAWsT,KAAQzC,EAAS,MAAO,CACjC,KAAM,CAAE,MAAA/Q,EAAO,KAAA0B,EAAM,cAAA+R,CAAa,EAAKV,GAAgBS,CAAI,EAC3DxT,EAAM,SAAWC,EACjB8I,EAAI,KAAKhJ,GAAYC,EAAOC,EAAUsT,EAAW,CAAE,OAAQ,CAACvT,EAAO,GAAGyT,CAAa,EAAG,KAAA/R,CAAI,CAAE,CAAC,EAC7F6R,GAAa,CACf,CACAH,GAAS/I,EAAOtB,CAAG,CACrB,CASO,SAAS2K,GAAsBrJ,EAAO9E,EAAK,CAChD,MAAMoO,EAAWtJ,EAAM,OAASA,EAChCsJ,EAAS,OAAS,IAAI,KAAKpO,EAAI,QAAU,CAAA,GAAI,IAAKxC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAClE4Q,EAAS,KAAO,IAAI,KAAKpO,EAAI,MAAQ,CAAA,GAAI,IAAK,GAAM,CAAC,EAAE,GAAI,CAAC,CAAC,CAAC,EAC9DoO,EAAS,OAASpO,EAAI,QAAU,KAChCoO,EAAS,WAAa,IAAI,KAAKpO,EAAI,YAAc,CAAA,GAAI,IAAKE,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAC1EkO,EAAS,oBAAsB,KAC/BA,EAAS,SAAW,IAAI,KAAKpO,EAAI,UAAY,CAAA,GAAI,IAAKG,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACtEiO,EAAS,kBAAoB,KAC7BA,EAAS,QAAU,IAAI,IAKvBA,EAAS,QAAQ,CAAC,GAAGA,EAAS,OAAO,KAAI,EAAI,GAAGA,EAAS,KAAK,KAAI,EAAI,cAAe,WAAW,CAAC,CACnG,CAYO,SAASC,GAAuB1B,EAAU2B,EAAW,CAC1D,UAAW9C,KAAY8C,EACrB3B,EAAS,SAAS,mBAAmBnB,EAAS,EAAE,GAAI,CAClD,UAAW,IAAM,KACjB,OAAQ,GACR,aAAc,CACZ,MAAOA,EAAS,MAChB,KAAMA,EAAS,KACf,SAAUA,EAAS,UAAY,CAACA,EAAS,KAAK,EAC9C,IAAI1G,EAAO,CAAE,QAAAjJ,EAAS,MAAAwE,EAAO,WAAAkO,EAAY,SAAAC,GAAY,CAEnD,MAAMlO,EAAMwE,EAAM,OAAOzE,CAAK,EACxBK,GAAQJ,GAAA,YAAAA,EAAK,QAAS,GAC5BwE,EAAM,eAAevJ,GAAU8E,EAAO,CAAE,MAAOK,EAAM,MAAM,EAAG6N,CAAU,EAAI7N,EAAM,MAAM8N,CAAQ,CAAC,CAAE,CAAC,EAEpG,MAAMtP,EAAU4F,EAAM,SAASjJ,CAAO,EAEhClB,EADSmK,EAAM,SAAS5F,EAAQ,QAAQ,EACzB,WAAW,QAAQrD,CAAO,EAAI,EACnDkS,GAAoBjJ,EAAO0G,EAAU,CAAE,SAAUtM,EAAQ,SAAU,MAAAvE,EAAO,CAC5E,CACR,CACA,CAAK,CAEL,CCjFO,SAAS8T,GAAa,CAAE,MAAAC,CAAK,EAAK,GAAI,CAC3C,KAAM,CAACJ,EAAWK,CAAY,EAAIC,EAAAA,SAAS,CAAA,CAAE,EACvC,CAACC,EAAUC,CAAW,EAAIF,EAAAA,SAAS,EAAK,EAExCG,EAAUC,EAAAA,YAAY,KAC1BF,EAAY,EAAK,EACVnD,GAAa,EAAG,KAAMM,GAAQ,CACnC0C,EAAaD,EAAQzC,EAAI,OAAQgD,GAAMA,EAAE,QAAUP,CAAK,EAAIzC,CAAG,EAC/D6C,EAAY,EAAI,CAClB,CAAC,GAEA,CAACJ,CAAK,CAAC,EAEVQ,OAAAA,EAAAA,UAAU,IAAM,CACd,IAAIC,EAAY,GAChB,OAAAL,EAAY,EAAK,EACjBnD,GAAa,EAAG,KAAMM,GAAQ,CACxBkD,IACJR,EAAaD,EAAQzC,EAAI,OAAQgD,GAAMA,EAAE,QAAUP,CAAK,EAAIzC,CAAG,EAC/D6C,EAAY,EAAI,EAClB,CAAC,EACM,IAAM,CACXK,EAAY,EACd,CACF,EAAG,CAACT,CAAK,CAAC,EAEH,CAAE,UAAAJ,EAAW,SAAAO,EAAU,QAAAE,CAAO,CACvC,CC7BO,SAASK,GAAe,CAAE,UAAAd,EAAW,SAAAe,EAAU,WAAAC,EAAa,qBAAuB,CACxF,OAAIhB,EAAU,SAAW,EAChBiB,EAAAA,IAAC,IAAA,CAAE,UAAU,2BAA4B,SAAAD,EAAW,EAI3DC,EAAAA,IAAC,KAAA,CAAG,UAAU,qBAAqB,KAAK,OACrC,SAAAjB,EAAU,IAAK9C,GACdgE,EAAAA,KAAC,KAAA,CAAqB,UAAU,mBAC9B,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,wBACb,SAAA,CAAAD,EAAAA,IAAC,OAAA,CAAK,UAAU,wBAAyB,SAAA/D,EAAS,KAAK,EACtDA,EAAS,aAAe+D,EAAAA,IAAC,QAAK,UAAU,+BAAgC,WAAS,WAAA,CAAY,CAAA,EAChG,EACAA,EAAAA,IAAC,SAAA,CAAO,KAAK,SAAS,UAAU,0BAA0B,QAAS,IAAMF,EAAS7D,CAAQ,EAAG,SAAA,KAAA,CAE7F,CAAA,CAAA,EAPOA,EAAS,EAQlB,CACD,EACH,CAEJ,CCtBO,SAASiE,GAAmB3K,EAAO,CAAE,OAAA4K,EAAS,EAAI,EAAK,CAAA,EAAI,CAChE,MAAMvO,EAAS2D,EAAM,UAAS,EACxB,CAAE,OAAA1D,EAAQ,KAAAjF,CAAI,EAAK6Q,GAAelI,EAAO3D,CAAM,EAErD,OAAO,KAAK,UADI,CAAE,QAAS,EAAG,OAAAA,EAAQ,OAAAC,EAAQ,KAAAjF,CAAI,EACnB,KAAMuT,EAAS,EAAI,CAAC,CACrD,CAGO,SAASC,GAAmB7K,EAAO6H,EAAUE,EAAgB,CAClE,MAAMoB,EAAOnJ,EAAM,SAASA,EAAM,UAAS,CAAE,EAC7C,OAAKmJ,EACEvB,GAAoB5H,EAAO6H,EAAUsB,EAAK,WAAYpB,CAAc,EAAE,KAD3D,EAEpB,CAGO,SAAS+C,GAAmB9K,EAAO6H,EAAUE,EAAgB,CAClE,MAAMoB,EAAOnJ,EAAM,SAASA,EAAM,UAAS,CAAE,EAC7C,OAAKmJ,EACEvB,GAAoB5H,EAAO6H,EAAUsB,EAAK,WAAYpB,CAAc,EAAE,KAD3D,EAEpB,CC3BA,MAAMgD,GAAkB,EAAI,GAAK,IAC3BC,GAAuB,IAkBtB,SAASC,GAAyB,CAAE,MAAAjL,EAAO,MAAAmG,EAAO,OAAAlG,EAAS8K,GAAiB,YAAAG,EAAcF,GAAsB,WAAAG,EAAY,QAAA9J,GAAW,CAC5I,IAAI+J,EAAY,KACZC,EAAcrL,EAAM,cAAa,EAAG,OACpCsL,EAAqB,GAEzB,SAASC,GAAiB,CACpBH,IACF,aAAaA,CAAS,EACtBA,EAAY,KAEhB,CAEA,eAAeI,GAAiB,CAE9B,GADAD,EAAc,EACV,CAACD,EAAoB,OACzBA,EAAqB,GAErB,MAAMG,EAAMzL,EAAM,cAAa,EACzB0L,EAAUD,EAAI,MAAMJ,CAAW,EAErC,GADAA,EAAcI,EAAI,OACdC,EAAQ,SAAW,EAAG,OAE1B,MAAMtP,EAAa,IAAI,IAAIsP,EAAQ,IAAKC,GAAMA,EAAE,EAAE,EAAE,OAAO,OAAO,CAAC,EAC7DC,EAAY,CAAC,GAAG,IAAI,IAAIF,EAAQ,IAAKC,GAAMA,EAAE,OAAO,EAAE,OAAO,OAAO,CAAC,CAAC,EACtEE,EAAWH,EAAQA,EAAQ,OAAS,CAAC,EAAE,SAAW,KAExD,GAAI,CACF,MAAMxQ,EAAM,KAAK,MAAMyP,GAAmB3K,CAAK,CAAC,EAC1C+G,EAAU,CACd,GAAI,OAAO,WAAU,EACrB,MAAAZ,EACA,UAAW,KAAK,IAAG,EACnB,SAAA0F,EACA,UAAAD,EACA,QAAS,GAAGxP,EAAW,IAAI,SAASA,EAAW,OAAS,EAAI,GAAK,GAAG,WACpE,IAAAlB,CACR,EACM,MAAM4L,GAAoBC,CAAO,EACjCoE,GAAA,MAAAA,EAAapE,GAEb,MAAMI,EAAM,MAAMD,GAAqBf,CAAK,EAC5C,GAAIgB,EAAI,OAAS+D,EAAa,CAC5B,MAAMY,EAAS3E,EAAI,MAAM+D,CAAW,EACpC,MAAM,QAAQ,IAAIY,EAAO,IAAK1E,GAAMH,GAAsBG,EAAE,EAAE,CAAC,CAAC,CAClE,CACF,OAAS7F,EAAK,CACZF,GAAA,MAAAA,EAAUE,EACZ,CACF,CAEA,MAAMmG,EAAc1H,EAAM,mBAAmB,IAAM,CACjDsL,EAAqB,GACrBC,EAAc,EACdH,EAAY,WAAWI,EAAgBvL,CAAM,CAC/C,CAAC,EAED,MAAO,CAEL,MAAO,CACLsL,EAAc,EACd7D,EAAW,CACb,EAEA,MAAO8D,CACX,CACA,CC/EO,SAASO,GAAUC,EAASC,EAAS,CAC1C,MAAMC,EAAYC,GAASH,CAAO,EAC5BI,EAAYD,GAASF,CAAO,EAC5BI,EAAIH,EAAU,OACd1N,EAAI4N,EAAU,OAEdE,EAAK,MAAM,KAAK,CAAE,OAAQD,EAAI,CAAC,EAAI,IAAM,IAAI,YAAY7N,EAAI,CAAC,CAAC,EACrE,QAASxE,EAAIqS,EAAI,EAAGrS,GAAK,EAAGA,GAAK,EAC/B,QAASsO,EAAI9J,EAAI,EAAG8J,GAAK,EAAGA,GAAK,EAC/BgE,EAAGtS,CAAC,EAAEsO,CAAC,EAAI4D,EAAUlS,CAAC,IAAMoS,EAAU9D,CAAC,EAAIgE,EAAGtS,EAAI,CAAC,EAAEsO,EAAI,CAAC,EAAI,EAAI,KAAK,IAAIgE,EAAGtS,EAAI,CAAC,EAAEsO,CAAC,EAAGgE,EAAGtS,CAAC,EAAEsO,EAAI,CAAC,CAAC,EAIzG,MAAMiE,EAAW,CAAA,EACXC,EAAO,CAACC,EAAMC,IAAS,CAC3B,MAAMC,EAAOJ,EAASA,EAAS,OAAS,CAAC,EACrCI,GAAQA,EAAK,OAASF,EAAME,EAAK,MAAQD,EACxCH,EAAS,KAAK,CAAE,KAAAE,EAAM,KAAAC,CAAI,CAAE,CACnC,EAEA,IAAI1S,EAAI,EACJsO,EAAI,EACR,KAAOtO,EAAIqS,GAAK/D,EAAI9J,GACd0N,EAAUlS,CAAC,IAAMoS,EAAU9D,CAAC,GAC9BkE,EAAK,QAASN,EAAUlS,CAAC,CAAC,EAC1BA,GAAK,EACLsO,GAAK,GACIgE,EAAGtS,EAAI,CAAC,EAAEsO,CAAC,GAAKgE,EAAGtS,CAAC,EAAEsO,EAAI,CAAC,GACpCkE,EAAK,UAAWN,EAAUlS,CAAC,CAAC,EAC5BA,GAAK,IAELwS,EAAK,QAASJ,EAAU9D,CAAC,CAAC,EAC1BA,GAAK,GAGT,KAAOtO,EAAIqS,GACTG,EAAK,UAAWN,EAAUlS,CAAC,CAAC,EAC5BA,GAAK,EAEP,KAAOsO,EAAI9J,GACTgO,EAAK,QAASJ,EAAU9D,CAAC,CAAC,EAC1BA,GAAK,EAEP,OAAOiE,CACT,CAEA,SAASJ,GAASO,EAAM,CACtB,OAAQA,GAAQ,IAAI,MAAM,aAAa,GAAK,CAAA,CAC9C,CAEA,MAAME,GAAa,CAAE,IAAK,QAAS,IAAK,OAAQ,IAAK,OAAQ,IAAK,SAAU,IAAK,OAAO,EACxF,SAASC,GAAWH,EAAM,CACxB,OAAOA,EAAK,QAAQ,WAAahR,GAAOkR,GAAWlR,CAAE,CAAC,CACxD,CASA,SAASoR,GAAkB5R,EAAK,CAC9B,MAAM6R,EAAY,IAAI,IAAI7R,EAAI,OAAO,IAAKxC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACpDsU,EAAU,IAAI,IAAI9R,EAAI,KAAK,IAAKC,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAChDtB,EAAS,CAAA,EAEToT,EAAkBpU,GAAQA,EAAI,IAAK7C,GAAE,OAAK,QAAAyG,EAAAuQ,EAAQ,IAAIhX,CAAE,IAAd,YAAAyG,EAAiB,QAAS,GAAE,EAAE,KAAK,EAAE,EAE/EF,EAAQvG,GAAO,OACnB,MAAML,EAAQoX,EAAU,IAAI/W,CAAE,EAC9B,GAAI,CAACL,EAAO,OACZ,MAAMuX,GAAczQ,EAAA9G,EAAM,QAAN,YAAA8G,EAAa,YAC7B,MAAM,QAAQyQ,CAAW,GAAKA,EAAY,OAAS,EACrDrT,EAAO,KAAK,CAAE,GAAA7D,EAAI,KAAMiX,EAAeC,CAAW,EAAG,EAC5CvX,EAAM,WAAW,OAAS,GAAKA,EAAM,WAAW,MAAOwX,GAAQH,EAAQ,IAAIG,CAAG,CAAC,GACxFtT,EAAO,KAAK,CAAE,GAAA7D,EAAI,KAAMiX,EAAetX,EAAM,UAAU,EAAG,EAE5D,UAAW6G,KAAW7G,EAAM,WACrBqX,EAAQ,IAAIxQ,CAAO,GAAGD,EAAKC,CAAO,CAE3C,EACA,OAAAD,EAAKrB,EAAI,MAAM,EACRrB,CACT,CAEA,MAAMuT,GAAY,CAChB,OAAQ,OACR,OAAQ,CAAC,CAAE,GAAI,OAAQ,KAAM,OAAQ,SAAU,KAAM,WAAY,CAAA,EAAI,MAAO,CAAA,CAAE,CAAE,EAChF,KAAM,CAAA,CACR,EAYO,SAASC,GAAkBC,EAASC,EAAS,CAClD,MAAMC,EAAaV,GAAkBQ,GAAWF,EAAS,EACnDK,EAAaX,GAAkBS,GAAWH,EAAS,EACnDM,EAAW,IAAI,IAAIF,EAAW,IAAK9U,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EACnDiV,EAAU,IAAI,IAAIF,EAAW,IAAK/U,GAAMA,EAAE,EAAE,CAAC,EAE7CkV,EAAQ,CAAA,EAEd,UAAWjY,KAAS8X,EAAY,CAC9B,MAAMI,EAAYH,EAAS,IAAI/X,EAAM,EAAE,EACvC,GAAI,CAACkY,EAAW,CACd,MAAMnB,EAAOG,GAAWlX,EAAM,IAAI,GAAK,SACvCiY,EAAM,KAAK,wEAAwElB,CAAI,aAAa,EACpG,QACF,CACA,GAAImB,EAAU,OAASlY,EAAM,KAAM,CACjCiY,EAAM,KAAK,oCAAoCf,GAAWlX,EAAM,IAAI,GAAK,QAAQ,MAAM,EACvF,QACF,CAEA,MAAMwS,EADW4D,GAAU8B,EAAU,KAAMlY,EAAM,IAAI,EAElD,IAAKmY,GAAQ,CACZ,MAAMC,EAAUlB,GAAWiB,EAAI,IAAI,EACnC,OAAIA,EAAI,OAAS,QAAgB,uCAAuCC,CAAO,UAC3ED,EAAI,OAAS,UAAkB,yCAAyCC,CAAO,UAC5EA,CACT,CAAC,EACA,KAAK,EAAE,EACVH,EAAM,KAAK,oCAAoCzF,CAAI,MAAM,CAC3D,CAEA,UAAWxS,KAAS6X,EAClB,GAAI,CAACG,EAAQ,IAAIhY,EAAM,EAAE,EAAG,CAC1B,MAAM+W,EAAOG,GAAWlX,EAAM,IAAI,GAAK,SACvCiY,EAAM,KAAK,0EAA0ElB,CAAI,aAAa,CACxG,CAGF,OAAIkB,EAAM,SAAW,EAAU,wDACxBA,EAAM,KAAK,EAAE,CACtB,CCzIO,SAASI,GAAoB7H,EAAO,CACzC,KAAM,CAAC8H,EAAUC,CAAW,EAAIpE,EAAAA,SAAS,CAAA,CAAE,EACrC,CAACC,EAAUC,CAAW,EAAIF,EAAAA,SAAS,EAAK,EAExCG,EAAUC,EAAAA,YAAY,IACrB/D,GACL6D,EAAY,EAAK,EACV9C,GAAqBf,CAAK,EAAE,KAAMgB,GAAQ,CAC/C+G,EAAY/G,CAAG,EACf6C,EAAY,EAAI,CAClB,CAAC,GALkB,QAAQ,QAAO,EAMjC,CAAC7D,CAAK,CAAC,EAEViE,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAI,CAACjE,EAAO,CACV+H,EAAY,CAAA,CAAE,EACdlE,EAAY,EAAI,EAChB,MACF,CACA,IAAIK,EAAY,GAChB,OAAAL,EAAY,EAAK,EACjB9C,GAAqBf,CAAK,EAAE,KAAMgB,GAAQ,CACpCkD,IACJ6D,EAAY/G,CAAG,EACf6C,EAAY,EAAI,EAClB,CAAC,EACM,IAAM,CACXK,EAAY,EACd,CACF,EAAG,CAAClE,CAAK,CAAC,EAEH,CAAE,SAAA8H,EAAU,SAAAlE,EAAU,QAAAE,CAAO,CACtC,CC7CA,MAAAkE,GAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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"}