noteloom 0.3.3 → 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 +284 -55
  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 +372 -33
  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 -3283
  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 -3292
  102. package/dist/noteloom.cjs.map +0 -1
  103. package/dist/noteloom.es.js +0 -15047
  104. package/dist/noteloom.es.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/store/history.js","../src/react/useTemplates.js","../src/react/TemplatePicker.jsx","../src/people/people.js","../src/react/usePeople.js","../src/registry/blockRegistry.js","../src/registry/inlineRegistry.js","../src/blocks/index.js","../src/inlineTypes/index.js","../src/extensions/typing.js","../src/clipboard/simpleFormat.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/useEditorKeyboardShortcuts.js","../src/react/useExtensionBehaviors.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/FindBar.jsx","../src/search/findInDocument.js","../src/react/useFindInDocument.js","../src/react/NoteloomEditor.jsx","../src/react/useHistory.js","../src/react/usePresence.js","../src/react/useSmartQuotes.js","../src/react/useAutoPairBrackets.js","../src/react/MobileBlockPickerSheet.jsx","../src/react/MobileBlockOptionsSheet.jsx","../src/react/MobileActionBar.jsx","../src/react/DocumentExportButton.jsx","../src/inlineTypes/customSelect/CustomSelectInlineNode.jsx","../src/inlineTypes/customSelect/createSelectFieldType.jsx","../src/inlineTypes/customSelect/registerStoredFieldTypes.js","../src/react/useRegisterFieldTypes.js","../src/inlineTypes/customSelect/FieldTypeEditorModal.jsx"],"sourcesContent":["const IDLE_MS = 500;\n\n/**\n * Finds the boundaries of the differing region between an old and new\n * string via common-prefix/common-suffix trimming — e.g. \"hello\" ->\n * \"hello!\" gives {beforeOffset: 5, afterOffset: 6} (the edit happened right\n * at the end); \"hello\" -> \"helXlo\" gives {beforeOffset: 3, afterOffset: 4}\n * (caret was at 3 before typing \"X\", ends up at 4 after). Used to recover\n * exactly where the caret was/ended up around a single text-run edit,\n * purely from the op's before/after values — no DOM read needed (which\n * matters because by the time an updateRun op reaches History, the browser\n * has usually already mutated the DOM for that keystroke, so a live\n * `window.getSelection()` read at record-time would already reflect the\n * *post*-edit caret, not the pre-edit one this needs for undo).\n */\nfunction diffValueOffsets(oldValue, newValue) {\n const a = oldValue ?? '';\n const b = newValue ?? '';\n let start = 0;\n const maxStart = Math.min(a.length, b.length);\n while (start < maxStart && a[start] === b[start]) start += 1;\n let endA = a.length;\n let endB = b.length;\n while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) {\n endA -= 1;\n endB -= 1;\n }\n return { beforeOffset: endA, afterOffset: endB };\n}\n\n/**\n * Recovers the caret {runId, beforeOffset, afterOffset} for an undo entry,\n * when it's cleanly expressible as one text-run edit (an ordinary typing\n * batch, or a lone updateRun step) — returns null for anything else\n * (structural batches, non-text runs), which callers treat as \"don't move\n * focus\", same as today's behavior.\n */\n/**\n * Pulls \"the run's value right before this op was applied\" out of an\n * inverse, regardless of which of the two shapes `applyOperation` can\n * return for a text `updateRun`: the classic whole-value inverse\n * (`{type: 'updateRun', patch: {value}}`, still used for non-text patches\n * like marks/data) or the character-CRDT inverse (`{type: 'editRunChars',\n * previousValue}` — see operations.js's own doc comment on why it carries\n * a cosmetic-only plain-string snapshot alongside the real tombstone/\n * restore ids). Returns `undefined` for anything else.\n */\nfunction previousValueFromInverse(inverse) {\n if (inverse?.type === 'updateRun' && typeof inverse.patch?.value === 'string')\n return inverse.patch.value;\n if (inverse?.type === 'editRunChars' && typeof inverse.previousValue === 'string')\n return inverse.previousValue;\n return undefined;\n}\n\nfunction computeEntrySelection(entry) {\n if (!entry.ops.length || !entry.inverses.length) return null;\n const firstOp = entry.ops[0];\n const lastOp = entry.ops[entry.ops.length - 1];\n if (firstOp.type !== 'updateRun' || lastOp.type !== 'updateRun' || firstOp.id !== lastOp.id)\n return null;\n if (typeof lastOp.patch?.value !== 'string') return null;\n\n // inverses are unshifted (most-recent-first), so the last element is the\n // inverse of the *first* op — the run's value before the whole batch.\n const oldestInverse = entry.inverses[entry.inverses.length - 1];\n const previousValue = previousValueFromInverse(oldestInverse);\n if (previousValue === undefined) return null;\n\n const { beforeOffset, afterOffset } = diffValueOffsets(previousValue, lastOp.patch.value);\n return { runId: firstOp.id, beforeOffset, afterOffset };\n}\n\n/**\n * Structural ops (insert/remove/move block, setBlockContentIds,\n * updateBlockProps, ...) don't reduce to one clean run+offset the way a\n * text edit does, but every op shape here carries *some* id that names the\n * block it touched — block.id (insertBlock/its inverse), blockId\n * (setBlockContentIds/replaceRunSpan/setBlockRuns), id (removeBlock/\n * moveBlock/updateBlockProps — also a run id for updateRun, harmless here\n * since a plain-text-edit entry never reaches this function in the first\n * place; computeEntrySelection already handles that case), and\n * parentId/toParentId as a fallback anchor for when the primary block no\n * longer exists (e.g. after redoing a delete). Collected in that order\n * (most-specific first) so callers can walk the list and focus whichever\n * id is the first one that still resolves to a real block post-undo/redo.\n */\nfunction extractAffectedBlockIds(entry) {\n const ids = [];\n const collect = (op) => {\n if (!op) return;\n if (op.block?.id) ids.push(op.block.id);\n if (op.blockId) ids.push(op.blockId);\n if (op.id) ids.push(op.id);\n if (op.parentId) ids.push(op.parentId);\n if (op.toParentId) ids.push(op.toParentId);\n };\n for (const op of entry.ops) collect(op);\n for (const inverse of entry.inverses) collect(inverse);\n return [...new Set(ids)];\n}\n\n/**\n * Wraps an EditorStore with operation-based undo/redo and an audit log.\n *\n * Exposes the exact same read/write surface as EditorStore (getBlock,\n * getRun, getRootId, subscribe, applyOperation, toJSON) so any component\n * written against a plain store works unchanged when given a History\n * instance instead — `applyOperation` here just also records the inverse\n * before delegating to the store.\n *\n * Undo/redo replay inverse/forward operations directly (no full-document\n * snapshot). Rapid edits to the same run coalesce into one undo step via a\n * short idle timeout and a word-boundary heuristic; structural operations\n * (insert/remove/move block) never coalesce, each is its own undo step.\n * Every batch carries {actorId, timestamp}, which is also what backs the\n * audit log (`getHistoryLog`) — a bounded undo/redo stack and an unbounded\n * audit log are deliberately kept separate, since undoing/redoing should\n * not erase \"who changed what, when\".\n */\nexport class History {\n constructor(\n store,\n { idleMs = IDLE_MS, trackChanges = false, maxChangeLogSize = 500, defaultActorId = null } = {},\n ) {\n this.store = store;\n this.idleMs = idleMs;\n // Stamped onto historyLog/changeLog entries whenever a perform/\n // performBatch call doesn't pass its own `meta.actorId` -- the\n // pass-an-actorId-to-every-call-site convention this class already had\n // was never actually wired up anywhere in the package (every internal\n // call site is single-argument), so nothing knew \"who\" made an edit in\n // practice. Setting this once (see useEditor's `currentUserId` option)\n // makes every edit attributable for free, which is what\n // createAutoVersionHistory relies on for its own \"who changed this\"\n // tracking. `setDefaultActorId` below lets it change after construction\n // (e.g. identity resolves asynchronously after the editor already mounted).\n this.defaultActorId = defaultActorId;\n this.undoStack = [];\n this.redoStack = [];\n this.currentBatch = null;\n this.idleTimer = null;\n this.historyLog = [];\n this._listeners = new Set();\n this._undoRedoSnapshot = { canUndo: false, canRedo: false };\n this._pendingSelection = null;\n this._pendingAffectedBlockIds = [];\n // Opt-in, capped \"what changed, from what to what\" log — separate from\n // historyLog (which is just {opType, id, actorId, timestamp}, always\n // on) because storing actual before/after values has a real per-edit\n // memory cost. Off by default so it costs nothing for apps that never\n // ask for it; ring-buffered at maxChangeLogSize so a long session can't\n // grow it unbounded even with tracking on.\n this.trackChanges = trackChanges;\n this.maxChangeLogSize = maxChangeLogSize;\n this.changeLog = [];\n }\n\n /**\n * Appends one entry to the opt-in change log (see `trackChanges`) and\n * drops the oldest entry once over maxChangeLogSize. Only records actual\n * before/after *values* for updateRun/updateBlockProps — both carry a\n * small `patch` object on the op and its inverse already, so the diff is\n * free to capture. Structural ops (insert/remove/move block, ...) are\n * logged as the bare fact (opType/id/actorId/timestamp, before/after\n * left undefined) rather than snapshotting a whole block subtree, which\n * would defeat the point of keeping this lightweight.\n */\n _recordChange(op, inverse, meta) {\n if (!this.trackChanges) return;\n const hasPatch = op.patch !== undefined && inverse?.patch !== undefined;\n // A text `updateRun`'s inverse is `editRunChars`-shaped (see\n // operations.js), which has no `.patch` at all — its cosmetic-only\n // `previousValue` string is the equivalent \"before\" here.\n const previousValue = hasPatch ? undefined : previousValueFromInverse(inverse);\n this.changeLog.push({\n opType: op.type,\n id: op.id ?? op.blockId ?? op.block?.id,\n before: hasPatch\n ? inverse.patch\n : previousValue !== undefined\n ? { value: previousValue }\n : undefined,\n after: hasPatch ? op.patch : previousValue !== undefined ? op.patch : undefined,\n actorId: meta.actorId ?? null,\n timestamp: meta.timestamp ?? Date.now(),\n });\n if (this.changeLog.length > this.maxChangeLogSize) this.changeLog.shift();\n }\n\n /**\n * The opt-in change log (empty unless constructed with trackChanges:\n * true) — one entry per operation as it was originally applied, each\n * `{opType, id, before, after, actorId, timestamp}`. Same\n * independent-of-undo/redo convention as getHistoryLog: undoing an edit\n * doesn't erase or rewrite its original log entry.\n */\n getChangeLog() {\n return [...this.changeLog];\n }\n\n /**\n * Where the caret should move to after the undo/redo that was just\n * performed — {runId, offset}, or null when the entry wasn't a plain\n * text-run edit (structural ops) or carried no derivable caret. Read this\n * right after calling undo()/redo(); it's overwritten by the next call.\n */\n getPendingSelection() {\n return this._pendingSelection;\n }\n\n /**\n * Fallback for structural entries where getPendingSelection() is null —\n * ids (most-specific first) of blocks the just-undone/redone entry\n * touched, so a caller can focus the first one that still exists rather\n * than leaving focus wherever it happened to be (typically stale, since a\n * removed/re-inserted block is a brand-new DOM node). See\n * extractAffectedBlockIds for exactly what's collected.\n */\n getPendingAffectedBlockIds() {\n return this._pendingAffectedBlockIds;\n }\n\n /**\n * Cached {canUndo, canRedo} snapshot — only a new object when either value\n * actually changed, so useSyncExternalStore's getSnapshot can call this\n * every render without ever seeing a \"changed\" reference for no reason.\n */\n getUndoRedoSnapshot() {\n const canUndo = this.canUndo();\n const canRedo = this.canRedo();\n if (this._undoRedoSnapshot.canUndo !== canUndo || this._undoRedoSnapshot.canRedo !== canRedo) {\n this._undoRedoSnapshot = { canUndo, canRedo };\n }\n return this._undoRedoSnapshot;\n }\n\n // --- read surface: delegate straight through ---\n getBlock(id) {\n return this.store.getBlock(id);\n }\n\n getRun(id) {\n return this.store.getRun(id);\n }\n\n getRootId() {\n return this.store.getRootId();\n }\n\n getFieldTypes() {\n return this.store.getFieldTypes();\n }\n\n getFieldType(id) {\n return this.store.getFieldType(id);\n }\n\n getComments() {\n return this.store.getComments();\n }\n\n getComment(id) {\n return this.store.getComment(id);\n }\n\n getPeople() {\n return this.store.getPeople();\n }\n\n getPerson(id) {\n return this.store.getPerson(id);\n }\n\n getAllRunIds() {\n return this.store.getAllRunIds();\n }\n\n subscribe(id, listener) {\n return this.store.subscribe(id, listener);\n }\n\n subscribeAll(listener) {\n return this.store.subscribeAll(listener);\n }\n\n /**\n * Delegates straight to the store, deliberately outside perform/\n * performBatch — pruning tombstones never changes the visible document\n * (they were already invisible), so it isn't a user-facing edit and has\n * no business on the undo stack.\n */\n getTombstoneCount() {\n return this.store.getTombstoneCount();\n }\n\n pruneTombstones(options) {\n return this.store.pruneTombstones(options);\n }\n\n toJSON() {\n return this.store.toJSON();\n }\n\n // --- write surface ---\n applyOperation(op, meta = {}) {\n return this.perform(op, meta);\n }\n\n applyOperations(ops, meta = {}) {\n return ops.map((op) => this.perform(op, meta));\n }\n\n /**\n * Applies several operations as one atomic undo step (e.g. merging a\n * block into its previous sibling is remove-empty-block + reassign-\n * contentIds + delete-shell — three ops that must undo together, not one\n * press per op). Flushes any in-progress typing batch first so the merge\n * doesn't get folded into unrelated coalescing.\n */\n /** Changes the actorId future perform/performBatch calls fall back to when they don't pass their own `meta.actorId`. */\n setDefaultActorId(actorId) {\n this.defaultActorId = actorId;\n }\n\n performBatch(ops, meta = {}) {\n const actorId = meta.actorId ?? this.defaultActorId;\n const timestamp = meta.timestamp ?? Date.now();\n this._commitCurrentBatch();\n\n const inverses = [];\n for (const op of ops) {\n const inverse = this.store.applyOperation(op);\n inverses.unshift(inverse);\n this.historyLog.push({\n opType: op.type,\n id: op.id ?? op.blockId ?? op.block?.id,\n actorId,\n timestamp,\n });\n this._recordChange(op, inverse, { actorId, timestamp });\n }\n\n this.redoStack = [];\n this.undoStack.push({\n ops: [...ops],\n inverses,\n batchKey: null,\n actorId,\n timestamp,\n lastTimestamp: timestamp,\n boundaryHit: true,\n });\n this._notify();\n }\n\n perform(op, meta = {}) {\n const actorId = meta.actorId ?? this.defaultActorId;\n const timestamp = meta.timestamp ?? Date.now();\n const inverse = this.store.applyOperation(op);\n this._record(op, inverse, { actorId, timestamp });\n return inverse;\n }\n\n _batchKeyFor(op) {\n // Only same-run text edits coalesce; every structural op is its own step.\n return op.type === 'updateRun' ? `run:${op.id}` : null;\n }\n\n _isWordBoundary(op) {\n if (op.type !== 'updateRun') return false;\n const value = op.patch?.value;\n if (typeof value !== 'string' || value.length === 0) return false;\n return /\\s/.test(value[value.length - 1]);\n }\n\n _record(op, inverse, meta) {\n this.redoStack = [];\n const batchKey = this._batchKeyFor(op);\n const withinIdle =\n this.currentBatch && meta.timestamp - this.currentBatch.lastTimestamp <= this.idleMs;\n const sameBatch =\n this.currentBatch &&\n batchKey !== null &&\n this.currentBatch.batchKey === batchKey &&\n withinIdle &&\n !this.currentBatch.boundaryHit;\n\n if (sameBatch) {\n this.currentBatch.ops.push(op);\n this.currentBatch.inverses.unshift(inverse); // undo applies most-recent-first\n this.currentBatch.lastTimestamp = meta.timestamp;\n if (this._isWordBoundary(op)) this.currentBatch.boundaryHit = true;\n } else {\n this._commitCurrentBatch();\n this.currentBatch = {\n ops: [op],\n inverses: [inverse],\n batchKey,\n actorId: meta.actorId,\n timestamp: meta.timestamp,\n lastTimestamp: meta.timestamp,\n boundaryHit: this._isWordBoundary(op),\n };\n }\n\n this._resetIdleTimer();\n this.historyLog.push({\n opType: op.type,\n id: op.id ?? op.block?.id,\n actorId: meta.actorId,\n timestamp: meta.timestamp,\n });\n this._recordChange(op, inverse, meta);\n this._notify();\n }\n\n _resetIdleTimer() {\n if (this.idleTimer) clearTimeout(this.idleTimer);\n this.idleTimer = setTimeout(() => {\n this._commitCurrentBatch();\n this._notify();\n }, this.idleMs);\n }\n\n _commitCurrentBatch() {\n if (!this.currentBatch) return;\n this.undoStack.push(this.currentBatch);\n this.currentBatch = null;\n if (this.idleTimer) {\n clearTimeout(this.idleTimer);\n this.idleTimer = null;\n }\n }\n\n /** Force any in-progress coalescing batch to close (e.g. on blur). */\n flush() {\n this._commitCurrentBatch();\n this._notify();\n }\n\n undo() {\n this._commitCurrentBatch();\n const entry = this.undoStack.pop();\n if (!entry) return false;\n for (const inverse of entry.inverses) this.store.applyOperation(inverse);\n this.redoStack.push(entry);\n const selection = computeEntrySelection(entry);\n this._pendingSelection = selection\n ? { runId: selection.runId, offset: selection.beforeOffset }\n : null;\n this._pendingAffectedBlockIds = extractAffectedBlockIds(entry);\n this._notify();\n return true;\n }\n\n redo() {\n const entry = this.redoStack.pop();\n if (!entry) return false;\n for (const op of entry.ops) this.store.applyOperation(op);\n this.undoStack.push(entry);\n const selection = computeEntrySelection(entry);\n this._pendingSelection = selection\n ? { runId: selection.runId, offset: selection.afterOffset }\n : null;\n this._pendingAffectedBlockIds = extractAffectedBlockIds(entry);\n this._notify();\n return true;\n }\n\n canUndo() {\n return this.undoStack.length > 0 || this.currentBatch !== null;\n }\n\n canRedo() {\n return this.redoStack.length > 0;\n }\n\n /** Unbounded (never popped by undo/redo) who/when/what audit trail. */\n getHistoryLog() {\n return [...this.historyLog];\n }\n\n subscribeToHistory(listener) {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n _notify() {\n for (const listener of this._listeners) listener();\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 && (\n <span className=\"be-template-card-description\">{template.description}</span>\n )}\n </div>\n <button\n type=\"button\"\n className=\"be-template-card-select\"\n onClick={() => onSelect(template)}\n >\n Use\n </button>\n </li>\n ))}\n </ul>\n );\n}\n","import { genId } from '../utils/idGen.js';\nimport {\n addPerson as addPersonOp,\n updatePerson as updatePersonOp,\n removePerson as removePersonOp,\n} from '../store/operations.js';\n\n/**\n * Documented entry points for a document's own people list — real,\n * collaboration-aware document data (see EditorStore's `peopleWrite`\n * envelope handling), not device-local storage. This is what\n * `createSelectFieldType`'s \"Assignee\" usage is meant to source its\n * options from, so every collaborator on the same document sees and can\n * manage the same assignable people, the same way everyone sees the same\n * comment threads.\n *\n * Returns the new person's id.\n */\nexport function addPerson(store, { name, color }) {\n const id = genId();\n store.applyOperation(addPersonOp({ id, name, color }));\n return id;\n}\n\nexport function updatePerson(store, id, patch) {\n store.applyOperation(updatePersonOp(id, patch));\n}\n\nexport function removePerson(store, id) {\n store.applyOperation(removePersonOp(id));\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useEditorStore } from './EditorProvider.jsx';\n\nconst PEOPLE_KEY = '$people';\n\n/**\n * Subscribes to the document's own people list (see src/people/people.js) —\n * reactive so a \"manage assignees\" UI re-renders after add/update/remove,\n * including changes that arrived from a collaborator, the same way\n * useComments re-renders for remote comment activity. Not used by the\n * Assignee field type's own picker: that reads store.getPeople() fresh on\n * every keystroke via its options resolver, so a newly-added person shows\n * up there without any separate subscription.\n *\n * store.getPeople() returns a referentially-stable array (cached,\n * invalidated only by a people op, local or remote) — required by\n * useSyncExternalStore, same contract as useComments/useFieldTypes.\n */\nexport function usePeople() {\n const store = useEditorStore();\n const subscribe = useCallback(\n (onStoreChange) => store.subscribe(PEOPLE_KEY, onStoreChange),\n [store],\n );\n const getSnapshot = useCallback(() => store.getPeople(), [store]);\n return useSyncExternalStore(subscribe, getSnapshot);\n}\n","/**\n * Central registry of block types. Every consumer of a block's behavior\n * (the renderer, the slash-command menu, clipboard serialize/deserialize)\n * looks entries up here instead of switching on `block.type` itself — adding\n * a new block type is only ever \"call `register` once\".\n *\n * entry shape:\n * {\n * component, // React component, receives only { id }\n * isLeaf, // true if contentIds points at Runs, false if at child Blocks\n * defaultProps, // props for a freshly-inserted block of this type\n * toHTML(block, ctx), // ctx: { store, registry } -> html string\n * fromHTML(domNode, ctx), // -> constructed { block, runs } | null if this type doesn't claim the node\n * toPlainText(block, ctx), // -> plain text string\n * toMarkdown(block, ctx), // optional -> Markdown string; exportDocumentMarkdown falls back to toPlainText when absent\n * slashCommand: { label, icon, keywords, run(store, atBlockId) } | undefined,\n * slashCommands: [ { label, icon, keywords, run } ] | undefined // for a type offering more than one variant (e.g. listItem: bulleted/numbered/to-do)\n * }\n */\nexport class BlockRegistry {\n constructor() {\n this._types = new Map();\n }\n\n register(type, entry) {\n this._types.set(type, entry);\n }\n\n get(type) {\n return this._types.get(type);\n }\n\n isLeaf(type) {\n return Boolean(this._types.get(type)?.isLeaf);\n }\n\n listSlashCommands() {\n const commands = [];\n for (const entry of this._types.values()) {\n if (entry.slashCommand) commands.push(entry.slashCommand);\n if (entry.slashCommands) commands.push(...entry.slashCommands);\n }\n return commands;\n }\n\n listHtmlMatchers() {\n return [...this._types.values()].filter((entry) => entry.fromHTML);\n }\n}\n\nexport function createBlockRegistry() {\n return new BlockRegistry();\n}\n","/**\n * Registry of inline run types beyond plain text — e.g. a `select` chip, a\n * `date` chip, mixed directly into a paragraph's running text alongside\n * ordinary text runs. Parallel to BlockRegistry: `RunNode` (the per-run\n * renderer) looks entries up here instead of switching on `run.type`\n * itself, so adding a new inline type is only ever \"call `register` once\".\n *\n * entry shape:\n * {\n * component, // React component, receives only { id } (like BlockRenderer's contract)\n * isAtomic: true, // always true today: every registered inline type renders as a single\n * // contentEditable=false island (see RunNode) — the browser then handles\n * // arrow-key skip-over and single-backspace-delete for it natively.\n * toHTML(run, ctx), // ctx: { store, registry, inlineRegistry } -> html string\n * fromHTML(domNode, ctx), // -> constructed Run | null if this type doesn't claim the node\n * toPlainText(run, ctx), // -> plain text string\n * slashCommand: { label, icon, keywords, run(store, {blockId, runId}) } | undefined,\n * slashCommands: [ { label, icon, keywords, run } ] | undefined // for a type offering several commands\n * // at once (e.g. emoji: one entry per emoji, all sharing an \"emoji\" keyword)\n * // — mirrors BlockRegistry's own singular/plural split.\n * atCommand / atCommands, // same shape as slashCommand/slashCommands, listed under useAtMenuTrigger's\n * // \"@\" trigger instead of (or in addition to) \"/\" — e.g. createSelectFieldType's\n * // `triggers` option decides which of these two lists a given field type joins.\n * // A command object itself doesn't care which character triggered it (`run`\n * // only consumes {blockId, runId, sliceStart, sliceEnd}), so the very same\n * // object can be — and typically is — assigned to both slashCommand and atCommand.\n * }\n *\n * A plain `type: 'text'` run is handled directly by RunNode and never goes\n * through this registry — there's nothing to register for it.\n */\nexport class InlineRegistry {\n constructor() {\n this._types = new Map();\n }\n\n register(type, entry) {\n this._types.set(type, entry);\n }\n\n /** Drops a registered type — e.g. deleting a user-created custom field type. */\n unregister(type) {\n this._types.delete(type);\n }\n\n get(type) {\n return this._types.get(type);\n }\n\n listHtmlMatchers() {\n return [...this._types.values()].filter((entry) => entry.fromHTML);\n }\n\n listSlashCommands() {\n const commands = [];\n for (const entry of this._types.values()) {\n if (entry.slashCommand) commands.push(entry.slashCommand);\n if (entry.slashCommands) commands.push(...entry.slashCommands);\n }\n return commands;\n }\n\n /** Same shape as listSlashCommands, sourced from atCommand/atCommands instead — see useAtMenuTrigger. */\n listAtCommands() {\n const commands = [];\n for (const entry of this._types.values()) {\n if (entry.atCommand) commands.push(entry.atCommand);\n if (entry.atCommands) commands.push(...entry.atCommands);\n }\n return commands;\n }\n}\n\nexport function createInlineRegistry() {\n return new InlineRegistry();\n}\n","import { paragraphBlockType } from './paragraph/index.js';\nimport { headingBlockType } from './heading/index.js';\nimport { listItemBlockType } from './listItem/index.js';\nimport { tableBlockType, tableRowBlockType, tableCellBlockType } from './table/index.js';\nimport { layoutBlockType, layoutColumnBlockType } from './layout/index.js';\nimport { dividerBlockType } from './divider/index.js';\nimport { calloutBlockType } from './callout/index.js';\nimport { blockquoteBlockType } from './blockquote/index.js';\nimport { codeBlockType } from './code/index.js';\nimport { toggleHeadingBlockType } from './toggleHeading/index.js';\nimport { buttonBlockType } from './button/index.js';\nimport { embedBlockType } from './embed/index.js';\nimport { canvasBlockType } from './canvas/index.js';\n\n/** Registers every built-in block type on the given registry. */\nexport function registerBuiltInBlocks(registry) {\n registerBlocks(registry, {\n paragraph: paragraphBlockType,\n heading: headingBlockType,\n listItem: listItemBlockType,\n ...TABLE_BLOCKS,\n ...LAYOUT_BLOCKS,\n divider: dividerBlockType,\n callout: calloutBlockType,\n blockquote: blockquoteBlockType,\n code: codeBlockType,\n toggleHeading: toggleHeadingBlockType,\n button: buttonBlockType,\n embed: embedBlockType,\n canvas: canvasBlockType,\n });\n}\n\n/**\n * Registers only the block types you name — the opt-in counterpart to\n * `registerBuiltInBlocks`, for a consumer who wants (say) just paragraph,\n * heading, and table, with nothing else's code even reachable from their\n * bundle. `blocksByType` is `{ [type]: blockTypeEntry }`; every built-in\n * block type object below (`paragraphBlockType`, `tableBlockType`, ...) is\n * published individually for exactly this purpose — plain, tree-shakeable\n * values, not something living only inside this file's own registration\n * call.\n *\n * `table` and `layout` are each three/two block types that only work\n * together (a table with no `tableRow`/`tableCell` registered can't render\n * its own rows) — see `TABLE_BLOCKS`/`LAYOUT_BLOCKS` below, spread the\n * whole group in rather than picking pieces of one apart.\n */\nexport function registerBlocks(registry, blocksByType) {\n for (const [type, entry] of Object.entries(blocksByType)) {\n registry.register(type, entry);\n }\n}\n\n/** `table` needs its row/cell block types registered alongside it — spread this whole group in together. */\nexport const TABLE_BLOCKS = {\n table: tableBlockType,\n tableRow: tableRowBlockType,\n tableCell: tableCellBlockType,\n};\n\n/** `layout` needs its column block type registered alongside it — spread this whole group in together. */\nexport const LAYOUT_BLOCKS = {\n layout: layoutBlockType,\n layoutColumn: layoutColumnBlockType,\n};\n\nexport {\n paragraphBlockType,\n headingBlockType,\n listItemBlockType,\n tableBlockType,\n tableRowBlockType,\n tableCellBlockType,\n layoutBlockType,\n layoutColumnBlockType,\n dividerBlockType,\n calloutBlockType,\n blockquoteBlockType,\n codeBlockType,\n toggleHeadingBlockType,\n buttonBlockType,\n embedBlockType,\n canvasBlockType,\n};\n","import { selectInlineType } from './select/index.js';\nimport { dateInlineType } from './date/index.js';\nimport { checkboxInlineType } from './checkbox/index.js';\nimport { tableSelectInlineType } from './tableSelect/index.js';\nimport { emojiInlineType } from './emoji/index.js';\n\n/**\n * Registers every built-in inline type on the given inline registry. Not\n * on this list: \"mention\"-style @-someone chips — those are now just an\n * ordinary use of createSelectFieldType with `triggers: ['slash', 'at']`\n * (see the example app's \"Assignee\" field type), rather than a separate\n * hardcoded built-in, since a real app's roster/search always needs to be\n * host-supplied anyway.\n */\nexport function registerBuiltInInlineTypes(inlineRegistry) {\n registerInlineTypes(inlineRegistry, {\n select: selectInlineType,\n date: dateInlineType,\n checkbox: checkboxInlineType,\n ...TABLE_SELECT_INLINE_TYPES,\n emoji: emojiInlineType,\n });\n}\n\n/** Opt-in counterpart to `registerBuiltInInlineTypes` — see registerBlocks's own doc comment, same idea for inline types. */\nexport function registerInlineTypes(inlineRegistry, typesByType) {\n for (const [type, entry] of Object.entries(typesByType)) {\n inlineRegistry.register(type, entry);\n }\n}\n\n/** Only relevant alongside TABLE_BLOCKS (see blocks/index.js) — powers a table column set to \"select\" type. */\nexport const TABLE_SELECT_INLINE_TYPES = { tableSelect: tableSelectInlineType };\n\nexport {\n selectInlineType,\n dateInlineType,\n checkboxInlineType,\n tableSelectInlineType,\n emojiInlineType,\n};\n","// Optional typing-behavior extensions, expressed with defineExtension()'s\n// `onBeforeInput` hook. Framework-free — they mutate through `ctx` (whose\n// applyOperation already wraps flushSync so the DOM is in sync before\n// setCaret). These are the same behaviors as the older `useSmartQuotes` /\n// `useAutoPairBrackets` hooks, repackaged so they drop into\n// `useEditor({ extensions: [smartQuotes()] })` alongside blocks and chips.\n\nimport { defineExtension } from '../registry/define.js';\nimport { updateRun } from '../store/operations.js';\n\nconst CURLY = {\n '\"': { open: '“', close: '”' },\n \"'\": { open: '‘', close: '’' },\n};\n\n// Whitespace, start-of-line, or an opening bracket/quote before the caret ->\n// the next quote is an opening one; anything else (usually a letter, as in an\n// apostrophe) -> a closing one.\nfunction pickQuote(char, precedingChar) {\n const pair = CURLY[char];\n if (precedingChar === undefined || /[\\s([{“‘]/.test(precedingChar)) return pair.open;\n return pair.close;\n}\n\nfunction singleInsertChar(event) {\n if (event.inputType !== 'insertText' || !event.data || event.data.length !== 1) return null;\n return event.data;\n}\n\nfunction isType(ctx, blockId, type) {\n return ctx.getBlock(blockId)?.type === type;\n}\n\n/**\n * Straight `\"` / `'` typed while composing becomes the contextually correct\n * curly quote (one char in, one out). Typing one with text selected wraps the\n * selection in an open+close pair. Off inside `code` blocks.\n */\nexport function smartQuotes() {\n return defineExtension({\n name: 'smart-quotes',\n onBeforeInput(ctx, event) {\n const char = singleInsertChar(event);\n if (!char || !CURLY[char]) return false;\n const pair = CURLY[char];\n\n const selection = ctx.getSelection();\n if (selection) {\n if (isType(ctx, selection.blockId, 'code')) return false;\n const run = ctx.getRun(selection.runId);\n if (!run || run.type !== 'text') return false;\n const value = run.value ?? '';\n const next =\n value.slice(0, selection.startOffset) +\n pair.open +\n value.slice(selection.startOffset, selection.endOffset) +\n pair.close +\n value.slice(selection.endOffset);\n ctx.applyOperation(updateRun(run.id, { value: next }));\n ctx.setCaret(run.id, selection.endOffset + 2);\n return true;\n }\n\n const caret = ctx.getCaret();\n if (!caret || isType(ctx, caret.blockId, 'code')) return false;\n const run = ctx.getRun(caret.runId);\n if (!run || run.type !== 'text') return false;\n const value = run.value ?? '';\n const quote = pickQuote(char, value[caret.offset - 1]);\n ctx.applyOperation(\n updateRun(run.id, {\n value: value.slice(0, caret.offset) + quote + value.slice(caret.offset),\n }),\n );\n ctx.setCaret(run.id, caret.offset + 1);\n return true;\n },\n });\n}\n\nconst OPENERS = { '(': ')', '[': ']', '{': '}' };\nconst CLOSERS = new Set(Object.values(OPENERS));\n\n/**\n * Typing `(` `[` `{` inserts the matching closer and puts the caret between\n * them; typing a closer already sitting ahead of the caret just steps past it;\n * typing an opener with text selected wraps the selection. Off inside `code`\n * blocks. Excludes quotes — that's `smartQuotes()`.\n */\nexport function autoPairBrackets() {\n return defineExtension({\n name: 'auto-pair-brackets',\n onBeforeInput(ctx, event) {\n const char = singleInsertChar(event);\n if (!char) return false;\n const closer = OPENERS[char];\n\n if (closer) {\n const selection = ctx.getSelection();\n if (selection) {\n if (isType(ctx, selection.blockId, 'code')) return false;\n const run = ctx.getRun(selection.runId);\n if (!run || run.type !== 'text') return false;\n const value = run.value ?? '';\n const next =\n value.slice(0, selection.startOffset) +\n char +\n value.slice(selection.startOffset, selection.endOffset) +\n closer +\n value.slice(selection.endOffset);\n ctx.applyOperation(updateRun(run.id, { value: next }));\n ctx.setCaret(run.id, selection.endOffset + 2);\n return true;\n }\n\n const caret = ctx.getCaret();\n if (!caret || isType(ctx, caret.blockId, 'code')) return false;\n const run = ctx.getRun(caret.runId);\n if (!run || run.type !== 'text') return false;\n const value = run.value ?? '';\n ctx.applyOperation(\n updateRun(run.id, {\n value: value.slice(0, caret.offset) + char + closer + value.slice(caret.offset),\n }),\n );\n ctx.setCaret(run.id, caret.offset + 1);\n return true;\n }\n\n if (CLOSERS.has(char)) {\n const caret = ctx.getCaret();\n if (!caret || isType(ctx, caret.blockId, 'code')) return false;\n const run = ctx.getRun(caret.runId);\n if (!run || run.type !== 'text') return false;\n if ((run.value ?? '')[caret.offset] === char) {\n ctx.setCaret(run.id, caret.offset + 1);\n return true;\n }\n }\n return false;\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(\n cell.contentIds.map((runId) => store.getRun(runId)),\n ctx,\n );\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(\n runIds.map((id) => store.getRun(id)),\n ctx,\n );\n } else if (registry.isLeaf(type) && !NO_TEXT_LEAF_TYPES.has(type)) {\n data.text = runsToHTML(\n block.contentIds.map((id) => store.getRun(id)),\n ctx,\n );\n }\n\n const result = { id: block.id, type, data };\n if (!registry.isLeaf(type)) {\n result.children = block.contentIds.map((childId) =>\n exportBlock(store, registry, store.getBlock(childId), ctx),\n );\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({\n id: cellId,\n type: 'tableCell',\n parentId: rowId,\n contentIds: runs.map((r) => r.id),\n props: {},\n });\n return cellId;\n });\n blocksOut.push({ id: rowId, type: 'tableRow', parentId, contentIds: cellIds, props: {} });\n return rowId;\n });\n const block = {\n id,\n type: 'table',\n parentId,\n contentIds: rowIds,\n props: { columns: data.columns ?? [] },\n };\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(\n (child) => importBlock(child, id, registry, ctx, blocksOut, runsOut).id,\n );\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(\n (child) => importBlock(child, id, registry, ctx, blocksOut, runsOut).id,\n );\n }\n\n return block;\n}\n\n/**\n * True when `doc` is a simple-format document (`{ version, blocks: [...] }`),\n * as opposed to the internal engine shape (`{ rootId, blocks, runs }`). The\n * internal shape always carries `rootId` and a `runs` array; the simple one\n * carries neither. Used by `useEditor({ doc })` to accept either.\n */\nexport function isSimpleDocument(doc) {\n return (\n Boolean(doc) &&\n typeof doc === 'object' &&\n Array.isArray(doc.blocks) &&\n doc.rootId === undefined &&\n doc.runs === undefined\n );\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(\n (b) => importBlock(b, rootId, registry, ctx, blocksOut, runsOut).id,\n );\n blocksOut.push({ id: rootId, type: 'page', parentId: null, contentIds: topIds, props: {} });\n return { rootId, blocks: blocksOut, runs: runsOut };\n}\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 { registerExtensions } from '../registry/define.js';\nimport {\n isSimpleDocument,\n importDocumentSimpleJSON,\n exportDocumentSimpleJSON,\n} from '../clipboard/simpleFormat.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 * `extensions` is the newer, recommended way to pick what's registered: an\n * array of `defineBlock()` / `defineInline()` results (nesting allowed), e.g.\n * `useEditor({ extensions: [...starterKit(), myBlock] })`. Passing it turns\n * OFF the automatic built-in registration (like `registerBlocks` does), so\n * spread `starterKit()` in if you want the usual set. `registerBlocks` /\n * `registerInlineTypes` are the older callback form — still supported, and\n * they run *after* `extensions` if you pass both, so you can add a few\n * imperatively on top. With none of the three given, every built-in block and\n * inline type is registered.\n *\n * `doc` may be EITHER the internal engine shape (`{ rootId, blocks, runs }`,\n * what `store.toJSON()` / `exportDocumentJSON` produce) OR the simple format\n * (`{ version, blocks: [{ id, type, data, children? }] }`, what\n * `exportDocumentSimpleJSON` produces and `editor.toJSON()` returns by\n * default) — the shape is auto-detected. `editor.toJSON({ format })` reads the\n * live document back out: `'simple'` (default) or `'internal'`.\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 extensions,\n registerBlocks: customRegisterBlocks,\n registerInlineTypes: customRegisterInlineTypes,\n} = {}) {\n return useMemo(() => {\n const registry = createBlockRegistry();\n const inlineRegistry = createInlineRegistry();\n\n if (extensions != null) {\n registerExtensions(extensions, { registry, inlineRegistry });\n }\n // Block and inline registration are independent: an explicit callback for\n // one side doesn't suppress the built-ins on the other. `extensions`\n // suppresses the built-ins on both sides (opt-in), but a callback passed\n // alongside it still runs, on top.\n if (customRegisterBlocks) customRegisterBlocks(registry);\n else if (extensions == null) registerBuiltInBlocks(registry);\n\n if (customRegisterInlineTypes) customRegisterInlineTypes(inlineRegistry);\n else if (extensions == null) registerBuiltInInlineTypes(inlineRegistry);\n\n const internalDoc =\n doc == null\n ? defaultDoc()\n : isSimpleDocument(doc)\n ? importDocumentSimpleJSON(doc, registry, inlineRegistry)\n : doc;\n const rawStore = new EditorStore(internalDoc);\n const store = history ? new History(rawStore, { defaultActorId: currentUserId }) : rawStore;\n\n return {\n store,\n registry,\n inlineRegistry,\n // Flattened extension list — <NoteloomEditor> feeds this to\n // useExtensionBehaviors for the keymap/onBeforeInput/onPaste/setup half.\n // Block/inline definitions are already registered above; they're kept in\n // the list too but ignored there (no behavior fields).\n extensions: extensions != null ? extensions.flat(Infinity) : [],\n // Read the live document back out. 'simple' (default) is the canonical\n // interchange format; 'internal' is the normalized engine graph.\n toJSON: ({ format = 'simple' } = {}) =>\n format === 'internal'\n ? store.toJSON()\n : JSON.parse(exportDocumentSimpleJSON(store, registry, inlineRegistry)),\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n}\n","import { useCallback } from 'react';\nimport { useEditorStore, usePreviewMode } from './EditorProvider.jsx';\nimport { insertSiblingAfterAndFocus } from '../blocks/shared/blockCommands.js';\nimport { createTextLeafBlock } from '../blocks/shared/leafBlockFactory.js';\nimport { focusBlockEnd } from '../blocks/shared/navigationCommands.js';\nimport { ensureRootNonEmpty } from '../blocks/shared/ensureRootNonEmpty.js';\n\n/**\n * Matches every real editor's \"click below the last block to keep writing\"\n * affordance: a plain clickable strip below the\n * document's own content, sized so there's always somewhere to click even\n * when the last block fills the viewport. If the last top-level block is\n * already a paragraph, clicking here just moves the caret to its end —\n * clicking below your own last paragraph shouldn't create a new empty one\n * under it. For anything else (a heading, list, table, embed, ...), there's\n * nothing to place a text caret in at that position, so a fresh paragraph\n * is inserted after it and focused instead.\n *\n * A no-op in preview mode (see usePreviewMode) — a preview isn't something\n * you edit, so clicking below its content shouldn't create a new block.\n */\nexport function EditorTrailingSpace({ minHeight = 180, className = 'be-trailing-space' }) {\n const store = useEditorStore();\n const [isPreviewMode] = usePreviewMode();\n\n const handleClick = useCallback(() => {\n if (isPreviewMode) return;\n const rootId = store.getRootId();\n const root = store.getBlock(rootId);\n const lastId = root?.contentIds?.[root.contentIds.length - 1];\n\n if (!lastId) {\n const fallbackId = ensureRootNonEmpty(store);\n if (fallbackId) focusBlockEnd(store, fallbackId);\n return;\n }\n\n const lastBlock = store.getBlock(lastId);\n if (lastBlock?.type === 'paragraph') {\n focusBlockEnd(store, lastId);\n } else {\n insertSiblingAfterAndFocus(store, lastId, createTextLeafBlock('paragraph'));\n }\n }, [store, isPreviewMode]);\n\n return <div className={className} style={{ minHeight }} onClick={handleClick} />;\n}\n","import { serializeBlockRange } from './serialize.js';\n\n/**\n * Writes a block range to the system clipboard via the async\n * `navigator.clipboard` API — used by BlockRangeActionMenu's Copy/Cut\n * buttons, which aren't a native `copy`/`cut` ClipboardEvent (those go\n * through useClipboardHandlers' synchronous, `event.clipboardData` path\n * instead, which is the only one that can carry the app's own lossless\n * MIME type — see serialize.js's own doc comment on that risk). The async\n * API's `ClipboardItem` support for arbitrary MIME types is inconsistent\n * across browsers, so this deliberately only ever writes `text/plain` and\n * `text/html` — a paste elsewhere (or back into this editor) still works\n * via the same text/html -> domWalk fallback path an external app's copy\n * would use, just without the same-editor lossless round-trip.\n */\nexport async function copyBlockRangeToClipboard(store, registry, inlineRegistry, blockIds) {\n const { html, text } = serializeBlockRange(store, registry, blockIds, inlineRegistry);\n if (typeof ClipboardItem !== 'undefined' && navigator.clipboard?.write) {\n await navigator.clipboard.write([\n new ClipboardItem({\n 'text/plain': new Blob([text], { type: 'text/plain' }),\n 'text/html': new Blob([html], { type: 'text/html' }),\n }),\n ]);\n return;\n }\n await navigator.clipboard?.writeText?.(text);\n}\n","import { removeBlock, moveBlock, updateBlockProps } from '../../store/operations.js';\nimport { isTurnIntoEligible, turnBlockInto } from './turnInto.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 * Removes every block in `blockIds` (a contiguous run — see\n * useBlockRangeDrag) as ONE atomic undo step, regardless of how many\n * blocks are in the range. Each `removeBlock` op looks its own target's\n * index up fresh at apply time (see EditorStore), so issuing one op per id\n * in document order is correct without any special ordering care.\n */\nexport function deleteBlockRange(store, blockIds) {\n if (blockIds.length === 0) return;\n applyOps(\n store,\n blockIds.map((id) => removeBlock(id)),\n );\n}\n\n/**\n * Moves the whole contiguous range up by one sibling position — implemented\n * as swapping the range with its immediately preceding sibling (ONE\n * `moveBlock` op moving that single neighbor to just after the range's new\n * end) rather than moving every block in the range individually. Returns\n * false (no-op) if the range is already at the top.\n */\nexport function moveBlockRangeUp(store, blockIds) {\n if (blockIds.length === 0) return false;\n const first = store.getBlock(blockIds[0]);\n if (!first) return false;\n const parent = store.getBlock(first.parentId);\n if (!parent) return false;\n\n const startIndex = parent.contentIds.indexOf(blockIds[0]);\n const endIndex = parent.contentIds.indexOf(blockIds[blockIds.length - 1]);\n if (startIndex <= 0) return false;\n\n const precedingId = parent.contentIds[startIndex - 1];\n store.applyOperation(moveBlock(precedingId, first.parentId, endIndex));\n return true;\n}\n\n/** Symmetric to moveBlockRangeUp — swaps the range with its immediately following sibling. */\nexport function moveBlockRangeDown(store, blockIds) {\n if (blockIds.length === 0) return false;\n const first = store.getBlock(blockIds[0]);\n if (!first) return false;\n const parent = store.getBlock(first.parentId);\n if (!parent) return false;\n\n const startIndex = parent.contentIds.indexOf(blockIds[0]);\n const endIndex = parent.contentIds.indexOf(blockIds[blockIds.length - 1]);\n if (endIndex === -1 || endIndex >= parent.contentIds.length - 1) return false;\n\n const followingId = parent.contentIds[endIndex + 1];\n store.applyOperation(moveBlock(followingId, first.parentId, startIndex));\n return true;\n}\n\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\". */\nexport function isEntireBlockRangeHidden(store, blockIds) {\n return blockIds.length > 0 && blockIds.every((id) => Boolean(store.getBlock(id)?.props?.hidden));\n}\n\n/** Sets props.hidden on every block in the range, one atomic undo step. */\nexport function setBlockRangeHidden(store, blockIds, hidden) {\n if (blockIds.length === 0) return;\n applyOps(\n store,\n blockIds.map((id) => updateBlockProps(id, { hidden })),\n );\n}\n\n/**\n * Converts every *eligible* (see `isTurnIntoEligible`) block in the range to\n * `target` ({ type, props }), as ONE atomic undo step for the whole range —\n * ineligible blocks (table, embed, divider, ...) are silently left\n * untouched rather than erroring, matching the same \"skip, don't fail\"\n * behavior every reference editor's own multi-select conversion has.\n *\n * Every block's own `ops` are computed by `turnBlockInto` up front, against\n * the store's state as it stood *before* any of this range's conversions\n * were applied — each conversion replaces one block with one new block at\n * the exact same slot, which never shifts any sibling's index, so it's\n * safe to compute every block's ops first (in document order) and apply\n * the full concatenated batch only once at the end, rather than\n * interleaving compute-then-apply per block.\n */\nexport function convertBlockRangeType(store, registry, blockIds, target) {\n const eligibleIds = blockIds.filter((id) => isTurnIntoEligible(store.getBlock(id)?.type));\n if (eligibleIds.length === 0) return;\n const allOps = eligibleIds.flatMap((id) => turnBlockInto(store, registry, id, target).ops);\n applyOps(store, allOps);\n}\n\n/**\n * Re-derives a previously-captured id set's DOCUMENT order from the\n * store's current contentIds — used after a move/hide action to keep\n * `selectedBlockRange` valid (same ids, correct order) without the caller\n * needing to know the tree shape itself.\n */\nexport function reorderBlockRangeFromStore(store, blockIds) {\n if (blockIds.length === 0) return [];\n const first = store.getBlock(blockIds[0]);\n const parent = first && store.getBlock(first.parentId);\n if (!parent) return blockIds;\n const idSet = new Set(blockIds);\n return parent.contentIds.filter((id) => idSet.has(id));\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n useEditorStore,\n useBlockRegistry,\n useInlineRegistry,\n useBlockRangeSelection,\n} from './EditorProvider.jsx';\nimport { copyBlockRangeToClipboard } from '../clipboard/copyBlockRange.js';\nimport { useMenuKeyboardNav } from './useMenuKeyboardNav.js';\nimport { useAutoAdjustedPosition } from './useAutoAdjustedPosition.js';\nimport { announce } from './liveAnnouncer.js';\nimport { TurnIntoSubmenu } from './TurnIntoSubmenu.jsx';\nimport { isTurnIntoEligible } from '../blocks/shared/turnInto.js';\nimport {\n deleteBlockRange,\n moveBlockRangeUp,\n moveBlockRangeDown,\n isEntireBlockRangeHidden,\n setBlockRangeHidden,\n convertBlockRangeType,\n} from '../blocks/shared/blockRangeActions.js';\nimport {\n CopyIcon,\n ScissorsIcon,\n TrashIcon,\n ArrowUpIcon,\n ArrowDownIcon,\n EyeIcon,\n EyeOffIcon,\n} from './icons.jsx';\n\n/**\n * The action menu that appears once a gutter-margin drag (see\n * useBlockRangeDrag) finishes selecting a run of blocks — Copy, Cut,\n * Delete, Move up/down, Hide/Show in preview, all applied to the whole\n * range as one atomic undo step apiece. Mount this once anywhere under\n * EditorProvider (it reads useBlockRangeSelection itself, same pattern as\n * FieldTypeEditorModal); it renders nothing while nothing is range-selected.\n *\n * Positioned off the LAST selected block's own row — recomputed on every\n * range change (including live, mid-drag), so it visibly follows a\n * growing/shrinking selection rather than only appearing once, stale, at\n * mouseup.\n *\n * Outside-click/Escape/Delete are handled with a bespoke listener here\n * rather than the shared useOutsideClickAndEscape hook: a click on a\n * *different* block's gutter must start a brand-new drag (BlockGutterRow's\n * own onMouseDown → startDrag) rather than being swallowed as \"outside\n * click, clear the old selection\" — since both listeners are native\n * `mousedown` handlers, a generic ref-based exemption can't express \"except\n * anywhere with a `.be-block-gutter` ancestor\" the way this needs.\n */\nexport function BlockRangeActionMenu() {\n const store = useEditorStore();\n const registry = useBlockRegistry();\n const inlineRegistry = useInlineRegistry();\n const [selectedBlockRange, setSelectedBlockRange] = useBlockRangeSelection();\n const [rect, setRect] = useState(null);\n const menuRef = useRef(null);\n const turnIntoMenuRef = useRef(null);\n\n const isOpen = selectedBlockRange.length > 0;\n const position = useAutoAdjustedPosition(\n menuRef,\n isOpen,\n rect?.bottom != null ? rect.bottom + 4 : null,\n rect?.left,\n );\n const clear = useCallback(() => setSelectedBlockRange([]), [setSelectedBlockRange]);\n // No single \"trigger button\" here (the menu appears after a drag gesture,\n // not a click) — passed as undefined, which the hook handles fine; this\n // still gets arrow-key/Home/End navigation between its own menu items.\n useMenuKeyboardNav(menuRef, isOpen, clear, undefined);\n\n useEffect(() => {\n if (!isOpen) {\n setRect(null);\n return undefined;\n }\n\n // Recomputed on scroll/resize, not just once per selection change — the\n // menu is position:fixed off a getBoundingClientRect() snapshot, which\n // is only valid for the instant it was measured. Without this, scrolling\n // the page after selecting a range leaves the menu stuck at its old\n // viewport position while the actual selected blocks scroll away\n // underneath it (exactly the \"menu drifts away from the selection\"\n // symptom) instead of staying anchored to the last selected block's row.\n const recompute = () => {\n const lastId = selectedBlockRange[selectedBlockRange.length - 1];\n const el = document.querySelector(`[data-block-row-id=\"${lastId}\"]`);\n setRect(el?.getBoundingClientRect() ?? null);\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 }, [isOpen, selectedBlockRange]);\n\n useEffect(() => {\n if (!isOpen) return undefined;\n\n const handlePointerDown = (event) => {\n if (menuRef.current?.contains(event.target)) return;\n // The Turn into item's own submenu is a separate portal (a DOM sibling\n // of this menu, not a descendant) — without this, a click inside it\n // reads as \"outside\", clearing the selection and unmounting the\n // submenu before its own click handler ever fires. See\n // TurnIntoSubmenu's doc comment for the full story.\n if (turnIntoMenuRef.current?.contains(event.target)) return;\n if (event.target.closest?.('.be-block-gutter')) return; // let that gutter's own drag-start take over\n clear();\n };\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') {\n clear();\n } else if (event.key === 'Delete' || event.key === 'Backspace') {\n event.preventDefault();\n deleteBlockRange(store, selectedBlockRange);\n clear();\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 }, [isOpen, store, selectedBlockRange, clear]);\n\n const blockWord = (n) => (n === 1 ? 'block' : 'blocks');\n\n const handleCopy = useCallback(() => {\n copyBlockRangeToClipboard(store, registry, inlineRegistry, selectedBlockRange);\n announce(`${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} copied`);\n clear();\n }, [store, registry, inlineRegistry, selectedBlockRange, clear]);\n\n const handleCut = useCallback(async () => {\n await copyBlockRangeToClipboard(store, registry, inlineRegistry, selectedBlockRange);\n const count = selectedBlockRange.length;\n deleteBlockRange(store, selectedBlockRange);\n announce(`${count} ${blockWord(count)} cut`);\n clear();\n }, [store, registry, inlineRegistry, selectedBlockRange, clear]);\n\n const handleDelete = useCallback(() => {\n const count = selectedBlockRange.length;\n deleteBlockRange(store, selectedBlockRange);\n announce(`${count} ${blockWord(count)} deleted`);\n clear();\n }, [store, selectedBlockRange, clear]);\n\n // Every action below closes the menu and clears the selection once it's\n // done (matching \"click an option, it acts on the selection, the\n // selection and menu both go away\" — a host that wants to keep acting on\n // the same range repeatedly can just re-drag-select it) — Move up/down\n // and Hide/Show used to keep the range selected instead, to allow several\n // moves/toggles in a row without reselecting, but a lingering menu after\n // an action was already taken read as \"did my click even do anything?\".\n const handleMoveUp = useCallback(() => {\n if (moveBlockRangeUp(store, selectedBlockRange)) {\n announce(`${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} moved up`);\n }\n clear();\n }, [store, selectedBlockRange, clear]);\n\n const handleMoveDown = useCallback(() => {\n if (moveBlockRangeDown(store, selectedBlockRange)) {\n announce(`${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} moved down`);\n }\n clear();\n }, [store, selectedBlockRange, clear]);\n\n const isHidden = isEntireBlockRangeHidden(store, selectedBlockRange);\n const handleToggleHidden = useCallback(() => {\n setBlockRangeHidden(store, selectedBlockRange, !isHidden);\n announce(\n isHidden\n ? `${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} shown in preview`\n : `${selectedBlockRange.length} ${blockWord(selectedBlockRange.length)} hidden in preview`,\n );\n clear();\n }, [store, selectedBlockRange, isHidden, clear]);\n\n const hasEligibleBlock = selectedBlockRange.some((id) =>\n isTurnIntoEligible(store.getBlock(id)?.type),\n );\n const handleTurnInto = useCallback(\n (target) => {\n const count = selectedBlockRange.length;\n convertBlockRangeType(store, registry, selectedBlockRange, target);\n announce(`${count} ${blockWord(count)} turned into ${target.label}`);\n clear();\n },\n [store, registry, selectedBlockRange, clear],\n );\n\n if (!isOpen || !position) return null;\n\n return createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n aria-label=\"Selected blocks options\"\n className=\"be-block-range-menu\"\n style={{ position: 'fixed', top: position.top, left: position.left }}\n >\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-block-range-menu-item\"\n onClick={handleCopy}\n >\n <CopyIcon size={15} /> Copy\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-block-range-menu-item\"\n onClick={handleCut}\n >\n <ScissorsIcon size={15} /> Cut\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-block-range-menu-item\"\n onClick={handleMoveUp}\n >\n <ArrowUpIcon size={15} /> Move up\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-block-range-menu-item\"\n onClick={handleMoveDown}\n >\n <ArrowDownIcon size={15} /> Move down\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-block-range-menu-item\"\n onClick={handleToggleHidden}\n >\n {isHidden ? <EyeIcon size={15} /> : <EyeOffIcon size={15} />}\n {isHidden ? 'Show in preview' : 'Hide in preview'}\n </button>\n {hasEligibleBlock && (\n <TurnIntoSubmenu\n onSelect={handleTurnInto}\n onClose={() => {}}\n containerRef={turnIntoMenuRef}\n menuClassName=\"be-block-range-menu\"\n itemClassName=\"be-block-range-menu-item\"\n />\n )}\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-block-range-menu-item be-block-range-menu-item-danger\"\n onClick={handleDelete}\n >\n <TrashIcon size={15} /> Delete\n </button>\n </div>,\n document.body,\n );\n}\n","// Custom clipboard MIME type for lossless same-editor copy/paste round-trips.\n// Reliable via the synchronous ClipboardEvent path used in useClipboardHandlers;\n// NOT guaranteed via the async navigator.clipboard.write/ClipboardItem API —\n// if a toolbar \"Copy\" button is added later, restrict it to text/plain+text/html.\nexport const APP_MIME = 'application/x-block-editor-blocks+json';\n","import { domInlineToRuns } from '../inline/runOps.js';\nimport { genId } from '../utils/idGen.js';\n\nexport function textToParagraphs(text) {\n return text\n .split(/\\r\\n|\\r|\\n/)\n .filter((line) => line.length > 0)\n .map((line) => {\n const runId = genId();\n return {\n block: { id: genId(), type: 'paragraph', parentId: null, contentIds: [runId], props: {} },\n runs: [{ id: runId, type: 'text', value: line, marks: {} }],\n };\n });\n}\n\n/**\n * Parses an HTML string and walks its top-level nodes, dispatching each to\n * whichever registered block type's `fromHTML` claims it (first match\n * wins). `<ul>/<ol>` are handled specially here rather than via a matcher,\n * since there's no standalone \"list\" block type in this model — only\n * `listItem` blocks carrying an `ordered` flag, one per `<li>`.\n */\nexport function walkDomToBlocks(html, registry, inlineRegistry) {\n const doc = new DOMParser().parseFromString(html, 'text/html');\n const ctx = { registry, inlineRegistry };\n const matchers = registry.listHtmlMatchers();\n const results = [];\n\n const consumeList = (listNode) => {\n const ordered = listNode.tagName === 'OL';\n const items = [];\n for (const li of listNode.children) {\n if (li.tagName !== 'LI') continue;\n const result = registry.get('listItem')?.fromHTML(li, ctx);\n if (result) {\n result.block.props.ordered = ordered;\n items.push(result);\n }\n }\n return items;\n };\n\n /**\n * A <blockquote> with several nested <p>s (a multi-line quote, matching\n * what serializeHTML's own grouping now emits) becomes one sibling\n * `blockquote` block per <p> — this model keeps multi-line quotes as\n * separate leaf siblings rather than one container block. A <blockquote>\n * with no nested <p> at all (plain external HTML, just inline content\n * directly inside it) falls back to the registered single-block fromHTML.\n */\n const consumeBlockquote = (bqNode) => {\n const paragraphs = Array.from(bqNode.children).filter((c) => c.tagName === 'P');\n if (paragraphs.length === 0) {\n const result = registry.get('blockquote')?.fromHTML(bqNode, ctx);\n return result ? [result] : [];\n }\n return paragraphs.map((p) => {\n const runs = domInlineToRuns(p, ctx);\n return {\n block: {\n id: genId(),\n type: 'blockquote',\n parentId: null,\n contentIds: runs.map((r) => r.id),\n props: {},\n },\n runs,\n };\n });\n };\n\n for (const node of doc.body.childNodes) {\n if (node.nodeType === 3 /* TEXT_NODE */) {\n const text = node.textContent.trim();\n if (text) results.push(...textToParagraphs(text));\n continue;\n }\n if (node.nodeType !== 1 /* ELEMENT_NODE */) continue;\n\n if (node.tagName === 'UL' || node.tagName === 'OL') {\n results.push(...consumeList(node));\n continue;\n }\n\n if (node.tagName === 'BLOCKQUOTE') {\n results.push(...consumeBlockquote(node));\n continue;\n }\n\n let matched = null;\n for (const entry of matchers) {\n const result = entry.fromHTML(node, ctx);\n if (result) {\n matched = result;\n break;\n }\n }\n\n if (matched) {\n results.push(matched);\n } else if (node.textContent.trim()) {\n const runs = domInlineToRuns(node, ctx);\n results.push({\n block: {\n id: genId(),\n type: 'paragraph',\n parentId: null,\n contentIds: runs.map((r) => r.id),\n props: {},\n },\n runs,\n });\n }\n }\n\n return results;\n}\n","import { APP_MIME } from './mimeType.js';\nimport { walkDomToBlocks, textToParagraphs } from './domWalk.js';\nimport { remapSubtreeIds } from './serialize.js';\n\n/**\n * Given a DataTransfer-like object (real ClipboardEvent.clipboardData, or a\n * plain { types, getData } stand-in for tests), returns an array of\n * `{ block, runs, subtreeBlocks }` ready to insert. Prefers the lossless\n * same-editor payload, falls back to HTML (cross-editor), then plain text.\n */\nexport function deserializeClipboard(dataTransfer, registry, inlineRegistry) {\n const types = dataTransfer.types ?? [];\n\n if (types.includes(APP_MIME)) {\n const json = dataTransfer.getData(APP_MIME);\n if (json) return deserializeAppJSON(json);\n }\n\n if (types.includes('text/html')) {\n const html = dataTransfer.getData('text/html');\n if (html) return walkDomToBlocks(html, registry, inlineRegistry);\n }\n\n const text = dataTransfer.getData('text/plain') ?? '';\n return textToParagraphs(text);\n}\n\nfunction deserializeAppJSON(json) {\n const payload = JSON.parse(json);\n return payload.blocks.map((subtree) => remapSubtreeIds(subtree));\n}\n","import { genId } from '../utils/idGen.js';\nimport { setBlockRuns, removeBlock, insertBlock } from '../store/operations.js';\nimport { canMergeTypes } from '../blocks/shared/mergeCommands.js';\nimport { createTextLeafBlock } from '../blocks/shared/leafBlockFactory.js';\n\nfunction getBlockRunIds(store, blockId) {\n const block = store.getBlock(blockId);\n return block.props?.titleRunIds ?? block.contentIds;\n}\n\nfunction blankRun() {\n return { id: genId(), type: 'text', value: '', marks: {} };\n}\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 * Deletes the [startRunId+startOffset, endRunId+endOffset) range from one\n * block's own run list. Unlike mark-toggling (applyMarkOverRunSpan), an\n * atomic (non-text) run anywhere in the range is simply dropped — there's\n * no sensible \"delete the surrounding text but keep the chip\" here. Falls\n * back to one blank run if the deletion would leave zero runs (same \"never\n * leave a caret-less contentEditable region\" guarantee as\n * EditableBlockContent's removeRun/handleInput).\n *\n * Returns `{ blockId, runId, offset }` for the collapsed caret the\n * deletion leaves behind, or null if the range didn't resolve.\n */\nexport function deleteRunRangeInBlock(store, blockId, selection) {\n const { startRunId, startOffset, endRunId, endOffset } = selection;\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] =\n startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\n const fromOffset = startIndex <= endIndex ? startOffset : endOffset;\n const toOffset = startIndex <= endIndex ? endOffset : startOffset;\n\n const beforeRuns = runIds.slice(0, fromIndex).map((id) => store.getRun(id));\n const afterRuns = runIds.slice(toIndex + 1).map((id) => store.getRun(id));\n const spanRuns = runIds.slice(fromIndex, toIndex + 1).map((id) => store.getRun(id));\n\n const survivors = [];\n let caretRunId = null;\n let caretOffset = 0;\n\n if (fromIndex === toIndex) {\n const run = spanRuns[0];\n if (run.type === 'text') {\n const from = Math.max(0, Math.min(fromOffset, toOffset));\n const to = Math.min(run.value.length, Math.max(fromOffset, toOffset));\n const survivor = { ...run, value: run.value.slice(0, from) + run.value.slice(to) };\n survivors.push(survivor);\n caretRunId = survivor.id;\n caretOffset = from;\n } // atomic: dropped entirely, caret resolved from before/after below\n } else {\n spanRuns.forEach((run, i) => {\n if (run.type !== 'text') return; // atomic anywhere in a multi-run range: dropped entirely\n const isFirst = i === 0;\n const isLast = i === spanRuns.length - 1;\n // isFirst/isLast are never both true here — that's the single-run\n // case handled above (fromIndex === toIndex).\n const prefix = isFirst ? run.value.slice(0, fromOffset) : '';\n if (isFirst && prefix) {\n const prefixRun = { ...run, value: prefix };\n survivors.push(prefixRun);\n caretRunId = prefixRun.id;\n caretOffset = prefix.length;\n }\n if (isLast && !isFirst) {\n const suffixValue = run.value.slice(toOffset);\n if (suffixValue) {\n const suffixRun = { id: genId(), type: 'text', value: suffixValue, marks: run.marks };\n survivors.push(suffixRun);\n if (caretRunId === null) {\n caretRunId = suffixRun.id;\n caretOffset = 0;\n }\n }\n }\n });\n }\n\n let finalRuns = [...beforeRuns, ...survivors, ...afterRuns];\n\n if (finalRuns.length === 0) {\n const blank = blankRun();\n finalRuns = [blank];\n caretRunId = blank.id;\n caretOffset = 0;\n } else if (caretRunId === null) {\n // Nothing survived from the deleted span itself (e.g. it was a single\n // atomic run): land at the boundary — end of whatever's right before,\n // or start of whatever's right after.\n const lastBefore = beforeRuns[beforeRuns.length - 1];\n if (lastBefore) {\n caretRunId = lastBefore.id;\n caretOffset = lastBefore.type === 'text' ? lastBefore.value.length : 0;\n } else if (afterRuns[0]) {\n caretRunId = afterRuns[0].id;\n caretOffset = 0;\n }\n }\n\n store.applyOperation(setBlockRuns(blockId, finalRuns));\n return { blockId, runId: caretRunId, offset: caretOffset };\n}\n\n/**\n * Deletes a selection spanning *multiple sibling blocks* under a shared\n * parent (see resolveCrossBlockSelection) — the same range shape\n * toggleMarkOverBlockRange consumes, reused here for deletion instead of\n * mark-toggling. This is also what a \"select all\" (twice-pressed Ctrl+A,\n * which spans every top-level block under root) funnels through: the\n * general logic below naturally handles \"delete the entire document\" as\n * the extreme case of \"delete across several sibling blocks\" — no special\n * casing needed beyond the final \"did this leave one lone empty\n * non-paragraph block?\" check.\n *\n * Fully-covered blocks strictly between the two boundaries are removed\n * outright. The two boundary blocks are trimmed to their surviving prefix/\n * suffix; if they're mergeable text types (see canMergeTypes), those\n * survivors are combined into ONE remaining block (matching\n * mergeWithPreviousOrDelete's merge convention). If they're not mergeable\n * (e.g. the range runs from a paragraph into a table cell), both trimmed\n * blocks are simply left in place rather than guessing at cross-type\n * semantics.\n *\n * One atomic undo step. Returns `{ blockId, runId, offset }` for the\n * resulting caret position, or null if the range didn't resolve.\n */\nexport function deleteOverBlockRange(store, crossSelection) {\n const { blockIds, startBlockId, startRunId, startOffset, endBlockId, endRunId, endOffset } =\n crossSelection;\n if (!blockIds || blockIds.length === 0) return null;\n\n const startBlockIndex = blockIds.indexOf(startBlockId);\n const endBlockIndex = blockIds.indexOf(endBlockId);\n if (startBlockIndex === -1 || endBlockIndex === -1) return null;\n\n const [fromBlockIndex, toBlockIndex] =\n startBlockIndex <= endBlockIndex\n ? [startBlockIndex, endBlockIndex]\n : [endBlockIndex, startBlockIndex];\n const firstIsStart = startBlockIndex <= endBlockIndex;\n const firstRunId = firstIsStart ? startRunId : endRunId;\n const firstOffset = firstIsStart ? startOffset : endOffset;\n const lastRunId = firstIsStart ? endRunId : startRunId;\n const lastOffset = firstIsStart ? endOffset : startOffset;\n\n if (fromBlockIndex === toBlockIndex) {\n return deleteRunRangeInBlock(store, blockIds[fromBlockIndex], {\n startRunId: firstRunId,\n startOffset: firstOffset,\n endRunId: lastRunId,\n endOffset: lastOffset,\n });\n }\n\n const firstBlockId = blockIds[fromBlockIndex];\n const lastBlockId = blockIds[toBlockIndex];\n const firstBlock = store.getBlock(firstBlockId);\n const lastBlock = store.getBlock(lastBlockId);\n\n const firstRunIds = getBlockRunIds(store, firstBlockId);\n const firstIdx = firstRunIds.indexOf(firstRunId);\n const firstPrefixRuns = firstRunIds.slice(0, firstIdx).map((id) => store.getRun(id));\n const firstRun = store.getRun(firstRunId);\n const firstPrefixSurvivor =\n firstRun.type === 'text' && firstOffset > 0\n ? { ...firstRun, value: firstRun.value.slice(0, firstOffset) }\n : null;\n\n const lastRunIds = getBlockRunIds(store, lastBlockId);\n const lastIdx = lastRunIds.indexOf(lastRunId);\n const lastSuffixRuns = lastRunIds.slice(lastIdx + 1).map((id) => store.getRun(id));\n const lastRun = store.getRun(lastRunId);\n const lastSuffixSurvivor =\n lastRun.type === 'text' && lastOffset < lastRun.value.length\n ? { id: genId(), type: 'text', value: lastRun.value.slice(lastOffset), marks: lastRun.marks }\n : null;\n\n const firstSurvivors = [\n ...firstPrefixRuns,\n ...(firstPrefixSurvivor ? [firstPrefixSurvivor] : []),\n ];\n const lastSurvivors = [...(lastSuffixSurvivor ? [lastSuffixSurvivor] : []), ...lastSuffixRuns];\n\n const ops = [];\n for (let i = fromBlockIndex + 1; i < toBlockIndex; i += 1) ops.push(removeBlock(blockIds[i]));\n\n const mergeable = canMergeTypes(firstBlock.type, lastBlock.type);\n const parent = store.getBlock(firstBlock.parentId);\n // Only the mergeable branch can ever collapse to a single surviving\n // block (the non-mergeable branch always leaves both first and last in\n // place) — \"select all, then delete\" is exactly this shape: the merge\n // leaves nothing behind, and it was the only two blocks under the\n // parent. Every real editor leaves a plain paragraph there, not\n // whatever type happened to survive (a now-empty heading, say). Decided\n // analytically (without mutating the store first) so the swap can be\n // folded into the same ops array — one atomic undo step, not two.\n const removedCount = toBlockIndex - fromBlockIndex - 1 + (mergeable ? 1 : 0);\n const wouldBeOnlyChild = parent && parent.contentIds.length - removedCount === 1;\n\n let caretRunId;\n let caretOffset;\n let survivingBlockId;\n\n if (mergeable) {\n const merged = [...firstSurvivors, ...lastSurvivors];\n\n if (merged.length === 0 && wouldBeOnlyChild && firstBlock.type !== 'paragraph') {\n const { block: fallbackBlock, runs } = createTextLeafBlock('paragraph')(parent.id);\n ops.push({\n type: 'insertBlock',\n block: fallbackBlock,\n parentId: parent.id,\n index: 0,\n subtree: { blocks: [fallbackBlock], runs },\n });\n ops.push(removeBlock(firstBlockId));\n ops.push(removeBlock(lastBlockId));\n applyOps(store, ops);\n return { blockId: fallbackBlock.id, runId: fallbackBlock.contentIds[0], offset: 0 };\n }\n\n const finalRuns = merged.length ? merged : [blankRun()];\n ops.push(setBlockRuns(firstBlockId, finalRuns));\n ops.push(removeBlock(lastBlockId));\n survivingBlockId = firstBlockId;\n\n if (firstPrefixSurvivor) {\n caretRunId = firstPrefixSurvivor.id;\n caretOffset = firstPrefixSurvivor.value.length;\n } else if (firstPrefixRuns.length) {\n const last = firstPrefixRuns[firstPrefixRuns.length - 1];\n caretRunId = last.id;\n caretOffset = last.type === 'text' ? last.value.length : 0;\n } else if (lastSuffixSurvivor) {\n caretRunId = lastSuffixSurvivor.id;\n caretOffset = 0;\n } else if (lastSuffixRuns.length) {\n caretRunId = lastSuffixRuns[0].id;\n caretOffset = 0;\n } else {\n caretRunId = finalRuns[0].id;\n caretOffset = 0;\n }\n } else {\n const firstFinalRuns = firstSurvivors.length ? firstSurvivors : [blankRun()];\n ops.push(setBlockRuns(firstBlockId, firstFinalRuns));\n ops.push(setBlockRuns(lastBlockId, lastSurvivors.length ? lastSurvivors : [blankRun()]));\n survivingBlockId = firstBlockId;\n\n if (firstPrefixSurvivor) {\n caretRunId = firstPrefixSurvivor.id;\n caretOffset = firstPrefixSurvivor.value.length;\n } else if (firstPrefixRuns.length) {\n const last = firstPrefixRuns[firstPrefixRuns.length - 1];\n caretRunId = last.id;\n caretOffset = last.type === 'text' ? last.value.length : 0;\n } else {\n caretRunId = firstFinalRuns[0].id;\n caretOffset = 0;\n }\n }\n\n applyOps(store, ops);\n return { blockId: survivingBlockId, runId: caretRunId, offset: caretOffset };\n}\n\n/**\n * Deletes every top-level block under the document root and leaves one\n * paragraph behind (blank, or seeded with `replacementText` — typing a\n * character over a \"whole document selected\" state replaces it, matching\n * the standard \"type over a selection\" convention). Deliberately its own,\n * much simpler function rather than routed through deleteOverBlockRange:\n * a whole-document deletion never needs partial-boundary trimming (unlike\n * a cross-sibling-block selection, which stops mid-run at each end), and\n * the top-level blocks can be *any* type — including containers like\n * tables that don't have a run-based content list at all — so there's\n * nothing to trim at the boundaries in the first place, only whole blocks\n * to remove.\n *\n * One atomic undo step. Returns `{ blockId, runId, offset }` for the\n * resulting caret position, or null if the document was already empty.\n */\nexport function deleteEntireDocument(store, replacementText = '') {\n const rootId = store.getRootId();\n const contentIds = store.getBlock(rootId)?.contentIds ?? [];\n if (contentIds.length === 0) return null;\n\n const ops = contentIds.map((id) => removeBlock(id));\n const { block: fallbackBlock, runs } = createTextLeafBlock('paragraph')(rootId);\n if (replacementText) runs[0].value = replacementText;\n ops.push(insertBlock(fallbackBlock, rootId, 0, { blocks: [fallbackBlock], runs }));\n\n applyOps(store, ops);\n return {\n blockId: fallbackBlock.id,\n runId: fallbackBlock.contentIds[0],\n offset: replacementText.length,\n };\n}\n","import { useCallback } from 'react';\nimport {\n useEditorStore,\n useBlockRegistry,\n useInlineRegistry,\n useWholeDocumentSelection,\n useBlockRangeSelection,\n useFileUpload,\n} from './EditorProvider.jsx';\nimport { serializeBlockRange } from '../clipboard/serialize.js';\nimport { deserializeClipboard } from '../clipboard/deserialize.js';\nimport { APP_MIME } from '../clipboard/mimeType.js';\nimport { insertBlock, removeBlock, updateRun } from '../store/operations.js';\nimport {\n resolveMultiRunSelection,\n resolveCrossBlockSelection,\n resolveCollapsedCaret,\n} from './selectionResolve.js';\nimport {\n deleteRunRangeInBlock,\n deleteOverBlockRange,\n deleteEntireDocument,\n} from '../inline/deleteCommands.js';\nimport { deleteBlockRange } from '../blocks/shared/blockRangeActions.js';\nimport { focusRunAtOffset } from './focusRun.js';\nimport { resolveFileToEmbedInsert } from '../blocks/embed/resolveFileEmbed.js';\n\n// Several plain `<input>`/`<textarea>` fields live inside the editor's own\n// DOM subtree — the embed block's URL field, FindBar's query/replace\n// inputs, LinkEditModal/ButtonEditModal/FieldTypeEditorModal's fields, the\n// comment composer's textarea, and more. None of them are portaled outside\n// NoteloomEditor's own container div, and React's synthetic copy/cut/paste\n// events bubble along the REACT tree (portals included) regardless of the\n// real DOM structure — so without this check, copying/cutting/pasting\n// inside any of those fields was hijacked by this hook's own block-range\n// logic instead of that field's native behavior (e.g. a paste into the\n// embed URL field landing as a brand-new paragraph elsewhere in the\n// document instead of into the field itself). This editor's own actual\n// text-editing surface is never a plain `<input>`/`<textarea>` — every run\n// is a `contentEditable` span — so this check cleanly separates \"real\n// editor content\" from every other field, present or future.\nfunction isPlainFormField(target) {\n return target?.tagName === 'INPUT' || target?.tagName === 'TEXTAREA';\n}\n\nfunction closestBlockId(node) {\n let el = node?.nodeType === 1 ? node : node?.parentElement;\n while (el && typeof el.hasAttribute === 'function' && !el.hasAttribute('data-block-id')) {\n el = el.parentElement;\n }\n return el?.getAttribute?.('data-block-id') ?? null;\n}\n\n/**\n * v0.1 selection-range resolution: maps the native selection's anchor/focus\n * to the nearest [data-block-id] ancestor and, if they differ, to a\n * contiguous sibling range under their shared parent. Partial-text selection\n * within a single block still copies that block's whole HTML — full\n * character-level range slicing is a follow-up once store/selection.js\n * (logical {blockId, offset} tracking) is built.\n */\nfunction resolveSelectedBlockIds(store) {\n const selection = window.getSelection?.();\n if (!selection || selection.rangeCount === 0) return [];\n\n const startId = closestBlockId(selection.anchorNode);\n const endId = closestBlockId(selection.focusNode);\n if (!startId) return [];\n if (!endId || startId === endId) return [startId];\n\n const startBlock = store.getBlock(startId);\n const parent = startBlock && store.getBlock(startBlock.parentId);\n if (!parent) return [startId];\n\n const ids = parent.contentIds;\n const i1 = ids.indexOf(startId);\n const i2 = ids.indexOf(endId);\n if (i1 === -1 || i2 === -1) return [startId];\n\n const [from, to] = i1 <= i2 ? [i1, i2] : [i2, i1];\n return ids.slice(from, to + 1);\n}\n\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. */\nfunction deleteCurrentSelection(store) {\n const same = resolveMultiRunSelection();\n if (same) return deleteRunRangeInBlock(store, same.blockId, same);\n\n const cross = resolveCrossBlockSelection(store);\n if (cross) return deleteOverBlockRange(store, cross);\n\n return null;\n}\n\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. */\nfunction insertTextAtCaret(store, caret, text) {\n const run = store.getRun(caret.runId);\n if (!run || run.type !== 'text') return null;\n const value = run.value ?? '';\n const newValue = value.slice(0, caret.offset) + text + value.slice(caret.offset);\n store.applyOperation(updateRun(run.id, { value: newValue }));\n return { blockId: caret.blockId, runId: run.id, offset: caret.offset + text.length };\n}\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\nexport function useClipboardHandlers() {\n const store = useEditorStore();\n const registry = useBlockRegistry();\n const inlineRegistry = useInlineRegistry();\n const { uploadFile, maxFileSize } = useFileUpload();\n const [isWholeDocumentSelected, setIsWholeDocumentSelected] = useWholeDocumentSelection();\n const [selectedBlockRange, setSelectedBlockRange] = useBlockRangeSelection();\n\n const onCopy = useCallback(\n (event) => {\n if (isPlainFormField(event.target)) return; // let the field handle its own native copy\n // Priority: whole-document select-all > a drag-selected block range\n // (see useBlockRangeDrag) > the native browser Selection. Only one of\n // these is ever meaningfully active at once in practice (starting\n // any of the others clears the rest), but the order still matters if\n // more than one happens to be non-empty.\n const blockIds = isWholeDocumentSelected\n ? (store.getBlock(store.getRootId())?.contentIds ?? [])\n : selectedBlockRange.length > 0\n ? selectedBlockRange\n : resolveSelectedBlockIds(store);\n if (blockIds.length === 0) return;\n const { html, text, json } = serializeBlockRange(store, registry, blockIds, inlineRegistry);\n event.clipboardData.setData('text/plain', text);\n event.clipboardData.setData('text/html', html);\n event.clipboardData.setData(APP_MIME, json);\n event.preventDefault();\n },\n [store, registry, inlineRegistry, isWholeDocumentSelected, selectedBlockRange],\n );\n\n // Cut = copy, then delete whatever was selected — same \"delete selection\"\n // primitive a cross-block Backspace/Delete keypress uses (see\n // useEditorKeyboardShortcuts), reused here instead of duplicated. One\n // atomic undo step for the deletion (copying doesn't touch the store).\n const onCut = useCallback(\n (event) => {\n if (isPlainFormField(event.target)) return; // let the field handle its own native cut\n onCopy(event);\n if (isWholeDocumentSelected) {\n const result = deleteEntireDocument(store);\n setIsWholeDocumentSelected(false);\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\n return;\n }\n if (selectedBlockRange.length > 0) {\n deleteBlockRange(store, selectedBlockRange);\n setSelectedBlockRange([]);\n return;\n }\n const result = deleteCurrentSelection(store);\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\n },\n [\n onCopy,\n store,\n isWholeDocumentSelected,\n setIsWholeDocumentSelected,\n selectedBlockRange,\n setSelectedBlockRange,\n ],\n );\n\n // A raw image/media file straight off the OS clipboard (a screenshot, an\n // OS-level \"Copy Image\") — as opposed to copying an <img> from a webpage,\n // which arrives as text/html and is handled by deserializeClipboard/\n // embed's fromHTML instead. Goes through the exact same uploadFile/\n // maxFileSize resolution as EmbedBlock's own dropzone (see\n // resolveFileEmbed.js's doc comment), so a host's upload config behaves\n // identically no matter which path triggered it. A file failing to\n // resolve (oversized, or a rejected uploadFile call) is skipped rather\n // than aborting the whole paste — the rest still land.\n const insertPastedFiles = useCallback(\n async (files) => {\n const settled = await Promise.allSettled(\n files.map((file) => resolveFileToEmbedInsert(file, { uploadFile, maxFileSize })),\n );\n const inserts = settled.filter((r) => r.status === 'fulfilled').map((r) => r.value);\n if (inserts.length === 0) return;\n\n if (isWholeDocumentSelected) {\n const rootId = store.getRootId();\n const contentIds = store.getBlock(rootId)?.contentIds ?? [];\n const ops = contentIds.map((id) => removeBlock(id));\n let rootIndex = 0;\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\n block.parentId = rootId;\n ops.push(\n insertBlock(block, rootId, rootIndex, { blocks: [block, ...subtreeBlocks], runs }),\n );\n rootIndex += 1;\n }\n applyOps(store, ops);\n setIsWholeDocumentSelected(false);\n return;\n }\n\n if (selectedBlockRange.length > 0) {\n const first = store.getBlock(selectedBlockRange[0]);\n const parentId = first?.parentId ?? null;\n const parent = parentId && store.getBlock(parentId);\n let index = parent ? parent.contentIds.indexOf(selectedBlockRange[0]) : 0;\n\n const ops = selectedBlockRange.map((id) => removeBlock(id));\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\n block.parentId = parentId;\n ops.push(\n insertBlock(block, parentId, index, { blocks: [block, ...subtreeBlocks], runs }),\n );\n index += 1;\n }\n applyOps(store, ops);\n setSelectedBlockRange([]);\n return;\n }\n\n const deleteResult = deleteCurrentSelection(store);\n const atBlockId =\n deleteResult?.blockId ?? closestBlockId(window.getSelection?.()?.anchorNode);\n if (!atBlockId) return;\n const current = store.getBlock(atBlockId);\n if (!current) return;\n const parent = store.getBlock(current.parentId);\n let index = parent.contentIds.indexOf(atBlockId) + 1;\n\n const insertOps = [];\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\n block.parentId = current.parentId;\n insertOps.push(\n insertBlock(block, current.parentId, index, { blocks: [block, ...subtreeBlocks], runs }),\n );\n index += 1;\n }\n applyOps(store, insertOps);\n },\n [\n store,\n uploadFile,\n maxFileSize,\n isWholeDocumentSelected,\n setIsWholeDocumentSelected,\n selectedBlockRange,\n setSelectedBlockRange,\n ],\n );\n\n const onPaste = useCallback(\n (event) => {\n if (isPlainFormField(event.target)) return; // let the field handle its own native paste\n // A real file on the clipboard (as opposed to an <img> copied from a\n // webpage, which arrives as text/html with no .files) is a strong,\n // unambiguous signal of direct image/screenshot paste intent — takes\n // priority over HTML/text deserialization below.\n const files = Array.from(event.clipboardData?.files ?? []);\n if (files.length > 0) {\n event.preventDefault();\n insertPastedFiles(files);\n return;\n }\n\n const inserts = deserializeClipboard(event.clipboardData, registry, inlineRegistry);\n if (inserts.length === 0) return;\n\n if (isWholeDocumentSelected) {\n const rootId = store.getRootId();\n const contentIds = store.getBlock(rootId)?.contentIds ?? [];\n const ops = contentIds.map((id) => removeBlock(id));\n let rootIndex = 0;\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\n block.parentId = rootId;\n ops.push(\n insertBlock(block, rootId, rootIndex, { blocks: [block, ...subtreeBlocks], runs }),\n );\n rootIndex += 1;\n }\n applyOps(store, ops);\n setIsWholeDocumentSelected(false);\n event.preventDefault();\n return;\n }\n\n // Same idea, scoped to a drag-selected block range instead of the\n // whole document: the range is removed and the pasted block(s) take\n // its place, starting at the range's former position.\n if (selectedBlockRange.length > 0) {\n const first = store.getBlock(selectedBlockRange[0]);\n const parentId = first?.parentId ?? null;\n const parent = parentId && store.getBlock(parentId);\n let index = parent ? parent.contentIds.indexOf(selectedBlockRange[0]) : 0;\n\n const ops = selectedBlockRange.map((id) => removeBlock(id));\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\n block.parentId = parentId;\n ops.push(\n insertBlock(block, parentId, index, { blocks: [block, ...subtreeBlocks], runs }),\n );\n index += 1;\n }\n applyOps(store, ops);\n setSelectedBlockRange([]);\n event.preventDefault();\n return;\n }\n\n // Pasting over an active selection replaces it, rather than leaving\n // the old selected content sitting next to the newly-inserted\n // blocks — same \"delete selection\" primitive as Cut/cross-block\n // Backspace. Its own atomic undo step, separate from the insertion\n // below.\n const deleteResult = deleteCurrentSelection(store);\n\n // Simple, single-run plain-text paste — by far the common case (a\n // word, a phrase, a URL) — splices directly into the run at the\n // caret instead of always creating a whole new sibling block,\n // a common rich text editor convention. Multi-block or structured clipboard\n // content (tables, lists, several paragraphs) still inserts as new\n // block(s) after the current one; splitting the current block\n // around it is a further follow-up.\n const isSimpleTextPaste =\n inserts.length === 1 &&\n inserts[0].runs.every((r) => r.type === 'text') &&\n (inserts[0].subtreeBlocks ?? []).length === 0;\n\n if (isSimpleTextPaste) {\n const caret = deleteResult\n ? {\n blockId: deleteResult.blockId,\n runId: deleteResult.runId,\n offset: deleteResult.offset,\n }\n : resolveCollapsedCaret();\n if (caret) {\n const text = inserts[0].runs.map((r) => r.value).join('');\n const result = insertTextAtCaret(store, caret, text);\n if (result) {\n focusRunAtOffset(result.runId, result.offset);\n event.preventDefault();\n return;\n }\n }\n }\n\n const atBlockId =\n deleteResult?.blockId ?? closestBlockId(window.getSelection?.()?.anchorNode);\n if (!atBlockId) return;\n\n const current = store.getBlock(atBlockId);\n if (!current) return;\n const parent = store.getBlock(current.parentId);\n let index = parent.contentIds.indexOf(atBlockId) + 1;\n\n const insertOps = [];\n for (const { block, runs, subtreeBlocks = [] } of inserts) {\n block.parentId = current.parentId;\n insertOps.push(\n insertBlock(block, current.parentId, index, { blocks: [block, ...subtreeBlocks], runs }),\n );\n index += 1;\n }\n // One atomic undo step for the whole paste, regardless of how many\n // blocks it inserts — previously each was its own separate step.\n applyOps(store, insertOps);\n\n event.preventDefault();\n },\n [\n store,\n registry,\n inlineRegistry,\n isWholeDocumentSelected,\n setIsWholeDocumentSelected,\n selectedBlockRange,\n setSelectedBlockRange,\n insertPastedFiles,\n ],\n );\n\n return { onCopy, onCut, onPaste };\n}\n","import { genId } from '../utils/idGen.js';\nimport { replaceRunSpan } from '../store/operations.js';\n\nconst BOOLEAN_MARK_NAMES = [\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'subscript',\n 'superscript',\n 'code',\n];\nconst VALUE_MARK_NAMES = ['color', 'highlight', 'link'];\n\nfunction getBlockRunIds(store, blockId) {\n const block = store.getBlock(blockId);\n return block.props?.titleRunIds ?? block.contentIds;\n}\n\n// Object-valued marks (link: {href, target}) can be equal in content but\n// different references — e.g. after undo/redo, or a copy-pasted link — so\n// plain === would spuriously read as \"mixed\" even when every run in range\n// really does carry the same link. Primitive marks (color/highlight) are\n// unaffected: === already succeeds for them before this ever falls through.\nfunction sameMarkValue(a, b) {\n if (a === b) return true;\n if (a && b && typeof a === 'object') return JSON.stringify(a) === JSON.stringify(b);\n return false;\n}\n\nfunction summarizeMarks(runs) {\n const summary = {};\n if (runs.length === 0) return summary;\n for (const name of BOOLEAN_MARK_NAMES) {\n summary[name] = runs.every((r) => r.marks?.[name]);\n }\n for (const name of VALUE_MARK_NAMES) {\n const first = runs[0].marks?.[name] ?? null;\n summary[name] = runs.every((r) => sameMarkValue(r.marks?.[name] ?? null, first)) ? first : null;\n }\n return summary;\n}\n\n/**\n * Summarizes which marks are uniformly active across a same-block\n * selection — used by the floating toolbar to show a button as \"pressed\"\n * only when the *entire* selection already has that mark (the same\n * all-or-nothing convention toggleMarkOverSelection's own enable/disable\n * decision uses), and to read the current color/highlight value when it's\n * consistent across the whole selection (null when mixed or unset).\n */\nexport function getMarksSummaryOverSelection(store, blockId, selection) {\n const { startRunId, startOffset, endRunId, endOffset } = selection;\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 {};\n const [fromIndex, toIndex] =\n startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\n const runs = runIds\n .slice(fromIndex, toIndex + 1)\n .map((id) => store.getRun(id))\n .filter((r) => r && r.type === 'text');\n return summarizeMarks(runs);\n}\n\n/**\n * Same idea as getMarksSummaryOverSelection but for a cross-block range.\n * Approximates by including every text run in every block the range\n * touches (not clipped to the exact sub-range within the first/last\n * block) — fine for a toolbar's \"is this button pressed\" indicator, which\n * doesn't need character-level precision; the actual mutation\n * (setMarksOverBlockRange) is exact.\n */\nexport function getMarksSummaryOverBlockRange(store, crossSelection) {\n const { blockIds, startBlockId, endBlockId } = crossSelection;\n const startBlockIndex = blockIds.indexOf(startBlockId);\n const endBlockIndex = blockIds.indexOf(endBlockId);\n if (startBlockIndex === -1 || endBlockIndex === -1) return {};\n const [fromBlockIndex, toBlockIndex] =\n startBlockIndex <= endBlockIndex\n ? [startBlockIndex, endBlockIndex]\n : [endBlockIndex, startBlockIndex];\n\n const runs = [];\n for (let i = fromBlockIndex; i <= toBlockIndex; i += 1) {\n for (const id of getBlockRunIds(store, blockIds[i])) {\n const run = store.getRun(id);\n if (run && run.type === 'text') runs.push(run);\n }\n }\n return summarizeMarks(runs);\n}\n\n/** Applies a {markName: value} patch to a marks object — value === null/undefined removes that key, anything else sets it. */\nfunction applyMarksPatch(marks, marksPatch) {\n const next = { ...marks };\n for (const [markName, value] of Object.entries(marksPatch)) {\n if (value != null) next[markName] = value;\n else delete next[markName];\n }\n return next;\n}\n\n/** Splits one run at [from, to) and applies `marksPatch` to the middle slice; the rest keeps its existing marks. */\nfunction applyPatchToSingleRun(store, blockId, run, from, to, marksPatch) {\n const nextMarks = applyMarksPatch(run.marks, marksPatch);\n\n if (from === 0 && to === run.value.length) {\n store.applyOperation({ type: 'updateRun', id: run.id, patch: { marks: nextMarks } });\n return run.id;\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 const middleRun = { id: genId(), type: 'text', value: middle, marks: nextMarks };\n newRuns.push(middleRun);\n if (after) newRuns.push({ id: genId(), type: 'text', value: after, marks: { ...run.marks } });\n\n store.applyOperation(replaceRunSpan(blockId, [run.id], newRuns));\n return middleRun.id;\n}\n\n/**\n * Applies `marksPatch` — one or more `{markName: value}` entries, value\n * `null`/`undefined` meaning \"remove this mark\" and anything else meaning\n * \"set it to this value\" — across a run span within one block, which may\n * cover one run or several. Applying several marks in the same patch (e.g.\n * `{ superscript: true, subscript: null }`, so turning superscript on\n * always clears subscript in the same pass) matters because two *sequential*\n * calls would each independently split/replace runs and mint new ids, so\n * the second call's selection (addressed by run id) could already be stale\n * by the time it runs — one patch, one pass, no staleness window.\n *\n * Atomic (non-text) runs in the span are passed through untouched. This is\n * the shared primitive every mark command below (boolean toggle, or a\n * value-based mark like color/highlight) ultimately applies per block.\n */\nfunction applyMarksPatchOverRunSpan(store, blockId, selection, marksPatch) {\n const { startRunId, startOffset, endRunId, endOffset } = selection;\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] =\n 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 run.id;\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 run.id;\n return applyPatchToSingleRun(store, blockId, run, from, to, marksPatch);\n }\n\n const newRuns = [];\n let lastNewRunId = null;\n\n rangeRuns.forEach((run, i) => {\n if (run.type !== 'text') {\n newRuns.push(run); // atomic: pass through untouched\n lastNewRunId = run.id;\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\n const middleRun = {\n id: genId(),\n type: 'text',\n value: middle,\n marks: applyMarksPatch(run.marks, marksPatch),\n };\n newRuns.push(middleRun);\n lastNewRunId = middleRun.id;\n\n if (after) newRuns.push({ id: genId(), type: 'text', value: after, marks: { ...run.marks } });\n });\n\n store.applyOperation(replaceRunSpan(blockId, rangeRunIds, newRuns));\n return lastNewRunId;\n}\n\n/** Whether every *text* run covered by the range already has the mark (decides enable vs disable for a boolean toggle). */\nfunction computeShouldEnableForRange(store, blockId, selection, markName) {\n const { startRunId, startOffset, endRunId, endOffset } = selection;\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 true;\n const [fromIndex, toIndex] =\n startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\n const textRuns = runIds\n .slice(fromIndex, toIndex + 1)\n .map((id) => store.getRun(id))\n .filter((r) => r.type === 'text');\n if (textRuns.length === 0) return true;\n if (fromIndex === toIndex) {\n const from = Math.max(0, Math.min(startOffset, endOffset));\n const to = Math.min(textRuns[0].value.length, Math.max(startOffset, endOffset));\n if (from === to) return !textRuns[0].marks?.[markName]; // collapsed: mirror toggleMarkOnRunRange's convention\n }\n return !textRuns.every((r) => r.marks?.[markName]);\n}\n\n/**\n * Toggles `markName` on the [startOffset, endOffset) slice of one run's\n * text. Kept as a direct single-run entry point (used when the caller\n * already knows it's exactly one run) — internally now just computes the\n * enable/disable decision and delegates to applyPatchToSingleRun.\n *\n * Returns the id of the run that now contains the toggled middle segment\n * (or the whole run, if no split was needed) — useful for restoring focus.\n */\nexport function toggleMarkOnRunRange(store, blockId, runId, startOffset, endOffset, markName) {\n const run = store.getRun(runId);\n const value = run.value ?? '';\n const from = Math.max(0, Math.min(startOffset, endOffset));\n const to = Math.min(value.length, Math.max(startOffset, endOffset));\n if (from === to) return runId; // collapsed selection: nothing to toggle\n\n const shouldEnable = !run.marks?.[markName];\n return applyPatchToSingleRun(store, blockId, run, from, to, {\n [markName]: shouldEnable ? true : null,\n });\n}\n\n/**\n * Applies an explicit `{markName: value}` patch (see applyMarksPatchOverRunSpan)\n * over a selection within one block — the entry point for value-based marks\n * (color/highlight, set to a specific picked value) and for any mark whose\n * enable/disable decision the caller has already made (e.g. clearing the\n * opposite of a mutually-exclusive pair like subscript/superscript\n * alongside setting the one being turned on, in the same pass).\n */\nexport function setMarksOverSelection(store, blockId, selection, marksPatch) {\n return applyMarksPatchOverRunSpan(store, blockId, selection, marksPatch);\n}\n\n/**\n * Toggles `markName` over a selection that may span *multiple runs within\n * the same block* — e.g. selecting \"ello wor\" across \"h[ello] [wor]ld\" where\n * the middle word already had a different mark boundary. Atomic (non-text)\n * runs caught in the range are passed through unchanged; marks don't apply\n * to them.\n *\n * The whole-range mark state (enable vs disable) is decided by whether\n * every *text* run currently in range already has the mark: if so, this\n * toggle removes it from all of them; otherwise it adds it to all of them\n * — the standard \"toggle bold over a mixed selection turns it fully on\"\n * rich-text convention.\n *\n * Scope: the selection must resolve to a single block (see\n * resolveMultiRunSelection). A selection spanning multiple blocks is\n * handled by toggleMarkOverBlockRange instead.\n */\nexport function toggleMarkOverSelection(store, blockId, selection, markName) {\n const shouldEnable = computeShouldEnableForRange(store, blockId, selection, markName);\n return setMarksOverSelection(store, blockId, selection, {\n [markName]: shouldEnable ? true : null,\n });\n}\n\n/**\n * Toggles `markName` over a selection spanning *multiple sibling blocks*\n * (e.g. selecting from the middle of one paragraph through the middle of\n * another, a few blocks down). `crossSelection` comes from\n * resolveCrossBlockSelection: `{ blockIds, startBlockId, startRunId,\n * startOffset, endBlockId, endRunId, endOffset }`, where blockIds is the\n * ordered sibling range under a shared parent.\n *\n * The enable/disable decision is computed ONCE across every text run\n * actually spanned in the whole range (not per block), so toggling bold\n * across three paragraphs turns it fully on/off consistently everywhere,\n * matching toggleMarkOverSelection's same-block convention.\n *\n * Each affected block gets its own REPLACE_RUN_SPAN operation — this is\n * correct but not a single atomic undo step; undoing a cross-block toggle\n * currently takes one undo press per affected block. Fully atomic\n * cross-block undo is a further follow-up.\n */\nexport function toggleMarkOverBlockRange(store, crossSelection, markName) {\n return setMarksOverBlockRange(\n store,\n crossSelection,\n (allMarked) => ({ [markName]: allMarked ? null : true }),\n markName,\n );\n}\n\n/**\n * Same shape as toggleMarkOverBlockRange, but for an explicit marks patch\n * rather than a single boolean toggle — `marksPatchOrFn` is either a plain\n * `{markName: value}` object (applied identically to every affected block,\n * e.g. a color pick) or a function `(allMarked) => marksPatch` when the\n * patch itself depends on the toggle decision (mirrors\n * toggleMarkOverBlockRange's own \"decide once across the whole range\"\n * semantics — `markNameForDecision` is which mark's presence decides\n * `allMarked`, defaulting to the lookup used by the boolean-toggle case).\n */\nexport function setMarksOverBlockRange(store, crossSelection, marksPatchOrFn, markNameForDecision) {\n const { blockIds, startBlockId, startRunId, startOffset, endBlockId, endRunId, endOffset } =\n crossSelection;\n if (!blockIds || blockIds.length === 0) return null;\n\n const startBlockIndex = blockIds.indexOf(startBlockId);\n const endBlockIndex = blockIds.indexOf(endBlockId);\n if (startBlockIndex === -1 || endBlockIndex === -1) return null;\n\n const [fromBlockIndex, toBlockIndex] =\n startBlockIndex <= endBlockIndex\n ? [startBlockIndex, endBlockIndex]\n : [endBlockIndex, startBlockIndex];\n const firstIsStart = startBlockIndex <= endBlockIndex;\n const firstRunId = firstIsStart ? startRunId : endRunId;\n const firstOffset = firstIsStart ? startOffset : endOffset;\n const lastRunId = firstIsStart ? endRunId : startRunId;\n const lastOffset = firstIsStart ? endOffset : startOffset;\n\n let marksPatch = marksPatchOrFn;\n if (typeof marksPatchOrFn === 'function') {\n let sawText = false;\n let allMarked = true;\n for (let i = fromBlockIndex; i <= toBlockIndex; i += 1) {\n const runs = getBlockRunIds(store, blockIds[i])\n .map((id) => store.getRun(id))\n .filter((r) => r.type === 'text');\n if (runs.length === 0) continue;\n sawText = true;\n if (!runs.every((r) => r.marks?.[markNameForDecision])) allMarked = false;\n }\n marksPatch = marksPatchOrFn(sawText && allMarked);\n }\n\n if (fromBlockIndex === toBlockIndex) {\n return setMarksOverSelection(\n store,\n blockIds[fromBlockIndex],\n {\n startRunId: firstRunId,\n startOffset: firstOffset,\n endRunId: lastRunId,\n endOffset: lastOffset,\n },\n marksPatch,\n );\n }\n\n let lastNewRunId = null;\n for (let i = fromBlockIndex; i <= toBlockIndex; i += 1) {\n const blockId = blockIds[i];\n const runIds = getBlockRunIds(store, blockId);\n const blockFirstRunId = runIds[0];\n const blockLastRunId = runIds[runIds.length - 1];\n const blockLastRun = store.getRun(blockLastRunId);\n const blockLastOffset = blockLastRun?.value?.length ?? 0;\n\n let selection;\n if (i === fromBlockIndex && i === toBlockIndex) {\n selection = {\n startRunId: firstRunId,\n startOffset: firstOffset,\n endRunId: lastRunId,\n endOffset: lastOffset,\n };\n } else if (i === fromBlockIndex) {\n selection = {\n startRunId: firstRunId,\n startOffset: firstOffset,\n endRunId: blockLastRunId,\n endOffset: blockLastOffset,\n };\n } else if (i === toBlockIndex) {\n selection = {\n startRunId: blockFirstRunId,\n startOffset: 0,\n endRunId: lastRunId,\n endOffset: lastOffset,\n };\n } else {\n selection = {\n startRunId: blockFirstRunId,\n startOffset: 0,\n endRunId: blockLastRunId,\n endOffset: blockLastOffset,\n };\n }\n\n lastNewRunId = setMarksOverSelection(store, blockId, selection, marksPatch);\n }\n\n return lastNewRunId;\n}\n","import { resolveMultiRunSelection, resolveCollapsedCaret } from './selectionResolve.js';\nimport { isRunsEmpty } from '../blocks/shared/blockEmpty.js';\n\nfunction getBlockRunIds(store, blockId) {\n const block = store.getBlock(blockId);\n return block?.props?.titleRunIds ?? block?.contentIds ?? [];\n}\n\n/**\n * True when the current (non-collapsed) selection exactly spans one\n * block's own content, start to end. The trigger for promoting a second\n * Ctrl+A press from \"select this block\" (already true via native browser\n * behavior — Ctrl+A in a focused contentEditable region selects only that\n * region by default, no code needed) to \"select the whole document\".\n */\nexport function isEntireBlockSelected(store) {\n const selection = resolveMultiRunSelection();\n if (!selection) return false; // collapsed, or already spans multiple blocks\n\n const { blockId, startRunId, startOffset, endRunId, endOffset } = selection;\n const runIds = getBlockRunIds(store, blockId);\n if (runIds.length === 0) return false;\n\n const startIndex = runIds.indexOf(startRunId);\n const endIndex = runIds.indexOf(endRunId);\n if (startIndex === -1 || endIndex === -1) return false;\n\n const [fromIndex, toIndex] =\n startIndex <= endIndex ? [startIndex, endIndex] : [endIndex, startIndex];\n const fromOffset = startIndex <= endIndex ? startOffset : endOffset;\n const toOffset = startIndex <= endIndex ? endOffset : startOffset;\n if (fromIndex !== 0 || toIndex !== runIds.length - 1 || fromOffset !== 0) return false;\n\n const lastRun = store.getRun(runIds[runIds.length - 1]);\n const lastLength = lastRun?.type === 'text' ? (lastRun.value ?? '').length : 1; // atomic run: one selectable \"unit\"\n return toOffset === lastLength;\n}\n\n/**\n * True when the caret sits in a block with no real content at all — e.g. a\n * heading just created from the slash menu, before anything's been typed\n * into it. An empty block has nothing for native Ctrl+A to actually\n * select, so the resulting selection stays collapsed no matter how many\n * times it's pressed — isEntireBlockSelected requires a *non-collapsed*\n * selection and can never detect \"fully selected\" for it, meaning a\n * second Ctrl+A press would never promote to whole-document mode (the\n * exact bug this fixes: select-all silently doing nothing on a freshly\n * created, still-empty block, while working fine on one that already had\n * text). Treating an empty current block as already \"fully selected\"\n * lets the very first Ctrl+A press jump straight to selecting the whole\n * document instead — there's nothing meaningful to select in between.\n */\nexport function isCurrentBlockEmpty(store) {\n const caret = resolveCollapsedCaret();\n if (!caret) return false;\n return isRunsEmpty(store, getBlockRunIds(store, caret.blockId));\n}\n","import { removeBlock } from '../../store/operations.js';\nimport { isContentlessBlock } from './contentless.js';\nimport { ensureRootNonEmpty } from './ensureRootNonEmpty.js';\nimport { focusRunEnd } from '../../react/focusRun.js';\n\n/**\n * Removes the currently-selected non-editable block (see setSelectedBlockId\n * in EditorProvider.jsx) and resolves what happens to focus next: its\n * previous sibling, or else its next sibling, or else (it was the only\n * block left) whatever ensureRootNonEmpty falls back to. If THAT target is\n * itself contentless (two dividers in a row), it becomes newly selected\n * (and focused, via tabIndex={-1} — see DividerBlock/EmbedBlock) rather\n * than focusing a run that doesn't exist; otherwise its last run is\n * focused normally.\n *\n * Shared by two different call sites that both need this exact resolution:\n * EditableBlockContent's own second-press delete (bubbled from whichever\n * adjacent text block still has focus throughout) and\n * useEditorKeyboardShortcuts' global handler (a Backspace/Delete that\n * lands *directly* on the already-selected, already-focused block itself —\n * there's no EditableBlockContent wrapping a divider/embed for that press\n * to bubble through).\n */\nexport function deleteSelectedBlockAndRefocus(store, selectedId, setSelectedBlockId) {\n const block = store.getBlock(selectedId);\n if (!block) {\n setSelectedBlockId(null);\n return;\n }\n const parent = store.getBlock(block.parentId);\n const idx = parent ? parent.contentIds.indexOf(selectedId) : -1;\n const prevId = idx > 0 ? parent.contentIds[idx - 1] : null;\n const nextId =\n idx !== -1 && idx < parent.contentIds.length - 1 ? parent.contentIds[idx + 1] : null;\n\n store.applyOperation(removeBlock(selectedId));\n setSelectedBlockId(null);\n const fallbackId = ensureRootNonEmpty(store);\n const landId = prevId ?? nextId ?? fallbackId;\n if (!landId) return;\n\n const landBlock = store.getBlock(landId);\n if (isContentlessBlock(store, landBlock)) {\n setSelectedBlockId(landId);\n requestAnimationFrame(() => document.querySelector(`[data-block-id=\"${landId}\"]`)?.focus());\n return;\n }\n\n const titleRunIds = landBlock?.props?.titleRunIds;\n const lastRunId =\n landBlock?.contentIds?.[landBlock.contentIds.length - 1] ??\n titleRunIds?.[titleRunIds.length - 1];\n if (lastRunId) focusRunEnd(lastRunId);\n}\n","import { useEffect } from 'react';\nimport { useEditorStore, useWholeDocumentSelection, useSelectedBlock } from './EditorProvider.jsx';\nimport { toggleMarkOverSelection, toggleMarkOverBlockRange } from '../inline/markCommands.js';\nimport { deleteOverBlockRange, deleteEntireDocument } from '../inline/deleteCommands.js';\nimport { resolveMultiRunSelection, resolveCrossBlockSelection } from './selectionResolve.js';\nimport { isEntireBlockSelected, isCurrentBlockEmpty } from './selectAllCommand.js';\nimport { focusRunEnd, focusRunAtOffset } from './focusRun.js';\nimport { deleteSelectedBlockAndRefocus } from '../blocks/shared/deleteSelectedBlock.js';\nimport { restoreSelectionAfterHistoryChange } from './restoreHistorySelection.js';\n\nconst MARK_KEYS = { b: 'bold', i: 'italic', u: 'underline' };\n\n/**\n * Wires Ctrl/Cmd+Z (undo), Ctrl/Cmd+Shift+Z or Ctrl/Cmd+Y (redo),\n * Ctrl/Cmd+A (select-all, two-stage — see below), Ctrl/Cmd+B/I/U (toggle\n * bold/italic/underline on the current selection), and Backspace/Delete\n * over a selection spanning multiple blocks, at the container level.\n * Undo/redo are no-ops if `store` is a plain EditorStore rather than a\n * History instance (optional chaining on store.undo/store.redo).\n *\n * Mark toggling tries the same-block resolver first (the common case —\n * spans one or more runs within one block), then falls back to the\n * cross-block resolver for a selection spanning sibling blocks. A\n * selection spanning non-sibling blocks (different nesting depths) still\n * isn't supported.\n *\n * Select-all is two-stage, matching every other block editor: native\n * Ctrl+A in a focused contentEditable region already\n * selects only that block's own content — no code needed for the first\n * press. Pressing it *again*, once the whole current block is already\n * selected, promotes to a *custom* \"whole document selected\" state (see\n * useWholeDocumentSelection) rather than trying to construct a native\n * Selection/Range spanning every block — browsers don't reliably support a\n * script-constructed Range across multiple independent contentEditable\n * islands (each is its own \"editing host\"), which is exactly why this\n * editor uses one region per block in the first place. A block editor's\n * cross-block \"select all\" highlight isn't native browser text selection\n * either, for the same reason.\n *\n * While the whole document is selected this way: Backspace/Delete clears\n * it (via deleteEntireDocument, falling back to one blank paragraph),\n * typing a printable character replaces it with that character (matching\n * the standard \"type over a selection\" convention), Escape or any other\n * key cancels the mode, and Ctrl/Cmd+C/X pick it up in useClipboardHandlers.\n *\n * Backspace/Delete over an *ordinary* (native, same- or cross-sibling-\n * block) selection is handled separately below: a same-block selection is\n * left to the existing native-typing + reconcileDomToRuns/beforeinput\n * pipeline in EditableBlockContent, which already handles it correctly —\n * letting the browser delete across *multiple separate* contentEditable\n * regions is what isn't safe.\n */\nexport function useEditorKeyboardShortcuts(containerRef) {\n const store = useEditorStore();\n const [isWholeDocumentSelected, setIsWholeDocumentSelected] = useWholeDocumentSelection();\n const { getSelectedBlockId, setSelectedBlockId } = useSelectedBlock();\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return undefined;\n\n const handleKeyDown = (event) => {\n // A non-editable block (image/divider/...) selected pending a second\n // Backspace/Delete (see EditableBlockContent's\n // selectOrDeleteContentlessNeighbor). Two different situations reach\n // here:\n // - The keydown bubbled up from an adjacent TEXT block's own\n // EditableBlockContent, which already fully handled it (selected\n // or deleted, and called preventDefault) — event.defaultPrevented\n // is already true, so there's nothing left to do here.\n // - The keydown landed *directly* on the already-selected, already-\n // focused block itself (a divider/embed has no EditableBlockContent\n // of its own to bubble through — see focusAfterMerge, which moves\n // real DOM focus onto it once the block that used to hold it was\n // deleted for being empty) — event.defaultPrevented is still\n // false, so this is the only place that can delete it.\n if (\n getSelectedBlockId() &&\n (event.key === 'Backspace' || event.key === 'Delete') &&\n !event.defaultPrevented\n ) {\n event.preventDefault();\n // This listener is native (added via addEventListener below) on an\n // ancestor of the React root's own delegated event target, so it\n // fires *before* React's synthetic onKeyDown dispatch during the\n // bubble phase. preventDefault() alone doesn't stop that dispatch —\n // without stopPropagation, the same keydown would also reach\n // whichever EditableBlockContent still has focus and be handled a\n // second time (e.g. re-evaluating its own now-stale neighbor check\n // after the divider this call just removed is already gone,\n // wrongly merging into the previous block instead of doing nothing).\n event.stopPropagation();\n deleteSelectedBlockAndRefocus(store, getSelectedBlockId(), setSelectedBlockId);\n return;\n }\n\n // Any other key cancels a pending selection, matching\n // isWholeDocumentSelected's own \"anything else cancels\" convention\n // below.\n if (getSelectedBlockId() && event.key !== 'Backspace' && event.key !== 'Delete') {\n setSelectedBlockId(null);\n }\n\n const mod = event.metaKey || event.ctrlKey;\n\n if (mod) {\n const key = event.key.toLowerCase();\n\n if (key === 'z' && !event.shiftKey) {\n event.preventDefault();\n if (store.undo?.()) restoreSelectionAfterHistoryChange(store);\n return;\n }\n if ((key === 'z' && event.shiftKey) || key === 'y') {\n event.preventDefault();\n if (store.redo?.()) restoreSelectionAfterHistoryChange(store);\n return;\n }\n if (key === 'a') {\n if (isWholeDocumentSelected) return; // already fully selected\n if (isEntireBlockSelected(store) || isCurrentBlockEmpty(store)) {\n event.preventDefault();\n // Deliberately leave the native selection alone (still\n // highlighting just the current block) rather than clearing\n // it — Ctrl+C/X/V are native browser commands that need an\n // active selection/focus target to even dispatch a copy/cut/\n // paste event to us at all. Our onCopy/onCut/onPaste always\n // check isWholeDocumentSelected first and use every top-level\n // block when it's set, so the leftover single-block native\n // selection's actual content is never used for anything.\n setIsWholeDocumentSelected(true);\n }\n return; // first press: let native Ctrl+A select the current block\n }\n if (MARK_KEYS[key]) {\n if (isWholeDocumentSelected) return; // formatting over \"select all\" isn't supported yet\n event.preventDefault();\n const markName = MARK_KEYS[key];\n\n const sameBlockSelection = resolveMultiRunSelection();\n if (sameBlockSelection) {\n const newRunId = toggleMarkOverSelection(\n store,\n sameBlockSelection.blockId,\n sameBlockSelection,\n markName,\n );\n if (newRunId) focusRunEnd(newRunId);\n return;\n }\n\n const crossBlockSelection = resolveCrossBlockSelection(store);\n if (crossBlockSelection) {\n const newRunId = toggleMarkOverBlockRange(store, crossBlockSelection, markName);\n if (newRunId) focusRunEnd(newRunId);\n }\n }\n return;\n }\n\n if (isWholeDocumentSelected) {\n if (event.key === 'Backspace' || event.key === 'Delete') {\n event.preventDefault();\n event.stopPropagation();\n const result = deleteEntireDocument(store);\n setIsWholeDocumentSelected(false);\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\n return;\n }\n if (event.key.length === 1) {\n // typing a printable character over \"select all\" replaces the\n // whole document with it, matching every editor's \"type over a\n // selection\" convention.\n event.preventDefault();\n event.stopPropagation();\n const result = deleteEntireDocument(store, event.key);\n setIsWholeDocumentSelected(false);\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\n return;\n }\n // Escape, arrows, or anything else not explicitly handled: just\n // cancel the mode and let the key proceed normally.\n setIsWholeDocumentSelected(false);\n if (event.key === 'Escape') return;\n }\n\n if (event.key === 'Backspace' || event.key === 'Delete') {\n const crossSelection = resolveCrossBlockSelection(store);\n if (!crossSelection) return; // same-block/collapsed: leave to EditableBlockContent's own handling\n\n event.preventDefault();\n event.stopPropagation(); // this block's own Backspace/Delete handler must not also run\n const result = deleteOverBlockRange(store, crossSelection);\n if (result?.runId) focusRunAtOffset(result.runId, result.offset);\n }\n };\n\n const handleMouseDown = () => {\n if (isWholeDocumentSelected) setIsWholeDocumentSelected(false);\n if (getSelectedBlockId()) setSelectedBlockId(null);\n };\n\n container.addEventListener('keydown', handleKeyDown);\n container.addEventListener('mousedown', handleMouseDown);\n return () => {\n container.removeEventListener('keydown', handleKeyDown);\n container.removeEventListener('mousedown', handleMouseDown);\n };\n }, [\n containerRef,\n store,\n isWholeDocumentSelected,\n setIsWholeDocumentSelected,\n getSelectedBlockId,\n setSelectedBlockId,\n ]);\n}\n","import { useEffect, useMemo } from 'react';\nimport { flushSync } from 'react-dom';\nimport { useEditorStore, useBlockRegistry, useInlineRegistry } from './EditorProvider.jsx';\nimport { resolveRunSelection, resolveCollapsedCaret } from './selectionResolve.js';\nimport { setCaretSync } from './focusRun.js';\n\n/**\n * Runs the behavior half of `defineExtension()` results — `keymap`,\n * `onBeforeInput`, `onPaste`, `setup` — for the extensions passed to\n * `useEditor({ extensions })`. `<NoteloomEditor>` calls this from its editor\n * surface (which owns `containerRef`); it must be called BEFORE\n * `useEditorKeyboardShortcuts` so an extension keymap gets first crack at a\n * key and can claim it (`event.stopImmediatePropagation()` then prevents the\n * built-in handler on the same element from also running).\n *\n * Entirely inert when `extensions` carries nothing with a behavior field —\n * `useEditor()` with no `extensions` adds zero listeners here.\n *\n * The `ctx` facade passed to every handler (stable for the life of the editor):\n * store, registry, inlineRegistry — the same objects useEditor made\n * container — the editor's root element (getter)\n * getBlock(id) / getRun(id) / getRootId()\n * applyOperation(op) / applyOperations(ops) — wrapped in flushSync so the DOM\n * is in sync before you setCaret()\n * getSelection() / getCaret() — resolveRunSelection / resolveCollapsedCaret\n * setCaret(runId, offset)\n * subscribe(fn) — store.subscribeAll\n */\nexport function useExtensionBehaviors(extensions, containerRef) {\n const store = useEditorStore();\n const registry = useBlockRegistry();\n const inlineRegistry = useInlineRegistry();\n\n const behaviorExtensions = useMemo(\n () =>\n (extensions ?? []).filter(\n (ext) => ext && (ext.keymap || ext.onBeforeInput || ext.onPaste || ext.setup),\n ),\n [extensions],\n );\n\n const ctx = useMemo(\n () => ({\n store,\n registry,\n inlineRegistry,\n get container() {\n return containerRef.current;\n },\n getBlock: (id) => store.getBlock(id),\n getRun: (id) => store.getRun(id),\n getRootId: () => store.getRootId(),\n applyOperation: (op) => flushSync(() => store.applyOperation(op)),\n applyOperations: (ops) =>\n flushSync(() => {\n if (typeof store.performBatch === 'function') store.performBatch(ops);\n else for (const op of ops) store.applyOperation(op);\n }),\n getSelection: () => resolveRunSelection(),\n getCaret: () => resolveCollapsedCaret(),\n setCaret: (runId, offset) => setCaretSync(runId, offset),\n subscribe: (fn) => store.subscribeAll(fn),\n }),\n [store, registry, inlineRegistry, containerRef],\n );\n\n // keymap / onBeforeInput / onPaste — native listeners on the surface.\n useEffect(() => {\n const container = containerRef.current;\n if (!container || behaviorExtensions.length === 0) return undefined;\n\n const withKeymap = behaviorExtensions.filter((ext) => ext.keymap);\n const withBeforeInput = behaviorExtensions.filter((ext) => ext.onBeforeInput);\n const withPaste = behaviorExtensions.filter((ext) => ext.onPaste);\n\n const onKeyDown = (event) => {\n for (const ext of withKeymap) {\n for (const [spec, handler] of Object.entries(ext.keymap)) {\n if (matchesKeymap(event, spec) && handler(ctx, event)) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return;\n }\n }\n }\n };\n const onBeforeInput = (event) => {\n for (const ext of withBeforeInput) {\n if (ext.onBeforeInput(ctx, event)) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return;\n }\n }\n };\n const onPaste = (event) => {\n for (const ext of withPaste) {\n if (ext.onPaste(ctx, event)) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return;\n }\n }\n };\n\n if (withKeymap.length) container.addEventListener('keydown', onKeyDown);\n if (withBeforeInput.length) container.addEventListener('beforeinput', onBeforeInput);\n if (withPaste.length) container.addEventListener('paste', onPaste);\n return () => {\n container.removeEventListener('keydown', onKeyDown);\n container.removeEventListener('beforeinput', onBeforeInput);\n container.removeEventListener('paste', onPaste);\n };\n }, [behaviorExtensions, containerRef, ctx]);\n\n // setup(ctx) — run once per extension, collect cleanups.\n useEffect(() => {\n const cleanups = behaviorExtensions\n .filter((ext) => ext.setup)\n .map((ext) => ext.setup(ctx))\n .filter((fn) => typeof fn === 'function');\n return () => {\n for (const fn of cleanups) fn();\n };\n }, [behaviorExtensions, ctx]);\n}\n\n/**\n * Matches a keydown against a spec like `Mod-Shift-k` / `Enter` / `Tab`.\n * `Mod` = Ctrl on Windows/Linux, Cmd on Mac (either metaKey or ctrlKey).\n */\nexport function matchesKeymap(event, spec) {\n const parts = String(spec).split('-');\n const key = parts.pop().toLowerCase();\n const mods = new Set(parts.map((p) => p.toLowerCase()));\n\n const hasMod = event.metaKey || event.ctrlKey;\n if (mods.has('mod') !== hasMod) return false;\n if (mods.has('shift') !== event.shiftKey) return false;\n if (mods.has('alt') !== event.altKey) return false;\n\n return event.key.toLowerCase() === key;\n}\n","import { useCallback, useEffect, useRef } from 'react';\nimport { useEditorStore, useBlockRangeSelection } from './EditorProvider.jsx';\n\n// Minimum pointer movement (px) before a press counts as an actual drag —\n// below this, mouseup fires with nothing selected at all. Keeps a plain\n// click in the margin (mousedown+mouseup with no real movement) from\n// selecting a block; only a genuine drag gesture does.\nconst DRAG_THRESHOLD_PX = 4;\n\n/** Ids of `anchorId`..`hoverId` inclusive, in document order, among their shared parent's siblings. */\nfunction computeRange(store, anchorId, hoverId) {\n const anchorBlock = store.getBlock(anchorId);\n if (!anchorBlock) return [];\n const parent = store.getBlock(anchorBlock.parentId);\n if (!parent) return [anchorId];\n\n const ids = parent.contentIds;\n const anchorIndex = ids.indexOf(anchorId);\n const hoverIndex = hoverId ? ids.indexOf(hoverId) : anchorIndex;\n if (anchorIndex === -1) return [anchorId];\n const [from, to] =\n hoverIndex === -1\n ? [anchorIndex, anchorIndex]\n : [Math.min(anchorIndex, hoverIndex), Math.max(anchorIndex, hoverIndex)];\n return ids.slice(from, to + 1);\n}\n\nfunction isCoarsePointer() {\n return (\n typeof window !== 'undefined' && window.matchMedia?.('(pointer: coarse)')?.matches === true\n );\n}\n\n/**\n * \"Drag in the margin to select a run of blocks\" mechanic.\n * Call this ONCE (e.g. in EditorSurface), passing the same containerRef the\n * rest of the surface's own trigger hooks use — it registers a single\n * document-level mousedown listener that decides, per press, whether it\n * landed somewhere that COULD start a block-range drag:\n *\n * - Inside a block row's own DOM box (data-block-row-id) but OUTSIDE its\n * rendered content (be-block-row-content) — covers both the narrow\n * per-block gutter (the +/grip buttons sit there too, so those are\n * explicitly excluded) and any empty space to a short block's right.\n * - Entirely outside every row's own box, but still within this editor's\n * container — covers the wide blank page margins on either side of the\n * content column (`.be-surface`'s own `max-width` centering), found by\n * whichever row's vertical span contains the click's Y coordinate.\n *\n * That press only becomes an actual selection once the pointer has moved\n * at least DRAG_THRESHOLD_PX from where it went down — a plain click\n * (mousedown immediately followed by mouseup, no real movement) selects\n * nothing at all. This is a genuine drag-to-select gesture, not a\n * click-to-select one; a single block can still be selected by dragging a\n * few pixels within its own row.\n *\n * A press directly on the actual editable content (inside\n * be-block-row-content) is deliberately left alone either way, so normal\n * click-to-place-caret and native text selection are never hijacked.\n *\n * Disabled entirely on coarse-pointer (touch) devices — dragging in the\n * margin would fight the page's own scroll gesture there, and there's no\n * equivalent \"hover to reveal the gutter\" affordance on touch anyway.\n */\nexport function useBlockRangeDrag(containerRef) {\n const store = useEditorStore();\n const [, setSelectedBlockRange] = useBlockRangeSelection();\n const anchorIdRef = useRef(null); // set from mousedown onward, whether or not the drag has \"armed\" yet\n const isArmedRef = useRef(false); // true only once movement has passed DRAG_THRESHOLD_PX\n const startPointRef = useRef(null);\n\n const handleMouseMove = useCallback(\n (event) => {\n if (!anchorIdRef.current) return;\n\n if (!isArmedRef.current) {\n const { x, y } = startPointRef.current ?? { x: event.clientX, y: event.clientY };\n const movedPx = Math.hypot(event.clientX - x, event.clientY - y);\n if (movedPx < DRAG_THRESHOLD_PX) return;\n isArmedRef.current = true;\n // Suppresses native text selection for the rest of this drag —\n // preventDefault alone isn't enough once the pointer has crossed\n // into real block content: the browser may have already latched\n // onto that content as a fresh selection anchor. `user-select:none`\n // on the document root is the standard belt-and-braces fix (see\n // `.be-block-range-dragging` in the example app's CSS), removed the\n // instant the drag ends.\n document.documentElement.classList.add('be-block-range-dragging');\n window.getSelection?.()?.removeAllRanges();\n }\n // Also keep clearing it on every subsequent move — some browsers\n // still extend a selection that started a frame earlier even with\n // user-select:none applied mid-gesture.\n window.getSelection?.()?.removeAllRanges();\n event.preventDefault();\n\n const el = document\n .elementFromPoint(event.clientX, event.clientY)\n ?.closest('[data-block-row-id]');\n const hoverId = el?.getAttribute('data-block-row-id') ?? null;\n setSelectedBlockRange(computeRange(store, anchorIdRef.current, hoverId));\n },\n [store, setSelectedBlockRange],\n );\n\n const handleMouseUp = useCallback(() => {\n anchorIdRef.current = null;\n isArmedRef.current = false;\n startPointRef.current = null;\n document.documentElement.classList.remove('be-block-range-dragging');\n }, []);\n\n const armDrag = useCallback((blockId, event) => {\n anchorIdRef.current = blockId;\n isArmedRef.current = false;\n startPointRef.current = { x: event.clientX, y: event.clientY };\n }, []);\n\n const handleMouseDown = useCallback(\n (event) => {\n if (event.button !== 0) return; // left click only\n if (isCoarsePointer()) return;\n if (event.target.closest?.('button, input, textarea, select')) return;\n\n const row = event.target.closest('[data-block-row-id]');\n if (row) {\n // DOM-ancestor check, not a geometry/rect comparison: the previous\n // rect-based version only compared clientX against\n // be-block-row-content's own bounding box, and (a) never checked Y\n // at all, (b) broke down for any block whose content box isn't a\n // simple full-width rectangle (wrapped text, an inline chip at the\n // end of a short line, a table). Any of those could put a genuine\n // click on real content just outside the rect's clientX range,\n // misclassifying it as \"margin\" and arming a drag — which doesn't\n // itself steal the click, but does mean the *next* mousemove (even\n // an incidental few px of jitter before the click properly\n // registers) can flip it into an actual drag-select, hijacking\n // what the user experienced as a plain click. Walking the DOM via\n // closest() instead answers \"is this element actually inside the\n // block's own rendered content\" exactly, with no geometry involved.\n if (event.target.closest('.be-block-row-content')) return;\n armDrag(row.getAttribute('data-block-row-id'), event);\n return;\n }\n\n // The press landed entirely outside every row's own DOM box — the\n // wide blank page margin on either side of `.be-surface`'s centered\n // content column (that margin is never inside any row's own element,\n // since each row is only ever as wide as the content column itself).\n // Scoped to THIS editor's own rows via containerRef, deliberately\n // NOT via container.contains(event.target) — a blank-margin click's\n // target is by definition outside the container's own narrower box.\n const container = containerRef?.current;\n if (!container) return;\n const rows = [...container.querySelectorAll('[data-block-row-id]')];\n const hovered = rows.find((el) => {\n const r = el.getBoundingClientRect();\n return event.clientY >= r.top && event.clientY <= r.bottom;\n });\n if (hovered) {\n armDrag(hovered.getAttribute('data-block-row-id'), event);\n }\n },\n [containerRef, armDrag],\n );\n\n useEffect(() => {\n document.addEventListener('mousedown', handleMouseDown);\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n return () => {\n document.removeEventListener('mousedown', handleMouseDown);\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n document.documentElement.classList.remove('be-block-range-dragging'); // in case unmounted mid-drag\n };\n }, [handleMouseDown, handleMouseMove, handleMouseUp]);\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useVirtualKeyboardInset } from '../react/useVirtualKeyboardInset.js';\nimport { useHorizontalAutoAdjustedLeft } from '../react/usePopoverEdgeClamp.js';\n\n// Rough worst-case menu height (max-height in .be-slash-menu's own CSS is\n// 320px, plus a little padding) — used only to decide *which side* of the\n// caret to open on, not as an exact pixel budget, so an approximation here\n// is fine either way.\nconst ESTIMATED_MENU_HEIGHT = 340;\n\n/**\n * Focus deliberately stays in the run's contentEditable (moving it into the\n * menu would exit typing) — so this follows the ARIA \"listbox with\n * aria-activedescendant\" pattern: the actively-selected option lives in\n * `aria-activedescendant` on whatever *does* have focus (the triggering run\n * element), not on the listbox itself. `runId` is what identifies that\n * element; its `aria-expanded`/`aria-activedescendant` are set/cleared here\n * rather than threaded through every block type, since only this component\n * knows the listbox's ids and open/active state.\n */\nfunction useActiveDescendantWiring(isOpen, runId, activeOptionId, menuId) {\n useEffect(() => {\n if (!isOpen || !runId) return undefined;\n const runEl = document.querySelector(`[data-run-id=\"${runId}\"]`);\n if (!runEl) return undefined;\n\n runEl.setAttribute('aria-expanded', 'true');\n runEl.setAttribute('aria-haspopup', 'listbox');\n runEl.setAttribute('aria-controls', menuId);\n if (activeOptionId) runEl.setAttribute('aria-activedescendant', activeOptionId);\n\n return () => {\n runEl.removeAttribute('aria-expanded');\n runEl.removeAttribute('aria-haspopup');\n runEl.removeAttribute('aria-controls');\n runEl.removeAttribute('aria-activedescendant');\n };\n }, [isOpen, runId, activeOptionId, menuId]);\n}\n\n/**\n * Generic filterable command popover — not slash-specific despite the name\n * (kept for backward compatibility), also used as-is for the \":\" emoji menu\n * (see useEmojiMenuTrigger). Pass a distinct `menuId`/`ariaLabel` for a\n * second simultaneously-mounted instance so DOM ids and\n * aria-controls/aria-activedescendant wiring never collide between them.\n */\nexport function SlashMenu({\n isOpen,\n rect,\n commands,\n runId,\n onSelect,\n onClose,\n menuId = 'be-slash-menu',\n ariaLabel = 'Slash commands',\n}) {\n const [activeIndex, setActiveIndex] = useState(0);\n const activeItemRef = useRef(null);\n const menuRef = useRef(null);\n const keyboardInset = useVirtualKeyboardInset();\n const adjustedLeft = useHorizontalAutoAdjustedLeft(\n menuRef,\n isOpen && commands.length > 0 && Boolean(rect),\n rect?.left,\n );\n\n useEffect(() => {\n setActiveIndex(0);\n }, [commands.length]);\n\n // Keeps the keyboard-active item visible as Arrow Up/Down moves it past\n // the edge of the scrollable list — without this, arrowing past the\n // bottom (or top) leaves the highlighted item scrolled out of view with\n // nothing on screen showing which one is currently selected.\n useEffect(() => {\n activeItemRef.current?.scrollIntoView?.({ block: 'nearest' });\n }, [activeIndex]);\n\n useEffect(() => {\n if (!isOpen) return undefined;\n\n const handleKeyDown = (event) => {\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n event.stopPropagation();\n setActiveIndex((i) => Math.min(i + 1, Math.max(commands.length - 1, 0)));\n } else if (event.key === 'ArrowUp') {\n event.preventDefault();\n event.stopPropagation();\n setActiveIndex((i) => Math.max(i - 1, 0));\n } else if (event.key === 'Enter') {\n event.preventDefault();\n event.stopPropagation();\n if (commands[activeIndex]) onSelect(commands[activeIndex]);\n } else if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n onClose();\n }\n };\n\n // capture phase: must win over EditableBlockContent's own onKeyDown (Enter/etc.)\n document.addEventListener('keydown', handleKeyDown, true);\n return () => document.removeEventListener('keydown', handleKeyDown, true);\n }, [isOpen, commands, activeIndex, onSelect, onClose]);\n\n const activeCommand = commands[activeIndex];\n const activeOptionId = activeCommand ? `${menuId}-option-${activeIndex}` : null;\n useActiveDescendantWiring(isOpen, runId, activeOptionId, menuId);\n\n if (!isOpen || commands.length === 0 || !rect || adjustedLeft == null) return null;\n\n // Flip to open above the caret instead of below it once there isn't\n // enough room left under it before the keyboard (or the bottom of the\n // screen) starts — without this, the popover can render partly or\n // entirely underneath the on-screen keyboard, invisible.\n const availableBottom = window.innerHeight - keyboardInset;\n const openAbove = rect.bottom + ESTIMATED_MENU_HEIGHT > availableBottom;\n const positionStyle = openAbove\n ? { bottom: window.innerHeight - rect.top + 4 }\n : { top: rect.bottom + 4 };\n\n return (\n <div\n ref={menuRef}\n id={menuId}\n role=\"listbox\"\n aria-label={ariaLabel}\n className=\"be-slash-menu\"\n style={{ position: 'fixed', left: adjustedLeft, zIndex: 1000, ...positionStyle }}\n >\n {commands.map((command, i) => {\n const Icon = command.icon;\n return (\n <div\n key={command.label}\n ref={i === activeIndex ? activeItemRef : undefined}\n id={`${menuId}-option-${i}`}\n role=\"option\"\n aria-selected={i === activeIndex}\n className={`be-slash-menu-item${i === activeIndex ? ' be-slash-menu-item-active' : ''}`}\n onMouseDown={(event) => {\n event.preventDefault();\n onSelect(command);\n }}\n onMouseEnter={() => setActiveIndex(i)}\n >\n {Icon && (\n <span className=\"be-slash-menu-item-icon\">\n <Icon size={16} />\n </span>\n )}\n <span className=\"be-slash-menu-item-label\">{command.label}</span>\n </div>\n );\n })}\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useEditorStore } from '../react/EditorProvider.jsx';\nimport { stripEmptyRunPlaceholder } from '../react/domRunSync.js';\n\nfunction matchesQuery(command, query) {\n if (!query) return true;\n const q = query.toLowerCase();\n return (\n command.label.toLowerCase().includes(q) ||\n command.keywords?.some((k) => k.toLowerCase().includes(q))\n );\n}\n\n/**\n * Resolves the caret's logical offset within `runEl`'s text (with the\n * empty-run placeholder stripped), regardless of whether the browser's\n * selection anchors on the run's text node directly or on the run element\n * itself (e.g. a not-yet-populated node). Falls back to \"end of text\" if\n * the selection isn't actually inside this element.\n */\nfunction caretOffsetInRun(runEl, selection) {\n const node = selection.anchorNode;\n const rawOffset = selection.anchorOffset;\n let rawTextBeforeCaret;\n\n if (node === runEl) {\n rawTextBeforeCaret = '';\n for (let i = 0; i < rawOffset && i < runEl.childNodes.length; i += 1) {\n rawTextBeforeCaret += runEl.childNodes[i].textContent ?? '';\n }\n } else if (node && node.parentElement === runEl) {\n rawTextBeforeCaret = (node.textContent ?? '').slice(0, rawOffset);\n } else {\n rawTextBeforeCaret = runEl.textContent ?? '';\n }\n\n return stripEmptyRunPlaceholder(rawTextBeforeCaret).length;\n}\n\n/**\n * Shared machinery behind both useSlashMenuTrigger (\"/\") and\n * useEmojiMenuTrigger (\":\") — watches for `regex` matching the text up to\n * the caret within any run inside `containerRef`, and resolves the matching\n * commands via `getCommands()`. Each caller only differs in its trigger\n * regex and its command source; the caret-resolution/query-matching/\n * keyboard-dismiss logic (this file) is identical either way.\n *\n * `regex` must have exactly two capture groups: group 1 is whatever\n * precedes the trigger character (start-of-string or whitespace, so it\n * isn't consumed as part of the query), group 2 is the query typed after\n * the trigger character.\n */\nexport function useTriggerMenu(containerRef, regex, getCommands) {\n const store = useEditorStore();\n const [state, setState] = useState(null); // { query, blockId, runId, sliceStart, sliceEnd, rect }\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return undefined;\n\n const handleInput = () => {\n const selection = window.getSelection?.();\n const anchorNode = selection?.anchorNode;\n let el = anchorNode?.nodeType === 1 ? anchorNode : anchorNode?.parentElement;\n while (el && typeof el.hasAttribute === 'function' && !el.hasAttribute('data-run-id')) {\n el = el.parentElement;\n }\n const runId = el?.getAttribute?.('data-run-id');\n if (!runId || !selection) {\n setState(null);\n return;\n }\n\n const caretOffset = caretOffsetInRun(el, selection);\n const textBeforeCaret = stripEmptyRunPlaceholder(el.textContent).slice(0, caretOffset);\n const match = regex.exec(textBeforeCaret);\n if (!match) {\n setState(null);\n return;\n }\n\n const blockId = el.closest?.('[data-block-id]')?.getAttribute('data-block-id');\n if (!blockId) {\n setState(null);\n return;\n }\n const sliceStart = match.index + match[1].length; // position of the trigger character itself\n setState({\n query: match[2],\n blockId,\n runId,\n sliceStart,\n sliceEnd: caretOffset,\n rect: el.getBoundingClientRect(),\n });\n };\n\n const handleKeyDown = (event) => {\n if (event.key === 'Escape') setState(null);\n };\n\n container.addEventListener('input', handleInput);\n container.addEventListener('keydown', handleKeyDown);\n return () => {\n container.removeEventListener('input', handleInput);\n container.removeEventListener('keydown', handleKeyDown);\n };\n }, [containerRef, regex]);\n\n const commands = state ? getCommands().filter((cmd) => matchesQuery(cmd, state.query)) : [];\n\n const selectCommand = useCallback(\n (command) => {\n if (!state) return;\n // Deliberately does NOT trim the query text here: a block command\n // just wants it gone (trimSlashQueryAndInsertAfter handles that), but\n // an inline command needs the untouched sliceStart/sliceEnd to splice\n // its chip/text in at the exact cursor position — pre-merging before/\n // after text here would destroy that split point.\n command.run(store, {\n blockId: state.blockId,\n runId: state.runId,\n sliceStart: state.sliceStart,\n sliceEnd: state.sliceEnd,\n });\n setState(null);\n },\n [state, store],\n );\n\n const close = useCallback(() => setState(null), []);\n\n return {\n isOpen: Boolean(state),\n query: state?.query ?? '',\n rect: state?.rect ?? null,\n runId: state?.runId ?? null,\n commands,\n selectCommand,\n close,\n };\n}\n","import { useCallback } from 'react';\nimport { useBlockRegistry, useInlineRegistry } from '../react/EditorProvider.jsx';\nimport { useTriggerMenu } from './useTriggerMenu.js';\n\n// Matches a \"/\" at the very start of the text, or right after whitespace,\n// followed by any word characters, anchored to the END of the string passed\n// in — the caller passes only the text *up to the caret*, which is what\n// lets \"/\" work with content after the cursor too (\"hello /table| world\"),\n// not just when the caret happens to be at the very end of the run.\nconst SLASH_RE = /(^|\\s)\\/(\\w*)$/;\n\n/**\n * Watches for \"/\" typed anywhere inside a run within `containerRef` and\n * tracks the query typed after it — works mid-block, with other text both\n * before and after the trigger in the same run, not just when the caret is\n * at the very end of otherwise-empty content. Commands come from both the\n * block registry (insert a new block after the current one) and the\n * inline-type registry (splice an atomic element in at the cursor) — see\n * each type's own `run(store, {blockId, runId})`. Only the matched\n * \"/query\" substring is removed on selection (preserving whatever comes\n * before *and after* it in the run), not the whole run.\n *\n * Emoji is its own separate \":\" trigger (see useEmojiMenuTrigger) — not\n * merged in here — so it doesn't crowd out every other \"/\" command with\n * ~60 emoji entries.\n *\n * See useTriggerMenu for the shared caret-resolution/query-matching\n * machinery this and useEmojiMenuTrigger both build on.\n */\nexport function useSlashMenuTrigger(containerRef) {\n const registry = useBlockRegistry();\n const inlineRegistry = useInlineRegistry();\n\n const getCommands = useCallback(\n () => [...registry.listSlashCommands(), ...(inlineRegistry?.listSlashCommands() ?? [])],\n [registry, inlineRegistry],\n );\n\n return useTriggerMenu(containerRef, SLASH_RE, getCommands);\n}\n","/**\n * A curated, hardcoded set of common emoji — no external emoji-data\n * package (matches this project's zero-runtime-dependency constraint).\n * Each entry's `name` doubles as its slash-command label/search keyword;\n * `keywords` adds a couple of common synonyms so \"/fire\", \"/heart\", etc.\n * find the right one directly, without having to type \"/emoji\" first.\n */\nexport const EMOJI_LIST = [\n { char: '😀', name: 'grinning face', keywords: ['smile', 'happy'] },\n { char: '😂', name: 'face with tears of joy', keywords: ['laugh', 'lol'] },\n { char: '😍', name: 'heart eyes', keywords: ['love', 'crush'] },\n { char: '😎', name: 'cool', keywords: ['sunglasses'] },\n { char: '🤔', name: 'thinking face', keywords: ['hmm'] },\n { char: '😉', name: 'winking face', keywords: ['wink'] },\n { char: '😢', name: 'crying face', keywords: ['sad', 'tear'] },\n { char: '😡', name: 'angry face', keywords: ['mad', 'rage'] },\n { char: '😱', name: 'screaming face', keywords: ['shock', 'scared'] },\n { char: '🥳', name: 'party face', keywords: ['celebrate', 'birthday'] },\n { char: '🙏', name: 'folded hands', keywords: ['please', 'pray', 'thanks'] },\n { char: '👍', name: 'thumbs up', keywords: ['approve', 'yes', 'like'] },\n { char: '👎', name: 'thumbs down', keywords: ['disapprove', 'no'] },\n { char: '👏', name: 'clapping hands', keywords: ['applause', 'congrats'] },\n { char: '🙌', name: 'raised hands', keywords: ['hooray', 'yay'] },\n { char: '👋', name: 'waving hand', keywords: ['hello', 'bye'] },\n { char: '✌️', name: 'victory hand', keywords: ['peace'] },\n { char: '💪', name: 'flexed biceps', keywords: ['strong', 'muscle'] },\n { char: '🤝', name: 'handshake', keywords: ['deal', 'agree'] },\n { char: '❤️', name: 'red heart', keywords: ['love'] },\n { char: '🔥', name: 'fire', keywords: ['hot', 'lit'] },\n { char: '⭐', name: 'star', keywords: ['favorite'] },\n { char: '✨', name: 'sparkles', keywords: ['shiny', 'magic'] },\n { char: '🎉', name: 'party popper', keywords: ['celebrate', 'congrats'] },\n { char: '🎊', name: 'confetti ball', keywords: ['celebrate'] },\n { char: '💡', name: 'light bulb', keywords: ['idea', 'tip'] },\n { char: '✅', name: 'check mark', keywords: ['done', 'yes', 'complete'] },\n { char: '❌', name: 'cross mark', keywords: ['no', 'wrong', 'delete'] },\n { char: '⚠️', name: 'warning', keywords: ['caution', 'alert'] },\n { char: '❓', name: 'question mark', keywords: ['question', 'help'] },\n { char: '❗', name: 'exclamation mark', keywords: ['important', 'alert'] },\n { char: '🚀', name: 'rocket', keywords: ['launch', 'fast', 'ship'] },\n { char: '🐛', name: 'bug', keywords: ['bug', 'issue'] },\n { char: '🔧', name: 'wrench', keywords: ['fix', 'tool', 'settings'] },\n { char: '📌', name: 'pushpin', keywords: ['pin', 'note'] },\n { char: '📎', name: 'paperclip', keywords: ['attachment', 'clip'] },\n { char: '📅', name: 'calendar', keywords: ['date', 'schedule'] },\n { char: '⏰', name: 'alarm clock', keywords: ['time', 'reminder'] },\n { char: '📈', name: 'chart increasing', keywords: ['growth', 'stats'] },\n { char: '📉', name: 'chart decreasing', keywords: ['decline', 'stats'] },\n { char: '💰', name: 'money bag', keywords: ['money', 'cash'] },\n { char: '💬', name: 'speech balloon', keywords: ['comment', 'chat'] },\n { char: '📝', name: 'memo', keywords: ['note', 'write'] },\n { char: '📚', name: 'books', keywords: ['reading', 'docs'] },\n { char: '🔗', name: 'link', keywords: ['url', 'chain'] },\n { char: '🔒', name: 'locked', keywords: ['private', 'secure'] },\n { char: '🔑', name: 'key', keywords: ['password', 'access'] },\n { char: '☕', name: 'coffee', keywords: ['coffee', 'break'] },\n { char: '🍕', name: 'pizza', keywords: ['food'] },\n { char: '🎂', name: 'birthday cake', keywords: ['birthday', 'cake'] },\n { char: '🎁', name: 'gift', keywords: ['present'] },\n { char: '🌟', name: 'glowing star', keywords: ['star', 'shiny'] },\n { char: '🌈', name: 'rainbow', keywords: ['colorful'] },\n { char: '☀️', name: 'sun', keywords: ['sunny', 'weather'] },\n { char: '🌧️', name: 'rain cloud', keywords: ['rainy', 'weather'] },\n { char: '🐶', name: 'dog face', keywords: ['dog', 'pet'] },\n { char: '🐱', name: 'cat face', keywords: ['cat', 'pet'] },\n { char: '🌍', name: 'globe', keywords: ['world', 'earth'] },\n { char: '🎯', name: 'direct hit', keywords: ['target', 'goal'] },\n { char: '🏆', name: 'trophy', keywords: ['win', 'award'] },\n { char: '🕐', name: 'clock', keywords: ['time'] },\n { char: '📣', name: 'megaphone', keywords: ['announce', 'shout'] },\n { char: '🧠', name: 'brain', keywords: ['smart', 'idea', 'mind'] },\n { char: '👀', name: 'eyes', keywords: ['look', 'watching'] },\n];\n","import { updateRun } from '../../store/operations.js';\nimport { focusRunAtOffset } from '../../react/focusRun.js';\n\n/**\n * Replaces the [sliceStart, sliceEnd) \"/query\" span in `runId`'s own text\n * with literal `text` — unlike insertInlineRunAtCursor, this never creates\n * a new run at all: the inserted content is ordinary text (an emoji\n * character), not an atomic chip, so it's just as selectable/deletable/\n * editable as anything else typed there. Used by the emoji slash commands.\n */\nexport function insertPlainTextAtCursor(store, { runId, sliceStart, sliceEnd }, text) {\n const run = store.getRun(runId);\n const value = run?.value ?? '';\n const newValue = value.slice(0, sliceStart) + text + value.slice(sliceEnd);\n store.applyOperation(updateRun(runId, { value: newValue }));\n focusRunAtOffset(runId, sliceStart + text.length);\n}\n","import { EMOJI_LIST } from './emojiList.js';\nimport { insertPlainTextAtCursor } from '../shared/insertPlainText.js';\n\n/**\n * One command per emoji, shared between however many trigger surfaces want\n * it (currently just the \":\" emoji menu — see useEmojiMenuTrigger). Kept as\n * its own module, separate from emojiList.js's raw data and index.js's\n * (now-empty) inline-type registration, so it's reusable without pulling in\n * anything registry-specific.\n */\nexport const EMOJI_COMMANDS = EMOJI_LIST.map(({ char, name, keywords }) => ({\n label: `${char} ${name}`,\n keywords,\n run: (store, ctx) => insertPlainTextAtCursor(store, ctx, char),\n}));\n","import { useTriggerMenu } from './useTriggerMenu.js';\nimport { EMOJI_COMMANDS } from '../inlineTypes/emoji/emojiCommands.js';\n\n// Matches a \":\" at the very start of the text, or right after whitespace,\n// followed by any word characters — same shape as the slash trigger, just a\n// different character, so \":fire\" narrows to 🔥 without colliding with \"/\"\n// commands typed in the same run.\nconst EMOJI_RE = /(^|\\s):(\\w*)$/;\n\nconst getEmojiCommands = () => EMOJI_COMMANDS;\n\n/**\n * Watches for \":\" typed anywhere inside a run within `containerRef` and\n * tracks the query typed after it, resolving against the built-in emoji\n * list — its own dedicated trigger, deliberately separate from \"/\" (see\n * useSlashMenuTrigger's doc comment), so emoji don't crowd out every other\n * slash command. Render the SAME `SlashMenu` component against this hook's\n * return value (it's a generic filterable command popover, not slash-\n * specific) — pass distinct `menuId`/`ariaLabel` props so the two popovers\n * (this one and the \"/\" one) never collide if both happen to be mounted at\n * once.\n */\nexport function useEmojiMenuTrigger(containerRef) {\n return useTriggerMenu(containerRef, EMOJI_RE, getEmojiCommands);\n}\n","import { useCallback } from 'react';\nimport { useInlineRegistry } from '../react/EditorProvider.jsx';\nimport { useTriggerMenu } from './useTriggerMenu.js';\n\n// Same shape as SLASH_RE/EMOJI_RE (see useSlashMenuTrigger/useEmojiMenuTrigger)\n// with \"@\" as the trigger character instead.\nconst AT_RE = /(^|\\s)@(\\w*)$/;\n\n/**\n * Watches for \"@\" typed anywhere inside a run within `containerRef` and\n * tracks the query typed after it, resolving against every inline type\n * that opted into `atCommand`/`atCommands` (see InlineRegistry's doc\n * comment) — its own dedicated trigger, deliberately separate from \"/\"\n * (same rationale as useEmojiMenuTrigger's own \":\" trigger: doesn't crowd\n * out every other slash command, and \"@\" carries its own well-understood\n * meaning elsewhere that \"/\" doesn't).\n *\n * Not every inline type shows up here — only ones that asked to (e.g. a\n * host-defined \"Assignee\" field type registered with\n * `createSelectFieldType({ ..., triggers: ['slash', 'at'] })`). A generic\n * \"Priority\"/\"Status\" dropdown, for instance, would usually stay slash-only\n * since \"@Priority\" doesn't read naturally the way \"@Assignee\" does.\n *\n * Render the SAME `SlashMenu` component against this hook's return value\n * (it's a generic filterable command popover, not slash-specific) — pass a\n * distinct `menuId`/`ariaLabel`, same as the emoji menu, so the popovers\n * never collide if more than one happens to be mounted at once.\n */\nexport function useAtMenuTrigger(containerRef) {\n const inlineRegistry = useInlineRegistry();\n const getAtCommands = useCallback(() => inlineRegistry?.listAtCommands() ?? [], [inlineRegistry]);\n return useTriggerMenu(containerRef, AT_RE, getAtCommands);\n}\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(\n (href, target) => applyLinkPatch({ link: { href, target } }),\n [applyLinkPatch],\n );\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 (\n typeof window !== 'undefined' && window.matchMedia?.('(pointer: coarse)')?.matches === true\n );\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 {\n BoldIcon,\n ItalicIcon,\n UnderlineIcon,\n StrikethroughIcon,\n LinkIcon,\n CommentIcon,\n} 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({\n isOpen,\n rect,\n kind,\n selection,\n crossSelection,\n marks,\n store,\n onComment,\n commentAuthorId,\n}) {\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))\n 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={{\n position: 'fixed',\n top: rect.top - 44,\n left: centerLeft,\n transform: 'translateX(-50%)',\n }}\n onMouseDown={(event) => {\n if (event.target.tagName !== 'TEXTAREA') event.preventDefault();\n }}\n >\n <CommentPopoverHeader title=\"Add comment\" onClose={cancelCommentComposer} />\n <CommentComposer\n authorId={commentAuthorId}\n autoFocus\n onSubmit={submitCommentComposer}\n onCancel={cancelCommentComposer}\n />\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={{\n position: 'fixed',\n top: rect.top - 44,\n left: centerLeft,\n transform: 'translateX(-50%)',\n }}\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={{\n backgroundColor: marks.highlight || 'transparent',\n padding: '0 2px',\n borderRadius: 2,\n }}\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';\nimport { useEditorStore } from '../react/EditorProvider.jsx';\nimport { resolveMultiRunSelection, resolveCrossBlockSelection } from '../react/selectionResolve.js';\nimport {\n getMarksSummaryOverSelection,\n getMarksSummaryOverBlockRange,\n} from '../inline/markCommands.js';\n\n/**\n * Shows a floating format toolbar whenever the current selection is a real\n * (non-collapsed) text range within `containerRef` — same-block or\n * cross-block, reusing the exact same resolvers useEditorKeyboardShortcuts'\n * Ctrl+B/I already rely on, so \"can this selection be formatted at all\" is\n * answered identically everywhere in the codebase, not re-derived here.\n *\n * Listens on `document`'s `selectionchange` (selection state can change from\n * a mouseup/keyup that fires outside this exact container, e.g. releasing a\n * drag over another block) rather than a local mouseup/keyup — this mirrors\n * how real editors track selection, and is the only event that reliably\n * fires for every way a selection can change (mouse drag, shift+arrow,\n * double/triple-click, select-all, programmatic).\n *\n * Position is read directly off `Range.getBoundingClientRect()` — a\n * `position: fixed` box anchored to that rect stays correct regardless of\n * page scroll, so this also recomputes on window scroll/resize (capture\n * phase, since an inner scrollable region's scroll event doesn't bubble to\n * window by default).\n */\nexport function useFloatingToolbarTrigger(containerRef) {\n const store = useEditorStore();\n const [state, setState] = useState(null); // { rect, kind: 'same-block' | 'cross-block', selection/crossSelection, marks }\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return undefined;\n\n const recompute = () => {\n // Don't re-derive (and don't blank out) toolbar state while focus is\n // inside the toolbar's own popover content (e.g. typing into the\n // Comment button's inline composer textarea) -- a <textarea> isn't\n // part of the editor's own run/block DOM, so resolveMultiRunSelection\n // below would find nothing and close the whole toolbar out from under\n // whatever's being typed. The toolbar keeps showing whatever\n // selection/rect it already had before focus moved there.\n if (document.activeElement?.closest?.('.be-floating-toolbar')) return;\n\n const selection = window.getSelection?.();\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {\n setState(null);\n return;\n }\n if (!container.contains(selection.anchorNode) || !container.contains(selection.focusNode)) {\n setState(null);\n return;\n }\n\n // jsdom (used by this package's own test suite) implements\n // Element.prototype.getBoundingClientRect but not\n // Range.prototype.getBoundingClientRect at all — falling back to a\n // zero rect keeps this hook's logic testable without a real layout\n // engine, the same way a zero-size rect from a real browser (a\n // genuinely empty range) is already handled fine by callers.\n const rect = selection.getRangeAt(0).getBoundingClientRect?.() ?? {\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n width: 0,\n height: 0,\n };\n\n const sameBlock = resolveMultiRunSelection();\n if (sameBlock) {\n setState({\n kind: 'same-block',\n rect,\n selection: sameBlock,\n marks: getMarksSummaryOverSelection(store, sameBlock.blockId, sameBlock),\n });\n return;\n }\n\n const crossBlock = resolveCrossBlockSelection(store);\n if (crossBlock) {\n setState({\n kind: 'cross-block',\n rect,\n crossSelection: crossBlock,\n marks: getMarksSummaryOverBlockRange(store, crossBlock),\n });\n return;\n }\n\n setState(null);\n };\n\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 }, [containerRef, store]);\n\n return {\n isOpen: Boolean(state),\n rect: state?.rect ?? null,\n kind: state?.kind ?? null,\n selection: state?.selection ?? null,\n crossSelection: state?.crossSelection ?? null,\n marks: state?.marks ?? {},\n close: () => setState(null),\n };\n}\n","import { ArrowUpIcon, ArrowDownIcon, XIcon, ChevronRightIcon } from './icons.jsx';\n\n/**\n * The visible bar for `useFindInDocument` — pass through everything that\n * hook returns. Rendered inline (not portaled) at the top of the editor\n * container by `NoteloomEditor`; a host assembling its own UI from the\n * lower-level pieces can mount it (or a custom bar built on the same hook)\n * wherever makes sense for their layout.\n */\nexport function FindBar({\n isOpen,\n close,\n query,\n setQuery,\n caseSensitive,\n setCaseSensitive,\n wholeWord,\n setWholeWord,\n isReplaceOpen,\n setIsReplaceOpen,\n replacement,\n setReplacement,\n matches,\n currentIndex,\n next,\n prev,\n replaceCurrent,\n replaceAll,\n queryInputRef,\n}) {\n if (!isOpen) return null;\n\n const handleQueryKeyDown = (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n if (event.shiftKey) prev();\n else next();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n close();\n }\n };\n\n const handleReplaceKeyDown = (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n replaceCurrent();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n close();\n }\n };\n\n return (\n <div className=\"be-find-bar\" contentEditable={false}>\n <div className=\"be-find-bar-row\">\n <button\n type=\"button\"\n className={`be-find-bar-replace-toggle${isReplaceOpen ? ' be-find-bar-replace-toggle-open' : ''}`}\n onClick={() => setIsReplaceOpen(!isReplaceOpen)}\n aria-expanded={isReplaceOpen}\n aria-label=\"Toggle replace\"\n >\n <ChevronRightIcon size={12} />\n </button>\n <input\n ref={queryInputRef}\n type=\"text\"\n className=\"be-find-bar-input\"\n placeholder=\"Find\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={handleQueryKeyDown}\n aria-label=\"Find in document\"\n />\n <span className=\"be-find-bar-count\">\n {matches.length === 0 ? '0/0' : `${currentIndex + 1}/${matches.length}`}\n </span>\n <button\n type=\"button\"\n className={`be-find-bar-toggle${caseSensitive ? ' be-find-bar-toggle-active' : ''}`}\n onClick={() => setCaseSensitive(!caseSensitive)}\n aria-pressed={caseSensitive}\n title=\"Match case\"\n aria-label=\"Match case\"\n >\n Aa\n </button>\n <button\n type=\"button\"\n className={`be-find-bar-toggle${wholeWord ? ' be-find-bar-toggle-active' : ''}`}\n onClick={() => setWholeWord(!wholeWord)}\n aria-pressed={wholeWord}\n title=\"Whole word\"\n aria-label=\"Whole word\"\n >\n [Ab]\n </button>\n <button\n type=\"button\"\n className=\"be-find-bar-nav\"\n onClick={prev}\n disabled={matches.length === 0}\n aria-label=\"Previous match\"\n >\n <ArrowUpIcon size={14} />\n </button>\n <button\n type=\"button\"\n className=\"be-find-bar-nav\"\n onClick={next}\n disabled={matches.length === 0}\n aria-label=\"Next match\"\n >\n <ArrowDownIcon size={14} />\n </button>\n <button\n type=\"button\"\n className=\"be-find-bar-close\"\n onClick={close}\n aria-label=\"Close find bar\"\n >\n <XIcon size={14} />\n </button>\n </div>\n {isReplaceOpen && (\n <div className=\"be-find-bar-row be-find-bar-replace-row\">\n <input\n type=\"text\"\n className=\"be-find-bar-input\"\n placeholder=\"Replace\"\n value={replacement}\n onChange={(event) => setReplacement(event.target.value)}\n onKeyDown={handleReplaceKeyDown}\n aria-label=\"Replace with\"\n />\n <button\n type=\"button\"\n className=\"be-find-bar-replace-btn\"\n onClick={replaceCurrent}\n disabled={matches.length === 0}\n >\n Replace\n </button>\n <button\n type=\"button\"\n className=\"be-find-bar-replace-btn\"\n onClick={replaceAll}\n disabled={matches.length === 0}\n >\n Replace All\n </button>\n </div>\n )}\n </div>\n );\n}\n","import { updateRun } from '../store/operations.js';\n\nfunction isWordChar(ch) {\n return ch != null && /[\\w]/.test(ch);\n}\n\n/** Checks that `haystack[start..start+length)` isn't part of a larger word — both neighboring characters (if any) are non-word characters. */\nfunction isWholeWordMatch(haystack, start, length) {\n const before = haystack[start - 1];\n const after = haystack[start + length];\n return !isWordChar(before) && !isWordChar(after);\n}\n\nfunction scanRun(store, blockId, runId, needle, options, results, knownRun) {\n const run = knownRun ?? store.getRun(runId);\n if (!run || run.type !== 'text' || !run.value) return;\n const haystack = options.caseSensitive ? run.value : run.value.toLowerCase();\n\n let from = 0;\n while (true) {\n const found = haystack.indexOf(needle, from);\n if (found === -1) break;\n if (!options.wholeWord || isWholeWordMatch(haystack, found, needle.length)) {\n results.push({ blockId, runId, offset: found, length: needle.length });\n }\n from = found + needle.length; // non-overlapping, matches native browser find behavior\n }\n}\n\n/**\n * Depth-first, reading-order walk of the block/run tree, matching the exact\n * dual-path convention `captureSubtree` (clipboard/serialize.js) already\n * uses: each id in `block.contentIds` is tried as a run first (duck-typed\n * via `store.getRun`, no registry lookup needed) and, if it isn't one,\n * treated as a nested block instead. `block.props.titleRunIds` (listItem/\n * toggleHeading's own text, kept separate from `contentIds` — see those\n * types' own doc comments) is scanned first, so a list item's title is\n * found before its nested children, matching reading order.\n *\n * Only text runs are searched — a non-text run (a select/date/mention chip)\n * is opaque here, same \"known limitation, documented\" scope comments.js's\n * own `anchorRunIds` accepts for its own range tracking. A match can't span\n * two runs either (e.g. across a bold/italic boundary splitting the search\n * term) — v1 scope, most search terms are shorter than a formatting run.\n */\nfunction walk(store, blockId, needle, options, results) {\n const block = store.getBlock(blockId);\n if (!block) return;\n\n for (const runId of block.props?.titleRunIds ?? []) {\n scanRun(store, blockId, runId, needle, options, results);\n }\n\n for (const childId of block.contentIds) {\n const run = store.getRun(childId);\n if (run) scanRun(store, blockId, childId, needle, options, results, run);\n else walk(store, childId, needle, options, results);\n }\n}\n\n/**\n * Finds every occurrence of `query` in the document, in reading order, as\n * `{ blockId, runId, offset, length }` — never a cross-run or non-text-run\n * match (see `walk`'s own doc comment for both limitations). `caseSensitive`\n * and `wholeWord` default to the common \"just find my text\" behavior\n * (case-insensitive, no word-boundary requirement).\n */\nexport function findMatches(store, query, { caseSensitive = false, wholeWord = false } = {}) {\n const results = [];\n if (!query) return results;\n const needle = caseSensitive ? query : query.toLowerCase();\n walk(store, store.getRootId(), needle, { caseSensitive, wholeWord }, results);\n return results;\n}\n\n/** Replaces one match's own slice of its run's text with `replacement` — one atomic undo step. */\nexport function replaceMatch(store, match, replacement) {\n const run = store.getRun(match.runId);\n if (!run) return;\n const value = run.value ?? '';\n const newValue =\n value.slice(0, match.offset) + replacement + value.slice(match.offset + match.length);\n store.applyOperation(updateRun(match.runId, { value: newValue }));\n}\n\n/**\n * Replaces every given match with `replacement`, one store write per\n * AFFECTED RUN (not per match) — several matches can land in the same run\n * (e.g. searching \"the\" in \"the theory of the thing\"), so each run's\n * matches are applied right-to-left against a single local string before\n * writing it once, keeping earlier offsets in that same run valid as later\n * ones are replaced. One atomic undo step for the whole operation via\n * `performBatch`, same convention `useClipboardHandlers`' multi-block paste\n * already uses.\n */\nexport function replaceAllMatches(store, matches, replacement) {\n const byRun = new Map();\n for (const match of matches) {\n if (!byRun.has(match.runId)) byRun.set(match.runId, []);\n byRun.get(match.runId).push(match);\n }\n\n const ops = [];\n for (const [runId, runMatches] of byRun) {\n const run = store.getRun(runId);\n if (!run) continue;\n let value = run.value ?? '';\n const rightToLeft = [...runMatches].sort((a, b) => b.offset - a.offset);\n for (const match of rightToLeft) {\n value = value.slice(0, match.offset) + replacement + value.slice(match.offset + match.length);\n }\n ops.push(updateRun(runId, { value }));\n }\n if (ops.length === 0) return;\n\n if (typeof store.performBatch === 'function') store.performBatch(ops);\n else for (const op of ops) store.applyOperation(op);\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useEditorStore } from './EditorProvider.jsx';\nimport { findMatches, replaceMatch, replaceAllMatches } from '../search/findInDocument.js';\n\nconst RECOMPUTE_DEBOUNCE_MS = 200;\n\nfunction rangeForMatch(match) {\n const el = document.querySelector(`[data-run-id=\"${match.runId}\"]`);\n const textNode = el?.firstChild;\n if (!textNode || textNode.nodeType !== 3) return null;\n const start = Math.min(match.offset, textNode.length);\n const end = Math.min(match.offset + match.length, textNode.length);\n if (start >= end) return null;\n const range = document.createRange();\n range.setStart(textNode, start);\n range.setEnd(textNode, end);\n return range;\n}\n\n/**\n * Find (and optionally replace) across the whole document — Ctrl/Cmd+F\n * opens the bar (only while `containerRef` contains focus, so a host page's\n * OWN native find elsewhere on the page is left alone; this is narrower in\n * scope than `usePersistedDocument`'s Ctrl/Cmd+S, which is deliberately\n * page-wide since \"save this document\" makes sense from anywhere on a page\n * that has one open, whereas \"find in THIS editor\" doesn't).\n *\n * Matches recompute synchronously on every query/option change (typing in\n * the find field itself), and debounced on document mutations (typing\n * elsewhere while the bar stays open) — same debounce idea as\n * `createAutoPersistence`, just tuned shorter since staleness here is more\n * user-visible than a save being a few hundred ms late.\n *\n * Highlighting uses the CSS Custom Highlight API (`CSS.highlights` +\n * `Highlight`) rather than injecting `<mark>` elements into the DOM — this\n * editor manages its own contentEditable-to-run DOM sync precisely (see\n * `domRunSync.js`), and splicing extra elements into that same tree for\n * highlighting would risk corrupting it. `CSS.highlights` paints purely at\n * the rendering layer, never touching the DOM structure at all. Older\n * Firefox (no Custom Highlight API support) degrades gracefully: search,\n * navigation, and replace all still work — the current/other matches just\n * aren't visually painted.\n */\nexport function useFindInDocument(containerRef) {\n const store = useEditorStore();\n const [isOpen, setIsOpen] = useState(false);\n const [query, setQuery] = useState('');\n const [caseSensitive, setCaseSensitive] = useState(false);\n const [wholeWord, setWholeWord] = useState(false);\n const [isReplaceOpen, setIsReplaceOpen] = useState(false);\n const [replacement, setReplacement] = useState('');\n const [matches, setMatches] = useState([]);\n const [currentIndex, setCurrentIndex] = useState(0);\n const previouslyFocusedRef = useRef(null);\n const queryInputRef = useRef(null);\n\n const recompute = useCallback(() => {\n const found = findMatches(store, query, { caseSensitive, wholeWord });\n setMatches(found);\n setCurrentIndex((prev) => (found.length === 0 ? 0 : Math.min(prev, found.length - 1)));\n }, [store, query, caseSensitive, wholeWord]);\n\n // Synchronous recompute on every query/option change -- these are\n // discrete, deliberate keystrokes/toggles in the find bar itself, not the\n // high-frequency \"typing elsewhere in the document\" case below.\n useEffect(() => {\n if (!isOpen) return;\n setCurrentIndex(0);\n recompute();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, query, caseSensitive, wholeWord]);\n\n // Debounced recompute when the document itself changes elsewhere (typing,\n // a remote collaborator's edit, undo/redo) while the bar stays open.\n useEffect(() => {\n if (!isOpen) return undefined;\n let timer = null;\n const unsubscribe = store.subscribeAll(() => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(recompute, RECOMPUTE_DEBOUNCE_MS);\n });\n return () => {\n if (timer) clearTimeout(timer);\n unsubscribe();\n };\n }, [isOpen, store, recompute]);\n\n // Paints highlights purely via CSS -- see the doc comment above for why\n // this never touches the DOM tree structure itself.\n useEffect(() => {\n if (!isOpen || typeof Highlight === 'undefined' || !CSS.highlights) return undefined;\n const otherRanges = [];\n let currentRange = null;\n matches.forEach((match, index) => {\n const range = rangeForMatch(match);\n if (!range) return;\n if (index === currentIndex) currentRange = range;\n else otherRanges.push(range);\n });\n CSS.highlights.set('be-find-match', new Highlight(...otherRanges));\n if (currentRange) {\n CSS.highlights.set('be-find-current', new Highlight(currentRange));\n const el = document.querySelector(`[data-run-id=\"${matches[currentIndex]?.runId}\"]`);\n el?.scrollIntoView({ block: 'center', behavior: 'smooth' });\n } else {\n CSS.highlights.delete('be-find-current');\n }\n return () => {\n CSS.highlights.delete('be-find-match');\n CSS.highlights.delete('be-find-current');\n };\n }, [isOpen, matches, currentIndex]);\n\n const open = useCallback(() => {\n if (isOpen) {\n queryInputRef.current?.select(); // already open: Ctrl+F again refocuses/reselects, matching native find-bar convention\n return;\n }\n previouslyFocusedRef.current = document.activeElement;\n setIsOpen(true);\n }, [isOpen]);\n\n const close = useCallback(() => {\n setIsOpen(false);\n setIsReplaceOpen(false);\n if (typeof Highlight !== 'undefined' && CSS.highlights) {\n CSS.highlights.delete('be-find-match');\n CSS.highlights.delete('be-find-current');\n }\n previouslyFocusedRef.current?.focus?.();\n previouslyFocusedRef.current = null;\n }, []);\n\n useEffect(() => {\n if (isOpen) queryInputRef.current?.focus();\n }, [isOpen]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return undefined;\n const handleKeyDown = (event) => {\n const mod = event.metaKey || event.ctrlKey;\n if (mod && event.key.toLowerCase() === 'f') {\n event.preventDefault();\n open();\n }\n };\n container.addEventListener('keydown', handleKeyDown);\n return () => container.removeEventListener('keydown', handleKeyDown);\n }, [containerRef, open]);\n\n const next = useCallback(() => {\n if (matches.length === 0) return;\n setCurrentIndex((i) => (i + 1) % matches.length);\n }, [matches.length]);\n\n const prev = useCallback(() => {\n if (matches.length === 0) return;\n setCurrentIndex((i) => (i - 1 + matches.length) % matches.length);\n }, [matches.length]);\n\n const replaceCurrent = useCallback(() => {\n const match = matches[currentIndex];\n if (!match) return;\n replaceMatch(store, match, replacement);\n // recompute happens via the subscribeAll debounce above; matches[currentIndex]\n // itself is now stale (this run's text just changed), so the effect's own\n // clamp-to-length logic picks a sane next current match.\n }, [store, matches, currentIndex, replacement]);\n\n const replaceAll = useCallback(() => {\n if (matches.length === 0) return;\n replaceAllMatches(store, matches, replacement);\n }, [store, matches, replacement]);\n\n return {\n isOpen,\n open,\n close,\n query,\n setQuery,\n caseSensitive,\n setCaseSensitive,\n wholeWord,\n setWholeWord,\n isReplaceOpen,\n setIsReplaceOpen,\n replacement,\n setReplacement,\n matches,\n currentIndex,\n next,\n prev,\n replaceCurrent,\n replaceAll,\n queryInputRef,\n };\n}\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 { useExtensionBehaviors } from './useExtensionBehaviors.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';\nimport { FindBar } from './FindBar.jsx';\nimport { useFindInDocument } from './useFindInDocument.js';\n\nfunction EditorSurface({ store, rootId, extensions, 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 const findInDocument = useFindInDocument(containerRef);\n // Before useEditorKeyboardShortcuts, so an extension keymap can claim a key.\n useExtensionBehaviors(extensions, containerRef);\n useEditorKeyboardShortcuts(containerRef);\n useBlockRangeDrag(containerRef);\n\n return (\n <div\n ref={containerRef}\n role=\"document\"\n aria-label=\"Document editor\"\n onCopy={onCopy}\n onCut={onCut}\n onPaste={onPaste}\n >\n <FindBar {...findInDocument} />\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 *\n * `uploadFile`/`maxFileSize` forward straight to `EditorProvider` too — see\n * `useFileUpload`'s own doc comment for the full contract (wiring a picked/\n * dropped file to local disk, S3, or any other cloud storage).\n *\n * Ctrl/Cmd+F, while the editor has focus, opens a built-in find/replace bar\n * (only while THIS editor has focus — a host page's own native find\n * elsewhere is left alone). See `useFindInDocument`'s own doc comment for\n * scope (single-run matches only, no cross-formatting-boundary search) and\n * a host building custom chrome can use that hook + `<FindBar>` directly.\n */\nexport function NoteloomEditor({\n editor,\n className,\n style,\n theme,\n getBlockClassName,\n onComment,\n commentAuthorId,\n showCommentsPanel,\n uploadFile,\n maxFileSize,\n children,\n}) {\n const { store, registry, inlineRegistry, extensions } = 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 uploadFile={uploadFile}\n maxFileSize={maxFileSize}\n >\n <EditorSurface\n store={store}\n rootId={rootId}\n extensions={extensions}\n onComment={onComment}\n commentAuthorId={commentAuthorId}\n />\n {showCommentsPanel && <CommentsPanel authorId={commentAuthorId} />}\n {children}\n </EditorProvider>\n );\n}\n","import { useCallback, useSyncExternalStore } from 'react';\nimport { useEditorContext } from './EditorProvider.jsx';\nimport { restoreSelectionAfterHistoryChange } from './restoreHistorySelection.js';\n\nconst STABLE_STATE = { canUndo: false, canRedo: false };\n\n/**\n * Subscribes to undo/redo availability, for wiring up toolbar buttons.\n * Returns null if the editor was created without a History instance (i.e.\n * the provider was given a plain EditorStore).\n */\nexport function useHistory() {\n const { history } = useEditorContext();\n\n const subscribe = useCallback(\n (onChange) => (history ? history.subscribeToHistory(onChange) : () => {}),\n [history],\n );\n const getSnapshot = useCallback(\n () => (history ? history.getUndoRedoSnapshot() : STABLE_STATE),\n [history],\n );\n\n const state = useSyncExternalStore(subscribe, getSnapshot);\n if (!history) return null;\n\n return {\n ...state,\n undo: () => {\n const changed = history.undo();\n if (changed) restoreSelectionAfterHistoryChange(history);\n return changed;\n },\n redo: () => {\n const changed = history.redo();\n if (changed) restoreSelectionAfterHistoryChange(history);\n return changed;\n },\n getHistoryLog: () => history.getHistoryLog(),\n };\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 } from 'react';\nimport { flushSync } from 'react-dom';\nimport { useEditorStore } from './EditorProvider.jsx';\nimport { resolveCollapsedCaret, resolveRunSelection } from './selectionResolve.js';\nimport { setCaretSync } from './focusRun.js';\nimport { updateRun } from '../store/operations.js';\n\nconst CURLY = {\n '\"': { open: '“', close: '”' },\n \"'\": { open: '‘', close: '’' },\n};\n\n// Whitespace, start-of-line, or opening punctuation before the caret means the next quote is opening; anything else (most often a letter, as in an apostrophe) means closing.\nfunction pickQuote(char, precedingChar) {\n const pair = CURLY[char];\n if (precedingChar === undefined || /[\\s([{“‘]/.test(precedingChar)) return pair.open;\n return pair.close;\n}\n\n/**\n * Optional typing behavior: a straight `\"`/`'` typed while composing text is\n * replaced with the contextually correct curly quote — one character in,\n * one character out, not a pair (that distinguishes this from\n * `useAutoPairBrackets`, which does insert pairs, deliberately for a\n * different set of characters). Typing a quote while text is selected wraps\n * the selection in an open+close pair instead — the one place this hook\n * does insert two characters, matching how quoting a selection behaves in\n * most rich text editors.\n *\n * Off inside `code` blocks — string literals need literal quote characters.\n */\nexport function useSmartQuotes(containerRef, { enabled = true } = {}) {\n const store = useEditorStore();\n\n useEffect(() => {\n if (!enabled) return undefined;\n const container = containerRef.current;\n if (!container) return undefined;\n\n function isCodeBlock(blockId) {\n return store.getBlock(blockId)?.type === 'code';\n }\n\n function handleBeforeInput(event) {\n if (event.inputType !== 'insertText' || !event.data || event.data.length !== 1) return;\n const char = event.data;\n const pair = CURLY[char];\n if (!pair) return;\n\n const selection = resolveRunSelection();\n if (selection) {\n if (isCodeBlock(selection.blockId)) return;\n const run = store.getRun(selection.runId);\n if (!run || run.type !== 'text') return;\n event.preventDefault();\n const value = run.value ?? '';\n const nextValue =\n value.slice(0, selection.startOffset) +\n pair.open +\n value.slice(selection.startOffset, selection.endOffset) +\n pair.close +\n value.slice(selection.endOffset);\n flushSync(() => store.applyOperation(updateRun(run.id, { value: nextValue })));\n setCaretSync(run.id, selection.endOffset + 2);\n return;\n }\n\n const caret = resolveCollapsedCaret();\n if (!caret || isCodeBlock(caret.blockId)) return;\n const run = store.getRun(caret.runId);\n if (!run || run.type !== 'text') return;\n event.preventDefault();\n const value = run.value ?? '';\n const quote = pickQuote(char, value[caret.offset - 1]);\n const nextValue = value.slice(0, caret.offset) + quote + value.slice(caret.offset);\n flushSync(() => store.applyOperation(updateRun(run.id, { value: nextValue })));\n setCaretSync(run.id, caret.offset + 1);\n }\n\n container.addEventListener('beforeinput', handleBeforeInput);\n return () => container.removeEventListener('beforeinput', handleBeforeInput);\n }, [containerRef, store, enabled]);\n}\n","import { useEffect } from 'react';\nimport { flushSync } from 'react-dom';\nimport { useEditorStore } from './EditorProvider.jsx';\nimport { resolveCollapsedCaret, resolveRunSelection } from './selectionResolve.js';\nimport { setCaretSync } from './focusRun.js';\nimport { updateRun } from '../store/operations.js';\n\nconst OPENERS = { '(': ')', '[': ']', '{': '}' };\nconst CLOSERS = new Set(Object.values(OPENERS));\n\n/**\n * Optional typing behavior: typing `(`, `[`, or `{` inserts the matching\n * closer and places the caret between them; typing a closer that's already\n * immediately ahead of the caret just moves past it instead of inserting a\n * duplicate; typing an opener while text is selected wraps the selection\n * instead of replacing it. Deliberately excludes quote characters — those\n * are `useSmartQuotes`' job, which substitutes one curly quote per keypress\n * rather than inserting a pair, a genuinely different behavior.\n *\n * Off inside `code` blocks (`type === 'code'`) — literal brackets there are\n * the point, not something to auto-complete around.\n *\n * v1 scope, same limits as the selection resolvers this is built on\n * (`resolveRunSelection`): wraps only a same-run selection; a selection\n * spanning multiple runs/blocks is left to the browser's default insertion\n * (event isn't preventDefault'd). Backspace-deletes-empty-pair isn't\n * implemented — deleting either character of an empty `()` leaves the\n * other one, same as not having this feature.\n */\nexport function useAutoPairBrackets(containerRef, { enabled = true } = {}) {\n const store = useEditorStore();\n\n useEffect(() => {\n if (!enabled) return undefined;\n const container = containerRef.current;\n if (!container) return undefined;\n\n function isCodeBlock(blockId) {\n return store.getBlock(blockId)?.type === 'code';\n }\n\n function handleBeforeInput(event) {\n if (event.inputType !== 'insertText' || !event.data || event.data.length !== 1) return;\n const char = event.data;\n const closer = OPENERS[char];\n\n if (closer) {\n const selection = resolveRunSelection();\n if (selection) {\n if (isCodeBlock(selection.blockId)) return;\n const run = store.getRun(selection.runId);\n if (!run || run.type !== 'text') return;\n event.preventDefault();\n const value = run.value ?? '';\n const nextValue =\n value.slice(0, selection.startOffset) +\n char +\n value.slice(selection.startOffset, selection.endOffset) +\n closer +\n value.slice(selection.endOffset);\n flushSync(() => store.applyOperation(updateRun(run.id, { value: nextValue })));\n setCaretSync(run.id, selection.endOffset + 2);\n return;\n }\n\n const caret = resolveCollapsedCaret();\n if (!caret || isCodeBlock(caret.blockId)) return;\n const run = store.getRun(caret.runId);\n if (!run || run.type !== 'text') return;\n event.preventDefault();\n const value = run.value ?? '';\n const nextValue = value.slice(0, caret.offset) + char + closer + value.slice(caret.offset);\n flushSync(() => store.applyOperation(updateRun(run.id, { value: nextValue })));\n setCaretSync(run.id, caret.offset + 1);\n return;\n }\n\n if (CLOSERS.has(char)) {\n const caret = resolveCollapsedCaret();\n if (!caret || isCodeBlock(caret.blockId)) return;\n const run = store.getRun(caret.runId);\n if (!run || run.type !== 'text') return;\n const value = run.value ?? '';\n if (value[caret.offset] === char) {\n event.preventDefault();\n setCaretSync(run.id, caret.offset + 1);\n }\n }\n }\n\n container.addEventListener('beforeinput', handleBeforeInput);\n return () => container.removeEventListener('beforeinput', handleBeforeInput);\n }, [containerRef, store, enabled]);\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 () => [\n ...(registry?.listSlashCommands() ?? []),\n ...(inlineRegistry?.listSlashCommands() ?? []),\n ],\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 {\n duplicateBlock,\n moveBlockUp,\n moveBlockDown,\n deleteBlockAndFocusSibling,\n} 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={() =>\n run(() => {\n duplicateBlock(store, blockId);\n announce('Block duplicated');\n })\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={() =>\n run(() => {\n if (moveBlockUp(store, blockId)) announce('Block moved up');\n })\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={() =>\n run(() => {\n if (moveBlockDown(store, blockId)) announce('Block moved down');\n })\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={() =>\n run(() => {\n store.applyOperation(updateBlockProps(blockId, { hidden: !isHidden }));\n announce(isHidden ? 'Block shown in preview' : 'Block hidden in preview');\n })\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\">\n {isHidden ? 'Show in preview' : 'Hide in preview'}\n </span>\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n className=\"be-mobile-picker-item be-mobile-picker-item-danger\"\n onClick={() =>\n run(() => {\n deleteBlockAndFocusSibling(store, blockId);\n announce('Block deleted');\n })\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 {\n resolveCollapsedCaret,\n resolveMultiRunSelection,\n resolveCrossBlockSelection,\n} from './selectionResolve.js';\nimport {\n getMarksSummaryOverSelection,\n getMarksSummaryOverBlockRange,\n} 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 {\n BoldIcon,\n ItalicIcon,\n UnderlineIcon,\n LinkIcon,\n PlusIcon,\n MoreHorizontalIcon,\n ChevronDownIcon,\n} 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(\n store,\n kind,\n selection,\n crossSelection,\n marks,\n );\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\n type=\"button\"\n className=\"be-mobile-bar-btn\"\n aria-label=\"Insert row below\"\n onClick={handleInsertRow}\n >\n + Row\n </button>\n <button\n type=\"button\"\n className=\"be-mobile-bar-btn\"\n aria-label=\"Insert column right\"\n onClick={handleInsertColumn}\n >\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 =\n 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 ??\n selectionState?.crossSelection?.startBlockId ??\n 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 && (\n <FormattingActions store={store} selectionState={selectionState} />\n )}\n\n {mode !== 'selection' && (\n <>\n <button\n type=\"button\"\n className=\"be-mobile-bar-btn\"\n aria-label=\"Add block\"\n onClick={openPicker}\n >\n <PlusIcon size={18} />\n </button>\n {TypeActions && actionableBlock && (\n <TypeActions store={store} blockId={actionableBlock.id} />\n )}\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\n type=\"button\"\n className=\"be-mobile-bar-btn\"\n aria-label=\"Block options\"\n onClick={openOptions}\n >\n <MoreHorizontalIcon size={18} />\n </button>\n )}\n <button\n type=\"button\"\n className=\"be-mobile-bar-btn\"\n aria-label=\"Dismiss keyboard\"\n onClick={handleDismissKeyboard}\n >\n <ChevronDownIcon size={18} />\n </button>\n </div>\n <MobileBlockPickerSheet\n isOpen={isPickerOpen}\n onClose={closePicker}\n onSelectCommand={handleSelectCommand}\n />\n <MobileBlockOptionsSheet\n isOpen={isOptionsOpen}\n onClose={closeOptions}\n store={store}\n blockId={topLevelBlock?.id}\n />\n </>\n );\n}\n","import { useCallback, useMemo, useState } from 'react';\nimport { Modal } from './Modal.jsx';\nimport { useEditorStore, useBlockRegistry, useInlineRegistry } from './EditorProvider.jsx';\nimport {\n exportDocumentJSON,\n exportDocumentHTML,\n exportDocumentText,\n exportDocumentMarkdown,\n exportDocumentWordHTML,\n} 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: 'markdown', label: 'Markdown' },\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, Markdown, or plain\n * text, without having to hand-roll the export/modal/copy plumbing\n * themselves.\n *\n * These formats aren't different features — JSON/HTML/Markdown/Text are\n * the same export pulled through the 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 five 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 * Markdown/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 if (format === 'markdown') return exportDocumentMarkdown(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 // A `data:` URL + temporary appended-then-clicked <a download>, not\n // Blob/URL.createObjectURL — same reasoning as CanvasBlock's own PNG\n // export: fewer moving parts, works in more environments, and Firefox in\n // particular doesn't reliably fire a download from a detached anchor.\n // encodeURIComponent (not btoa) is UTF-8 safe for any document content.\n const handleDownloadWord = useCallback(() => {\n const html = exportDocumentWordHTML(store, registry, inlineRegistry);\n const link = document.createElement('a');\n link.href = `data:application/msword;charset=utf-8,${encodeURIComponent(html)}`;\n link.download = 'document.doc';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n }, [store, registry, inlineRegistry]);\n\n // No PDF-writing code of its own — the browser's native \"Print\" dialog\n // (Save as PDF is a standard destination there in every major browser)\n // IS the zero-dependency path here, and the existing @media print\n // stylesheet already hides every piece of editor-only chrome (toolbars,\n // menus, the gutter, this very modal) so what prints is just the\n // document content. A host page's OWN surrounding chrome (nav bars,\n // sidebars) is outside this package's reach — same boundary as\n // everything else it doesn't own — so a host wanting a fully clean\n // printout should scope its own print CSS around the editor similarly.\n const handlePrint = useCallback(() => {\n window.print();\n }, []);\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-export-download\" onClick={handlePrint}>\n Print / Save as PDF\n </button>\n <button type=\"button\" className=\"be-export-download\" onClick={handleDownloadWord}>\n Download Word (.doc)\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, useRef } from 'react';\nimport { useRun } from '../../react/useBlock.js';\nimport { useEditorStore } from '../../react/EditorProvider.jsx';\nimport { updateRun } from '../../store/operations.js';\nimport { Select } from '../../react/Select.jsx';\nimport { consumePendingAutoOpen } from '../../react/pendingAutoOpen.js';\nimport { focusAfterChip } from '../shared/advanceAfterPick.js';\n\n/**\n * The atomic chip for one instance of a named custom select field type\n * (see createSelectFieldType) — same mounting contract as SelectInlineNode\n * (host+portal, contentEditable=false, stopPropagation on mousedown/\n * keydown so the surrounding paragraph never steals focus/keys from it).\n *\n * Unlike SelectInlineNode, `options` here comes from the field type's OWN\n * config (closed over by the factory), not from `run.data` — every chip of\n * a given field type shares the same options source, matching how a\n * table's select column works (one shared list, not one per cell). Only\n * the resolved selection is ever written back to the run.\n */\nexport function CustomSelectInlineNode({\n id,\n blockId,\n label,\n placeholder,\n variant,\n options,\n onManage,\n mention = false,\n}) {\n const store = useEditorStore();\n const run = useRun(id);\n // Consumed at most once per mount — see pendingAutoOpen.js and\n // SelectInlineNode's identical pattern (same reasoning: a plain ref\n // survives StrictMode's dev-only double-invocation without double-consuming).\n // Also doubles as \"was this chip inserted via the slash/@ menu\" for\n // handleChange below — see SelectInlineNode's identical comment.\n const autoOpenRef = useRef(null);\n if (autoOpenRef.current === null) autoOpenRef.current = consumePendingAutoOpen(id);\n\n const handleChange = useCallback(\n (selectedValue, option) => {\n store.applyOperation(\n updateRun(id, {\n data: { selectedValue, selectedLabel: option?.label ?? '', selectedColor: option?.color },\n }),\n );\n // Completes the \"insert -> auto-open -> pick\" flow — see\n // SelectInlineNode's identical comment.\n if (autoOpenRef.current) focusAfterChip(store, blockId, id);\n },\n [store, id, blockId],\n );\n\n if (!run) return null;\n const { selectedValue = '', selectedLabel = '', selectedColor } = run.data ?? {};\n\n return (\n <span\n className=\"be-inline-select\"\n onMouseDown={(event) => {\n event.preventDefault();\n event.stopPropagation();\n }}\n onKeyDown={(event) => event.stopPropagation()}\n >\n <Select\n value={selectedValue}\n selectedLabel={selectedLabel}\n selectedColor={selectedColor}\n options={options}\n onChange={handleChange}\n placeholder={placeholder}\n variant={variant}\n ariaLabel={label}\n onManageOptions={onManage}\n mention={mention}\n autoOpen={autoOpenRef.current}\n />\n </span>\n );\n}\n","import { CustomSelectInlineNode } from './CustomSelectInlineNode.jsx';\nimport { genId } from '../../utils/idGen.js';\nimport { insertInlineRunAtCursor } from '../shared/insertInlineRun.js';\nimport { SelectIcon } from '../../react/icons.jsx';\n\nfunction escapeHTML(str) {\n return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction escapeAttr(str) {\n return escapeHTML(str).replace(/\"/g, '&quot;');\n}\n\n/**\n * Builds a full InlineRegistry entry for one named \"select field type\" —\n * the mechanism behind BOTH halves of the custom-field-type system:\n *\n * - a host app calling this directly at setup time with its own `options`\n * (a plain array, OR a `(query) => Option[] | Promise<Option[]>`\n * resolver for DB/API-backed search — see Select.jsx) — never persisted,\n * the host re-registers it every load, same as registering any other\n * built-in inline type;\n * - the in-editor \"new field type\" UI (see FieldTypeEditorModal), which\n * can only ever produce STATIC options (there's no way to author a\n * fetch function through a form) and whose definition IS persisted via\n * the store's fieldTypes collection — see registerStoredFieldTypes,\n * which calls this same factory to re-register each one after load.\n *\n * Only the resolved `{ value, label }` of whatever got picked is ever\n * stored on the run (`data.selectedValue`/`data.selectedLabel`, plus\n * `data.selectedColor` for the tag variant) — never the live options list\n * itself, so a dynamic (DB-backed) type's run never embeds a stale\n * snapshot of someone else's database. This is exactly tableSelect's own\n * denormalized-label convention, applied here per-field-type instead of\n * per-table-column.\n *\n * `onManage`, if given, is threaded down to every chip as a \"Manage\n * options…\" footer entry in its popover (see Select's onManageOptions) —\n * registerStoredFieldTypes passes one that opens FieldTypeEditorModal\n * pre-filled for this type's stored id, so any chip can jump straight to\n * editing/deleting the type it belongs to. Not something a host app\n * calling this directly typically needs, since its own config lives in\n * code, not the store.\n *\n * `triggers` (default `['slash']`) decides which trigger-character menu(s)\n * this type's command shows up under — `'slash'` for useSlashMenuTrigger's\n * \"/\" menu, `'at'` for useAtMenuTrigger's \"@\" menu, or both. The command\n * object itself (label/icon/keywords/run) is identical either way — only\n * which InlineRegistry list (slashCommand vs atCommand) it's assigned to\n * differs — so opting a type into \"@\" is a one-line config change, not a\n * separate implementation. Left slash-only by default since not every\n * field type reads naturally after \"@\" (an \"Assignee\" or \"Reviewer\" type\n * does; a generic \"Priority\"/\"Status\" dropdown usually doesn't).\n */\nexport function createSelectFieldType({\n type,\n label,\n placeholder = 'Select…',\n variant = 'default',\n icon,\n options,\n onManage,\n triggers = ['slash'],\n // Defaults to true for an @-reachable type (Assignee, Reviewer, ...): a\n // picked chip renders as \"@Name\" in a fixed accent color rather than each\n // option's own tag color, matching how @mentions read everywhere else —\n // a consistent mention style, not a per-person palette. Pass\n // `mention: false` to opt an @-triggered type out of this\n // (e.g. it's reachable via \"@\" but isn't really a \"who\" mention).\n mention = triggers.includes('at'),\n}) {\n function toHTML(run) {\n const label = run.data?.selectedLabel || '';\n const text = mention && label ? `@${label}` : label;\n return `<span data-inline-type=\"${escapeAttr(type)}\" data-selected-value=\"${escapeAttr(run.data?.selectedValue ?? '')}\">${escapeHTML(text)}</span>`;\n }\n\n function toPlainText(run) {\n const label = run.data?.selectedLabel ?? '';\n return mention && label ? `@${label}` : label;\n }\n\n function fromHTML(node) {\n if (node.getAttribute?.('data-inline-type') !== type) return null;\n const text = node.textContent ?? '';\n // toHTML prepends \"@\" for a mention type — strip it back off so\n // selectedLabel stays the bare name; otherwise re-rendering the pasted\n // chip would prepend a second \"@\" on top of the one already baked into\n // the round-tripped text.\n const selectedLabel = mention && text.startsWith('@') ? text.slice(1) : text;\n return {\n id: genId(),\n type,\n value: '',\n marks: {},\n data: {\n selectedValue: node.getAttribute('data-selected-value') ?? '',\n selectedLabel,\n },\n };\n }\n\n function Component({ id, blockId }) {\n return (\n <CustomSelectInlineNode\n id={id}\n blockId={blockId}\n label={label}\n placeholder={placeholder}\n variant={variant}\n options={options}\n onManage={onManage}\n mention={mention}\n />\n );\n }\n\n const command = {\n label,\n // Falls back to the same icon the built-in generic `select` inline\n // type's own slash command uses (see inlineTypes/select/index.js) —\n // every custom field type (host-defined or created in-editor via\n // FieldTypeEditorModal, which has no way to let a user pick an icon at\n // all) gets a consistent, non-blank glyph in the \"/\"/\"@\" menu instead\n // of silently rendering with no icon at all next to every other entry\n // that has one. A host can still override it by passing its own\n // `icon` in the config, same as before.\n icon: icon ?? SelectIcon,\n keywords: [label.toLowerCase(), 'select', 'field'],\n run: (store, { blockId, runId, sliceStart, sliceEnd }) =>\n insertInlineRunAtCursor(\n store,\n { blockId, runId, sliceStart, sliceEnd },\n () => ({\n id: genId(),\n type,\n value: '',\n marks: {},\n data: { selectedValue: '', selectedLabel: '', selectedColor: undefined },\n }),\n { autoOpen: true },\n ),\n };\n\n return {\n component: Component,\n isAtomic: true,\n toHTML,\n toPlainText,\n fromHTML,\n slashCommand: triggers.includes('slash') ? command : undefined,\n atCommand: triggers.includes('at') ? command : undefined,\n };\n}\n","import { createSelectFieldType } from './createSelectFieldType.jsx';\n\n/**\n * Re-registers every persisted, user-created field type (store.getFieldTypes())\n * into the given inline registry — the rehydration step that makes a\n * previously-created custom select type usable again after a fresh page\n * load/store construction, without the host app needing to know what\n * types exist ahead of time (unlike code-defined types, which the host\n * itself registers via createSelectFieldType at setup time).\n *\n * `onManage(id)`, if given, becomes each type's \"Manage options…\" chip\n * affordance (see createSelectFieldType's own `onManage` param) — pass\n * `useFieldTypeEditor().openEdit` from React (see useRegisterFieldTypes,\n * which wraps this reactively). Safe to call directly, outside React too\n * (e.g. right after `new EditorStore(doc)`, or in tests) when no \"manage\"\n * UI is needed.\n */\nexport function registerStoredFieldTypes(store, inlineRegistry, { onManage } = {}) {\n for (const fieldType of store.getFieldTypes()) {\n inlineRegistry.register(\n fieldType.id,\n createSelectFieldType({\n type: fieldType.id,\n label: fieldType.label,\n placeholder: fieldType.placeholder,\n variant: fieldType.variant,\n options: fieldType.options ?? [],\n triggers: fieldType.mentionable ? ['slash', 'at'] : ['slash'],\n onManage: onManage ? () => onManage(fieldType.id) : undefined,\n }),\n );\n }\n}\n","import { useEffect, useRef } from 'react';\nimport { useEditorStore, useInlineRegistry, useFieldTypeEditor } from './EditorProvider.jsx';\nimport { useFieldTypes } from './useFieldTypes.js';\nimport { registerStoredFieldTypes } from '../inlineTypes/customSelect/registerStoredFieldTypes.js';\n\n/**\n * Keeps the inline registry in sync with the store's persisted field types\n * for the lifetime of a mounted editor: re-registers on every add/rename/\n * options-edit (registerStoredFieldTypes overwrites in place, cheap), and\n * unregisters any id that's disappeared from the list (a deleted type) so\n * its InlineRegistry entry doesn't linger with a \"Manage options…\" pointing\n * at a record that no longer exists. Each chip's onManage opens\n * FieldTypeEditorModal via useFieldTypeEditor().openEdit.\n *\n * Called once by FieldTypeEditorModal itself, so mounting that single\n * component is enough to get both the create/edit UI and this rehydration/\n * live-sync behavior — a host app never needs to call this directly.\n */\nexport function useRegisterFieldTypes() {\n const store = useEditorStore();\n const inlineRegistry = useInlineRegistry();\n const fieldTypes = useFieldTypes();\n const { openEdit } = useFieldTypeEditor();\n const previousIdsRef = useRef([]);\n\n useEffect(() => {\n if (!inlineRegistry) return;\n const currentIds = new Set(fieldTypes.map((f) => f.id));\n for (const id of previousIdsRef.current) {\n if (!currentIds.has(id)) inlineRegistry.unregister(id);\n }\n registerStoredFieldTypes(store, inlineRegistry, { onManage: openEdit });\n previousIdsRef.current = [...currentIds];\n }, [store, inlineRegistry, fieldTypes, openEdit]);\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { Modal } from '../../react/Modal.jsx';\nimport { useEditorStore, useFieldTypeEditor } from '../../react/EditorProvider.jsx';\nimport { addFieldType, updateFieldType, removeFieldType } from '../../store/operations.js';\nimport { genId } from '../../utils/idGen.js';\nimport { XIcon } from '../../react/icons.jsx';\nimport { pickTagColor } from '../../blocks/table/tagColors.js';\nimport { useRegisterFieldTypes } from '../../react/useRegisterFieldTypes.js';\n\n/**\n * Create/edit/delete UI for a user-created custom select field type — the\n * in-editor counterpart to a host app's code-only createSelectFieldType\n * calls. Mount this once anywhere under EditorProvider (it reads\n * useFieldTypeEditor() itself, so no props are required); wire a \"+ New\n * field type\" button to `useFieldTypeEditor().openCreate()`, and each\n * type's own chips reach the edit flow via their popover's \"Manage\n * options…\" entry (see createSelectFieldType's `onManage`).\n *\n * Reuses the same add/rename/remove-option-row shape as the table\n * column's SelectOptionsManager, plus a name field and Save/Cancel/Delete\n * — closer to ButtonEditModal's \"load a draft, commit on Save\" flow than\n * SelectOptionsManager's instant-write one, since creating a brand-new\n * type has no store record to write into until Save.\n *\n * Also owns useRegisterFieldTypes() — mounting this component is what\n * keeps the inline registry in sync with the store's fieldTypes list for\n * the whole session (rehydration + live add/edit/delete), not just what\n * renders the dialog.\n */\nexport function FieldTypeEditorModal() {\n useRegisterFieldTypes();\n const store = useEditorStore();\n const { target, close } = useFieldTypeEditor();\n const isOpen = target !== null;\n const isEditing = isOpen && target !== 'new';\n\n const [name, setName] = useState('');\n const [options, setOptions] = useState([]);\n const [draft, setDraft] = useState('');\n const [mentionable, setMentionable] = useState(false);\n\n useEffect(() => {\n if (!isOpen) return;\n if (isEditing) {\n const existing = store.getFieldType(target);\n setName(existing?.label ?? '');\n setOptions(existing?.options ?? []);\n setMentionable(!!existing?.mentionable);\n } else {\n setName('');\n setOptions([]);\n setMentionable(false);\n }\n setDraft('');\n }, [isOpen, isEditing, target, store]);\n\n const handleRename = useCallback((value, label) => {\n setOptions((rows) => rows.map((o) => (o.value === value ? { ...o, label } : o)));\n }, []);\n\n const handleRemoveOption = useCallback((value) => {\n setOptions((rows) => rows.filter((o) => o.value !== value));\n }, []);\n\n const handleAddOption = useCallback(() => {\n const label = draft.trim();\n setDraft('');\n if (!label) return;\n setOptions((rows) => [...rows, { value: genId(), label, color: pickTagColor(rows.length) }]);\n }, [draft]);\n\n const handleSave = useCallback(() => {\n const label = name.trim();\n if (!label) return;\n if (isEditing) {\n store.applyOperation(updateFieldType(target, { label, options, mentionable }));\n } else {\n store.applyOperation(\n addFieldType({\n id: genId(),\n label,\n placeholder: 'Select…',\n variant: 'tag',\n options,\n mentionable,\n }),\n );\n }\n close();\n }, [store, isEditing, target, name, options, mentionable, close]);\n\n const handleDelete = useCallback(() => {\n if (isEditing) store.applyOperation(removeFieldType(target));\n close();\n }, [store, isEditing, target, close]);\n\n return (\n <Modal isOpen={isOpen} onClose={close} title={isEditing ? 'Edit field type' : 'New field type'}>\n <label className=\"be-modal-field\">\n <span>Name</span>\n <input\n type=\"text\"\n value={name}\n onChange={(event) => setName(event.target.value)}\n placeholder=\"e.g. Priority, Status…\"\n autoFocus\n />\n </label>\n\n <div className=\"be-modal-field\">\n <span>Options</span>\n {options.map((option, i) => (\n <div key={option.value} className=\"be-table-header-menu-option-row\">\n <span\n className=\"be-table-header-menu-option-swatch\"\n style={{ background: (option.color ?? pickTagColor(i)).bg }}\n aria-hidden=\"true\"\n />\n <input\n className=\"be-table-header-menu-option-input\"\n value={option.label}\n onChange={(event) => handleRename(option.value, event.target.value)}\n aria-label={`Rename option ${option.label}`}\n />\n <button\n type=\"button\"\n className=\"be-table-header-menu-option-remove\"\n onClick={() => handleRemoveOption(option.value)}\n aria-label={`Remove option ${option.label}`}\n >\n <XIcon size={14} />\n </button>\n </div>\n ))}\n <div className=\"be-table-header-menu-option-row\">\n <input\n className=\"be-table-header-menu-option-input\"\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n placeholder=\"New option…\"\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n handleAddOption();\n }\n }}\n />\n <button\n type=\"button\"\n className=\"be-table-header-menu-option-add\"\n onClick={handleAddOption}\n aria-label=\"Add option\"\n >\n +\n </button>\n </div>\n </div>\n\n <label className=\"be-modal-field be-modal-field-checkbox\">\n <input\n type=\"checkbox\"\n checked={mentionable}\n onChange={(event) => setMentionable(event.target.checked)}\n />\n <span>Also show in @ mentions</span>\n </label>\n\n <div className=\"be-modal-actions\">\n {isEditing && (\n <button type=\"button\" className=\"be-modal-delete\" onClick={handleDelete}>\n Delete field type\n </button>\n )}\n <button type=\"button\" className=\"be-modal-cancel\" onClick={close}>\n Cancel\n </button>\n <button type=\"button\" className=\"be-modal-save\" onClick={handleSave}>\n Save\n </button>\n </div>\n </Modal>\n );\n}\n"],"names":["IDLE_MS","diffValueOffsets","oldValue","newValue","a","b","start","maxStart","endA","endB","previousValueFromInverse","inverse","_a","computeEntrySelection","entry","firstOp","lastOp","oldestInverse","previousValue","beforeOffset","afterOffset","extractAffectedBlockIds","ids","collect","op","History","store","idleMs","trackChanges","maxChangeLogSize","defaultActorId","meta","hasPatch","canUndo","canRedo","id","listener","options","ops","actorId","timestamp","inverses","value","batchKey","withinIdle","selection","useTemplates","scope","templates","setTemplates","useState","isLoaded","setIsLoaded","refresh","useCallback","listTemplates","all","t","useEffect","cancelled","TemplatePicker","onSelect","emptyLabel","jsx","template","jsxs","addPerson","name","color","genId","addPersonOp","updatePerson","patch","updatePersonOp","removePerson","removePersonOp","PEOPLE_KEY","usePeople","useEditorStore","subscribe","onStoreChange","getSnapshot","useSyncExternalStore","BlockRegistry","type","commands","createBlockRegistry","InlineRegistry","createInlineRegistry","registerBuiltInBlocks","registry","registerBlocks","paragraphBlockType","headingBlockType","listItemBlockType","TABLE_BLOCKS","LAYOUT_BLOCKS","dividerBlockType","calloutBlockType","blockquoteBlockType","codeBlockType","toggleHeadingBlockType","buttonBlockType","embedBlockType","canvasBlockType","blocksByType","tableBlockType","tableRowBlockType","tableCellBlockType","layoutBlockType","layoutColumnBlockType","registerBuiltInInlineTypes","inlineRegistry","registerInlineTypes","selectInlineType","dateInlineType","checkboxInlineType","TABLE_SELECT_INLINE_TYPES","emojiInlineType","typesByType","tableSelectInlineType","CURLY","pickQuote","char","precedingChar","pair","singleInsertChar","event","isType","ctx","blockId","smartQuotes","defineExtension","run","next","updateRun","caret","quote","OPENERS","CLOSERS","autoPairBrackets","closer","PROPS_ALLOWLIST","TITLE_RUN_TYPES","NO_TEXT_LEAF_TYPES","exportBlock","block","data","key","firstRow","resolveColumns","_b","rowId","cellId","cell","runsToHTML","runId","runIds","_c","result","childId","exportDocumentSimpleJSON","pretty","blocks","textToRuns","html","doc","domInlineToRuns","importTable","simpleBlock","parentId","blocksOut","runsOut","rowIds","rowCells","cellIds","cellHTML","runs","r","importBlock","children","props","child","isSimpleDocument","importDocumentSimpleJSON","json","rootId","topIds","defaultDoc","useEditor","history","currentUserId","extensions","customRegisterBlocks","customRegisterInlineTypes","useMemo","registerExtensions","internalDoc","rawStore","EditorStore","format","EditorTrailingSpace","minHeight","className","isPreviewMode","usePreviewMode","handleClick","root","lastId","fallbackId","ensureRootNonEmpty","focusBlockEnd","lastBlock","insertSiblingAfterAndFocus","createTextLeafBlock","copyBlockRangeToClipboard","blockIds","text","serializeBlockRange","applyOps","deleteBlockRange","removeBlock","moveBlockRangeUp","first","parent","startIndex","endIndex","precedingId","moveBlock","moveBlockRangeDown","followingId","isEntireBlockRangeHidden","setBlockRangeHidden","hidden","updateBlockProps","convertBlockRangeType","target","eligibleIds","isTurnIntoEligible","allOps","turnBlockInto","reorderBlockRangeFromStore","idSet","BlockRangeActionMenu","useBlockRegistry","useInlineRegistry","selectedBlockRange","setSelectedBlockRange","useBlockRangeSelection","rect","setRect","menuRef","useRef","turnIntoMenuRef","isOpen","position","useAutoAdjustedPosition","clear","useMenuKeyboardNav","recompute","el","handlePointerDown","_d","handleKeyDown","blockWord","n","handleCopy","announce","handleCut","count","handleDelete","handleMoveUp","handleMoveDown","isHidden","handleToggleHidden","hasEligibleBlock","handleTurnInto","createPortal","CopyIcon","ScissorsIcon","ArrowUpIcon","ArrowDownIcon","EyeIcon","EyeOffIcon","TurnIntoSubmenu","TrashIcon","APP_MIME","textToParagraphs","line","walkDomToBlocks","matchers","results","consumeList","listNode","ordered","items","li","consumeBlockquote","bqNode","paragraphs","c","p","node","matched","deserializeClipboard","dataTransfer","types","deserializeAppJSON","subtree","remapSubtreeIds","getBlockRunIds","blankRun","deleteRunRangeInBlock","startRunId","startOffset","endRunId","endOffset","fromIndex","toIndex","fromOffset","toOffset","beforeRuns","afterRuns","spanRuns","survivors","caretRunId","caretOffset","from","to","survivor","i","isFirst","isLast","prefix","prefixRun","suffixValue","suffixRun","finalRuns","blank","lastBefore","setBlockRuns","deleteOverBlockRange","crossSelection","startBlockId","endBlockId","startBlockIndex","endBlockIndex","fromBlockIndex","toBlockIndex","firstIsStart","firstRunId","firstOffset","lastRunId","lastOffset","firstBlockId","lastBlockId","firstBlock","firstRunIds","firstIdx","firstPrefixRuns","firstRun","firstPrefixSurvivor","lastRunIds","lastIdx","lastSuffixRuns","lastRun","lastSuffixSurvivor","firstSurvivors","lastSurvivors","mergeable","canMergeTypes","removedCount","wouldBeOnlyChild","survivingBlockId","merged","fallbackBlock","last","firstFinalRuns","deleteEntireDocument","replacementText","contentIds","insertBlock","isPlainFormField","closestBlockId","resolveSelectedBlockIds","startId","endId","startBlock","i1","i2","deleteCurrentSelection","same","resolveMultiRunSelection","cross","resolveCrossBlockSelection","insertTextAtCaret","useClipboardHandlers","uploadFile","maxFileSize","useFileUpload","isWholeDocumentSelected","setIsWholeDocumentSelected","useWholeDocumentSelection","onCopy","onCut","focusRunAtOffset","insertPastedFiles","files","inserts","file","resolveFileToEmbedInsert","rootIndex","subtreeBlocks","index","deleteResult","atBlockId","current","insertOps","onPaste","resolveCollapsedCaret","BOOLEAN_MARK_NAMES","VALUE_MARK_NAMES","sameMarkValue","summarizeMarks","summary","getMarksSummaryOverSelection","getMarksSummaryOverBlockRange","applyMarksPatch","marks","marksPatch","markName","applyPatchToSingleRun","nextMarks","before","middle","after","newRuns","middleRun","replaceRunSpan","applyMarksPatchOverRunSpan","rangeRunIds","rangeRuns","lastNewRunId","sliceStart","sliceEnd","computeShouldEnableForRange","textRuns","toggleMarkOnRunRange","shouldEnable","setMarksOverSelection","toggleMarkOverSelection","toggleMarkOverBlockRange","setMarksOverBlockRange","allMarked","marksPatchOrFn","markNameForDecision","sawText","blockFirstRunId","blockLastRunId","blockLastRun","blockLastOffset","isEntireBlockSelected","lastLength","isCurrentBlockEmpty","isRunsEmpty","deleteSelectedBlockAndRefocus","selectedId","setSelectedBlockId","idx","prevId","nextId","landId","landBlock","isContentlessBlock","titleRunIds","focusRunEnd","MARK_KEYS","useEditorKeyboardShortcuts","containerRef","getSelectedBlockId","useSelectedBlock","container","restoreSelectionAfterHistoryChange","sameBlockSelection","newRunId","crossBlockSelection","handleMouseDown","useExtensionBehaviors","behaviorExtensions","ext","flushSync","resolveRunSelection","offset","setCaretSync","fn","withKeymap","withBeforeInput","withPaste","onKeyDown","spec","handler","matchesKeymap","onBeforeInput","cleanups","parts","mods","hasMod","DRAG_THRESHOLD_PX","computeRange","anchorId","hoverId","anchorBlock","anchorIndex","hoverIndex","isCoarsePointer","useBlockRangeDrag","anchorIdRef","isArmedRef","startPointRef","handleMouseMove","x","y","_e","handleMouseUp","armDrag","row","hovered","ESTIMATED_MENU_HEIGHT","useActiveDescendantWiring","activeOptionId","menuId","runEl","SlashMenu","onClose","ariaLabel","activeIndex","setActiveIndex","activeItemRef","keyboardInset","useVirtualKeyboardInset","adjustedLeft","useHorizontalAutoAdjustedLeft","availableBottom","positionStyle","command","Icon","matchesQuery","query","q","k","caretOffsetInRun","rawOffset","rawTextBeforeCaret","stripEmptyRunPlaceholder","useTriggerMenu","regex","getCommands","state","setState","handleInput","anchorNode","textBeforeCaret","match","cmd","selectCommand","close","SLASH_RE","useSlashMenuTrigger","EMOJI_LIST","insertPlainTextAtCursor","EMOJI_COMMANDS","keywords","EMOJI_RE","getEmojiCommands","useEmojiMenuTrigger","AT_RE","useAtMenuTrigger","getAtCommands","useTextFormattingActions","kind","isLinkModalOpen","setIsLinkModalOpen","applyPatch","toggleBoolean","setSubSuper","opposite","enable","pendingLinkRef","openLinkModal","closeLinkModal","applyLinkPatch","pending","handleSaveLink","href","handleRemoveLink","TOUCH_INPUT_CLASS","matchesCoarsePointer","useCoarsePointer","isTouch","setIsTouch","BOOLEAN_BUTTONS","BoldIcon","ItalicIcon","UnderlineIcon","StrikethroughIcon","TEXT_COLORS","HIGHLIGHT_COLORS","FloatingToolbar","onComment","commentAuthorId","openPicker","setOpenPicker","pendingComment","setPendingComment","rootRef","pendingCommentRef","closeFloatingSelection","openCommentComposer","commentId","markOp","addCommentMarkOverRange","discardPendingComment","removeCommentMarkEverywhere","submitCommentComposer","addCommentThread","cancelCommentComposer","centerLeft","useAutoAdjustedCenteredLeft","isComposingComment","Fragment","CommentPopoverHeader","CommentComposer","title","LinkIcon","CommentIcon","LinkEditModal","useFloatingToolbarTrigger","sameBlock","crossBlock","FindBar","setQuery","caseSensitive","setCaseSensitive","wholeWord","setWholeWord","isReplaceOpen","setIsReplaceOpen","replacement","setReplacement","matches","currentIndex","prev","replaceCurrent","replaceAll","queryInputRef","handleQueryKeyDown","handleReplaceKeyDown","ChevronRightIcon","XIcon","isWordChar","ch","isWholeWordMatch","haystack","length","scanRun","needle","knownRun","found","walk","findMatches","replaceMatch","replaceAllMatches","byRun","runMatches","rightToLeft","RECOMPUTE_DEBOUNCE_MS","rangeForMatch","textNode","end","range","useFindInDocument","setIsOpen","setMatches","setCurrentIndex","previouslyFocusedRef","timer","unsubscribe","otherRanges","currentRange","open","EditorSurface","slashMenu","emojiMenu","atMenu","floatingToolbar","findInDocument","BlockChildren","NoteloomEditor","editor","style","theme","getBlockClassName","showCommentsPanel","EditorProvider","CommentsPanel","STABLE_STATE","useHistory","useEditorContext","onChange","changed","usePresence","session","presence","setPresence","useSmartQuotes","enabled","isCodeBlock","handleBeforeInput","nextValue","useAutoPairBrackets","MobileBlockPickerSheet","onSelectCommand","Modal","MobileBlockOptionsSheet","action","duplicateBlock","moveBlockUp","moveBlockDown","deleteBlockAndFocusSibling","LANGUAGE_OPTIONS","LANGUAGES","lang","useMobileBarState","isFocused","setIsFocused","mode","setMode","selectionState","setSelectionState","caretState","setCaretState","handleFocusIn","handleFocusOut","FormattingActions","TableCellActions","handleInsertRow","insertRowAfter","handleInsertColumn","table","colIndex","insertColumnAfter","CodeBlockActions","handleLanguageChange","language","Select","CalloutActions","CALLOUT_COLORS","BLOCK_TYPE_ACTIONS","findActionableAncestor","findTopLevelAncestor","MobileActionBar","isPickerOpen","setIsPickerOpen","isOptionsOpen","setIsOptionsOpen","closePicker","openOptions","closeOptions","handleSelectCommand","handleDismissKeyboard","actionableBlock","TypeActions","currentBlockId","topLevelBlock","PlusIcon","MoreHorizontalIcon","ChevronDownIcon","FORMATS","DocumentExportButton","label","setFormat","copied","setCopied","content","exportDocumentJSON","exportDocumentHTML","exportDocumentMarkdown","exportDocumentText","handleDownloadWord","exportDocumentWordHTML","link","handlePrint","CodeIcon","f","CustomSelectInlineNode","placeholder","variant","onManage","mention","useRun","autoOpenRef","consumePendingAutoOpen","handleChange","selectedValue","option","focusAfterChip","selectedLabel","selectedColor","escapeHTML","str","escapeAttr","createSelectFieldType","icon","triggers","toHTML","toPlainText","fromHTML","Component","SelectIcon","insertInlineRunAtCursor","registerStoredFieldTypes","fieldType","useRegisterFieldTypes","fieldTypes","useFieldTypes","openEdit","useFieldTypeEditor","previousIdsRef","currentIds","FieldTypeEditorModal","isEditing","setName","setOptions","draft","setDraft","mentionable","setMentionable","existing","handleRename","rows","o","handleRemoveOption","handleAddOption","pickTagColor","handleSave","updateFieldType","addFieldType","removeFieldType"],"mappings":"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"}