@notectl/core 1.7.1 → 1.7.3

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 (182) hide show
  1. package/dist/chunks/{AttrRegistry-Ci0qAvtS.mjs → AttrRegistry-D9Jx_RVb.mjs} +2 -2
  2. package/dist/chunks/{AttrRegistry-Ci0qAvtS.mjs.map → AttrRegistry-D9Jx_RVb.mjs.map} +1 -1
  3. package/dist/chunks/AttributedMarkCommands-BtLea72z.mjs +80 -0
  4. package/dist/chunks/AttributedMarkCommands-BtLea72z.mjs.map +1 -0
  5. package/dist/chunks/{CaretNavigation-qLfeL0So.mjs → CaretNavigation-7JYpIKbs.mjs} +3 -3
  6. package/dist/chunks/{CaretNavigation-qLfeL0So.mjs.map → CaretNavigation-7JYpIKbs.mjs.map} +1 -1
  7. package/dist/chunks/{ColorGrid-BBkN0AOb.mjs → ColorGrid--lBQ7jCK.mjs} +56 -55
  8. package/dist/chunks/ColorGrid--lBQ7jCK.mjs.map +1 -0
  9. package/dist/chunks/{ColorPickerPopup-D3ysvOH-.mjs → ColorPickerPopup-TpIRlXc8.mjs} +15 -15
  10. package/dist/chunks/ColorPickerPopup-TpIRlXc8.mjs.map +1 -0
  11. package/dist/chunks/{Document-DfZ1NOjs.mjs → Document-Brtw2jL1.mjs} +6 -6
  12. package/dist/chunks/Document-Brtw2jL1.mjs.map +1 -0
  13. package/dist/chunks/{MarkCommands-uybmkw9l.mjs → MarkCommands-6RUJ4L3r.mjs} +3 -3
  14. package/dist/chunks/MarkCommands-6RUJ4L3r.mjs.map +1 -0
  15. package/dist/chunks/{NodeResolver-CzLmmrph.mjs → NodeResolver-C2XYkeOi.mjs} +2 -2
  16. package/dist/chunks/{NodeResolver-CzLmmrph.mjs.map → NodeResolver-C2XYkeOi.mjs.map} +1 -1
  17. package/dist/chunks/NodeSpec-NZVvcCuH.mjs.map +1 -1
  18. package/dist/chunks/PopupPositioning-CgjgAKjp.mjs +34 -0
  19. package/dist/chunks/PopupPositioning-CgjgAKjp.mjs.map +1 -0
  20. package/dist/chunks/RangeIterator-Bh4Vl_6D.mjs +16 -0
  21. package/dist/chunks/{RangeIterator-Bye0UtbY.mjs.map → RangeIterator-Bh4Vl_6D.mjs.map} +1 -1
  22. package/dist/chunks/StyleRuntime-CP4NCwKT.mjs +235 -0
  23. package/dist/chunks/StyleRuntime-CP4NCwKT.mjs.map +1 -0
  24. package/dist/chunks/ToolbarItem-BpZggUGo.mjs.map +1 -1
  25. package/dist/chunks/{index-Bt_d4IqB.mjs → index--7pBhSF4.mjs} +74 -73
  26. package/dist/chunks/index--7pBhSF4.mjs.map +1 -0
  27. package/dist/chunks/{index-DayTn6Re.mjs → index-BXCkjDax.mjs} +78 -83
  28. package/dist/chunks/index-BXCkjDax.mjs.map +1 -0
  29. package/dist/chunks/{index-DGKQhSAl.mjs → index-BXtw5PNN.mjs} +2 -2
  30. package/dist/chunks/{index-DGKQhSAl.mjs.map → index-BXtw5PNN.mjs.map} +1 -1
  31. package/dist/chunks/{ToolbarPlugin-B7oJRzpl.mjs → index-BcDRT4K2.mjs} +110 -121
  32. package/dist/chunks/index-BcDRT4K2.mjs.map +1 -0
  33. package/dist/chunks/{index-DoCvDkfj.mjs → index-BjFBWBOC.mjs} +23 -25
  34. package/dist/chunks/index-BjFBWBOC.mjs.map +1 -0
  35. package/dist/chunks/{index-CrKz_IEn.mjs → index-C1opJocO.mjs} +2 -2
  36. package/dist/chunks/{index-CrKz_IEn.mjs.map → index-C1opJocO.mjs.map} +1 -1
  37. package/dist/chunks/{index-CfyS_pgH.mjs → index-CCyqQ0Dz.mjs} +32 -31
  38. package/dist/chunks/index-CCyqQ0Dz.mjs.map +1 -0
  39. package/dist/chunks/{index-E7OgN7hM.mjs → index-Cd3uJLP3.mjs} +2 -2
  40. package/dist/chunks/{index-E7OgN7hM.mjs.map → index-Cd3uJLP3.mjs.map} +1 -1
  41. package/dist/chunks/{index-yhz2qeeh.mjs → index-DSAuGP4n.mjs} +131 -127
  42. package/dist/chunks/index-DSAuGP4n.mjs.map +1 -0
  43. package/dist/chunks/{index-CH1r7DL-.mjs → index-DtRfqsq5.mjs} +211 -210
  44. package/dist/chunks/index-DtRfqsq5.mjs.map +1 -0
  45. package/dist/chunks/{index-CFPP456m.mjs → index-DxbQirny.mjs} +8 -8
  46. package/dist/chunks/{index-CFPP456m.mjs.map → index-DxbQirny.mjs.map} +1 -1
  47. package/dist/chunks/{index-DuRNETFv.mjs → index-ErZ5_a1o.mjs} +3 -3
  48. package/dist/chunks/{index-DuRNETFv.mjs.map → index-ErZ5_a1o.mjs.map} +1 -1
  49. package/dist/chunks/{index-Deag_lVi.mjs → index-WpbK_s_H.mjs} +29 -31
  50. package/dist/chunks/index-WpbK_s_H.mjs.map +1 -0
  51. package/dist/chunks/{index-DIvHQtE2.mjs → index-WrqH1wG8.mjs} +15 -14
  52. package/dist/chunks/index-WrqH1wG8.mjs.map +1 -0
  53. package/dist/chunks/{index-Dy6SllXW.mjs → index-fsVJLutn.mjs} +3 -3
  54. package/dist/chunks/{index-Dy6SllXW.mjs.map → index-fsVJLutn.mjs.map} +1 -1
  55. package/dist/chunks/{index-Ckzqtn5D.mjs → index-fx3KIap3.mjs} +15 -14
  56. package/dist/chunks/index-fx3KIap3.mjs.map +1 -0
  57. package/dist/chunks/{index-DmuuFS5D.mjs → index-oOJo-ywB.mjs} +4 -4
  58. package/dist/chunks/{index-DmuuFS5D.mjs.map → index-oOJo-ywB.mjs.map} +1 -1
  59. package/dist/chunks/{index-CFJFD4lF.mjs → index-toj88jtL.mjs} +19 -18
  60. package/dist/chunks/index-toj88jtL.mjs.map +1 -0
  61. package/dist/commands/AttributedMarkCommands.d.ts.map +1 -1
  62. package/dist/commands/MarkCommands.d.ts +3 -3
  63. package/dist/commands/MarkCommands.d.ts.map +1 -1
  64. package/dist/editor/CSSClassCollector.d.ts +36 -0
  65. package/dist/editor/CSSClassCollector.d.ts.map +1 -0
  66. package/dist/editor/ContentHTMLTypes.d.ts +29 -0
  67. package/dist/editor/ContentHTMLTypes.d.ts.map +1 -0
  68. package/dist/editor/ContentStyleInjector.d.ts +69 -0
  69. package/dist/editor/ContentStyleInjector.d.ts.map +1 -0
  70. package/dist/editor/DocumentParser.d.ts +9 -1
  71. package/dist/editor/DocumentParser.d.ts.map +1 -1
  72. package/dist/editor/DocumentSerializer.d.ts +6 -0
  73. package/dist/editor/DocumentSerializer.d.ts.map +1 -1
  74. package/dist/editor/EditorThemeController.d.ts +3 -0
  75. package/dist/editor/EditorThemeController.d.ts.map +1 -1
  76. package/dist/editor/MarkSerializer.d.ts +7 -0
  77. package/dist/editor/MarkSerializer.d.ts.map +1 -1
  78. package/dist/editor/NotectlEditor.d.ts +13 -3
  79. package/dist/editor/NotectlEditor.d.ts.map +1 -1
  80. package/dist/editor/PaperLayoutController.d.ts.map +1 -1
  81. package/dist/editor/styles/font-select.d.ts +1 -1
  82. package/dist/editor/styles/font-select.d.ts.map +1 -1
  83. package/dist/editor/styles/font-size-select.d.ts +1 -1
  84. package/dist/editor/styles/font-size-select.d.ts.map +1 -1
  85. package/dist/editor/styles/heading-select.d.ts +1 -1
  86. package/dist/editor/styles/heading-select.d.ts.map +1 -1
  87. package/dist/editor/styles/toolbar.d.ts +1 -1
  88. package/dist/editor/styles/toolbar.d.ts.map +1 -1
  89. package/dist/index.d.ts +10 -12
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/input/LegacyHTMLNormalizer.d.ts.map +1 -1
  92. package/dist/model/Document.d.ts +0 -4
  93. package/dist/model/Document.d.ts.map +1 -1
  94. package/dist/model/NodeSpec.d.ts +19 -2
  95. package/dist/model/NodeSpec.d.ts.map +1 -1
  96. package/dist/notectl-core.mjs +613 -477
  97. package/dist/notectl-core.mjs.map +1 -1
  98. package/dist/notectl-core.umd.js +1571 -1225
  99. package/dist/notectl-core.umd.js.map +1 -1
  100. package/dist/plugins/alignment/AlignmentPlugin.d.ts.map +1 -1
  101. package/dist/plugins/alignment.mjs +1 -1
  102. package/dist/plugins/caret-navigation.mjs +1 -1
  103. package/dist/plugins/code-block/CodeBlockNodeView.d.ts.map +1 -1
  104. package/dist/plugins/code-block/CodeBlockPlugin.d.ts +0 -1
  105. package/dist/plugins/code-block/CodeBlockPlugin.d.ts.map +1 -1
  106. package/dist/plugins/code-block/index.d.ts +2 -1
  107. package/dist/plugins/code-block/index.d.ts.map +1 -1
  108. package/dist/plugins/code-block.mjs +1 -1
  109. package/dist/plugins/font/FontPlugin.d.ts +0 -1
  110. package/dist/plugins/font/FontPlugin.d.ts.map +1 -1
  111. package/dist/plugins/font-size/FontSizePlugin.d.ts +0 -2
  112. package/dist/plugins/font-size/FontSizePlugin.d.ts.map +1 -1
  113. package/dist/plugins/font-size/FontSizePopup.d.ts +3 -1
  114. package/dist/plugins/font-size/FontSizePopup.d.ts.map +1 -1
  115. package/dist/plugins/font-size.mjs +1 -1
  116. package/dist/plugins/font.mjs +1 -1
  117. package/dist/plugins/gap-cursor.mjs +6 -6
  118. package/dist/plugins/hard-break.mjs +1 -1
  119. package/dist/plugins/heading/HeadingBlockTypePicker.d.ts.map +1 -1
  120. package/dist/plugins/heading.mjs +1 -1
  121. package/dist/plugins/highlight/HighlightPlugin.d.ts.map +1 -1
  122. package/dist/plugins/highlight.mjs +1 -1
  123. package/dist/plugins/horizontal-rule.mjs +1 -1
  124. package/dist/plugins/image/ImageNodeView.d.ts.map +1 -1
  125. package/dist/plugins/image/ImagePlugin.d.ts.map +1 -1
  126. package/dist/plugins/image.mjs +1 -1
  127. package/dist/plugins/link.mjs +1 -1
  128. package/dist/plugins/list/ListPlugin.d.ts.map +1 -1
  129. package/dist/plugins/list.mjs +1 -1
  130. package/dist/plugins/print/PrintContentPreparer.d.ts.map +1 -1
  131. package/dist/plugins/shared/ColorGrid.d.ts.map +1 -1
  132. package/dist/plugins/shared/ColorPickerPopup.d.ts +2 -1
  133. package/dist/plugins/shared/ColorPickerPopup.d.ts.map +1 -1
  134. package/dist/plugins/shared/PopupManager.d.ts +12 -2
  135. package/dist/plugins/shared/PopupManager.d.ts.map +1 -1
  136. package/dist/plugins/shared/PopupPositioning.d.ts.map +1 -1
  137. package/dist/plugins/strikethrough.mjs +1 -1
  138. package/dist/plugins/super-sub.mjs +1 -1
  139. package/dist/plugins/table/TableContextMenu.d.ts.map +1 -1
  140. package/dist/plugins/table/TableControls.d.ts.map +1 -1
  141. package/dist/plugins/table/TableControlsDOM.d.ts.map +1 -1
  142. package/dist/plugins/table/TableControlsLayout.d.ts.map +1 -1
  143. package/dist/plugins/table/TableNodeViews.d.ts.map +1 -1
  144. package/dist/plugins/table/TablePlugin.d.ts.map +1 -1
  145. package/dist/plugins/table.mjs +1 -1
  146. package/dist/plugins/text-color/TextColorPlugin.d.ts.map +1 -1
  147. package/dist/plugins/text-color.mjs +1 -1
  148. package/dist/plugins/text-formatting.mjs +1 -1
  149. package/dist/plugins/toolbar/ToolbarItem.d.ts +3 -2
  150. package/dist/plugins/toolbar/ToolbarItem.d.ts.map +1 -1
  151. package/dist/plugins/toolbar/ToolbarOverflowController.d.ts.map +1 -1
  152. package/dist/plugins/toolbar/ToolbarPopupController.d.ts +0 -3
  153. package/dist/plugins/toolbar/ToolbarPopupController.d.ts.map +1 -1
  154. package/dist/plugins/toolbar/ToolbarRenderers.d.ts.map +1 -1
  155. package/dist/plugins/toolbar/ToolbarTooltip.d.ts.map +1 -1
  156. package/dist/plugins/toolbar.mjs +2 -2
  157. package/dist/presets/PresetTypes.d.ts +1 -1
  158. package/dist/presets/PresetTypes.d.ts.map +1 -1
  159. package/dist/style/StyleRuntime.d.ts +34 -0
  160. package/dist/style/StyleRuntime.d.ts.map +1 -0
  161. package/dist/view/Reconciler.d.ts.map +1 -1
  162. package/package.json +1 -1
  163. package/dist/chunks/AttributedMarkCommands-BETuHXj8.mjs +0 -58
  164. package/dist/chunks/AttributedMarkCommands-BETuHXj8.mjs.map +0 -1
  165. package/dist/chunks/ColorGrid-BBkN0AOb.mjs.map +0 -1
  166. package/dist/chunks/ColorPickerPopup-D3ysvOH-.mjs.map +0 -1
  167. package/dist/chunks/Document-DfZ1NOjs.mjs.map +0 -1
  168. package/dist/chunks/MarkCommands-uybmkw9l.mjs.map +0 -1
  169. package/dist/chunks/PopupPositioning-Cn6L_mO2.mjs +0 -30
  170. package/dist/chunks/PopupPositioning-Cn6L_mO2.mjs.map +0 -1
  171. package/dist/chunks/RangeIterator-Bye0UtbY.mjs +0 -16
  172. package/dist/chunks/ToolbarPlugin-B7oJRzpl.mjs.map +0 -1
  173. package/dist/chunks/index-Bt_d4IqB.mjs.map +0 -1
  174. package/dist/chunks/index-CFJFD4lF.mjs.map +0 -1
  175. package/dist/chunks/index-CH1r7DL-.mjs.map +0 -1
  176. package/dist/chunks/index-CfyS_pgH.mjs.map +0 -1
  177. package/dist/chunks/index-Ckzqtn5D.mjs.map +0 -1
  178. package/dist/chunks/index-DIvHQtE2.mjs.map +0 -1
  179. package/dist/chunks/index-DayTn6Re.mjs.map +0 -1
  180. package/dist/chunks/index-Deag_lVi.mjs.map +0 -1
  181. package/dist/chunks/index-DoCvDkfj.mjs.map +0 -1
  182. package/dist/chunks/index-yhz2qeeh.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"notectl-core.mjs","sources":["../src/model/SchemaRegistry.ts","../src/model/ContentModel.ts","../src/model/BuiltinSpecs.ts","../src/state/BlockTreeOps.ts","../src/state/InlineContentOps.ts","../src/state/StepApplication.ts","../src/state/Transaction.ts","../src/state/EditorState.ts","../src/state/ReadonlyGuard.ts","../src/state/History.ts","../src/commands/DeleteCommands.ts","../src/input/KeyboardHandler.ts","../src/editor/MarkSerializer.ts","../src/input/InternalClipboard.ts","../src/input/ClipboardHandler.ts","../src/input/CompositionTracker.ts","../src/input/KeymapRegistry.ts","../src/input/InputRuleRegistry.ts","../src/input/FileHandlerRegistry.ts","../src/view/NodeViewRegistry.ts","../src/plugins/toolbar/ToolbarRegistry.ts","../src/plugins/heading/BlockTypePickerRegistry.ts","../src/view/MarkRendering.ts","../src/view/CursorWrapper.ts","../src/plugins/shared/PopupKeyboardPatterns.ts","../src/plugins/EventBus.ts","../src/plugins/PluginManager.ts","../src/plugins/print/PrintLocale.ts","../src/plugins/print/PrintContentPreparer.ts","../src/editor/PaperSize.ts","../src/plugins/print/PrintTypes.ts","../src/plugins/print/PrintPlugin.ts","../src/plugins/print/PrintServiceImpl.ts","../src/plugins/print/PrintStyleCollector.ts","../src/editor/theme/ThemeTokens.ts","../src/editor/theme/ThemeEngine.ts","../src/i18n/Locale.ts","../src/editor/DocumentSerializer.ts","../src/editor/DocumentParser.ts","../src/input/InputHandler.ts","../src/model/ContentSlice.ts","../src/commands/PasteCommand.ts","../src/model/HTMLParser.ts","../src/input/LegacyHTMLNormalizer.ts","../src/input/PasteHandler.ts","../src/view/Reconciler.ts","../src/view/EditorView.ts","../src/editor/styles/base.ts","../src/editor/styles.ts","../src/editor/styles/reduced-motion.ts","../src/editor/styles/paper.ts","../src/editor/EditorThemeController.ts","../src/editor/PaperLayoutController.ts","../src/editor/NotectlEditor.ts","../src/editor/EditorDOM.ts","../src/presets/MinimalPreset.ts","../src/presets/FullPreset.ts"],"sourcesContent":["/**\n * SchemaRegistry: central registry for node specs, mark specs,\n * and inline node specs registered by plugins.\n *\n * Model-only — no imports from input/, plugins/, or view/ layers.\n */\n\nimport type { InlineNodeSpec } from './InlineNodeSpec.js';\nimport type { MarkSpec } from './MarkSpec.js';\nimport type { NodeSpec } from './NodeSpec.js';\nimport type { ParseRule } from './ParseRule.js';\n\nexport class SchemaRegistry {\n\tprivate readonly _nodeSpecs = new Map<string, NodeSpec>();\n\tprivate readonly _markSpecs = new Map<string, MarkSpec>();\n\tprivate readonly _inlineNodeSpecs = new Map<string, InlineNodeSpec>();\n\n\t// --- NodeSpec ---\n\n\tregisterNodeSpec<T extends string>(spec: NodeSpec<T>): void {\n\t\tif (this._nodeSpecs.has(spec.type)) {\n\t\t\tthrow new Error(`NodeSpec for type \"${spec.type}\" is already registered.`);\n\t\t}\n\t\tthis._nodeSpecs.set(spec.type, spec);\n\t}\n\n\tgetNodeSpec(type: string): NodeSpec | undefined {\n\t\treturn this._nodeSpecs.get(type);\n\t}\n\n\tremoveNodeSpec(type: string): void {\n\t\tthis._nodeSpecs.delete(type);\n\t}\n\n\tgetNodeTypes(): string[] {\n\t\treturn [...this._nodeSpecs.keys()];\n\t}\n\n\t// --- MarkSpec ---\n\n\tregisterMarkSpec<T extends string>(spec: MarkSpec<T>): void {\n\t\tif (this._markSpecs.has(spec.type)) {\n\t\t\tthrow new Error(`MarkSpec for type \"${spec.type}\" is already registered.`);\n\t\t}\n\t\tthis._markSpecs.set(spec.type, spec);\n\t}\n\n\tgetMarkSpec(type: string): MarkSpec | undefined {\n\t\treturn this._markSpecs.get(type);\n\t}\n\n\tremoveMarkSpec(type: string): void {\n\t\tthis._markSpecs.delete(type);\n\t}\n\n\tgetMarkTypes(): string[] {\n\t\treturn [...this._markSpecs.keys()];\n\t}\n\n\t// --- InlineNodeSpec ---\n\n\tregisterInlineNodeSpec<T extends string>(spec: InlineNodeSpec<T>): void {\n\t\tif (this._inlineNodeSpecs.has(spec.type)) {\n\t\t\tthrow new Error(`InlineNodeSpec for type \"${spec.type}\" is already registered.`);\n\t\t}\n\t\tthis._inlineNodeSpecs.set(spec.type, spec);\n\t}\n\n\tgetInlineNodeSpec(type: string): InlineNodeSpec | undefined {\n\t\treturn this._inlineNodeSpecs.get(type);\n\t}\n\n\tremoveInlineNodeSpec(type: string): void {\n\t\tthis._inlineNodeSpecs.delete(type);\n\t}\n\n\tgetInlineNodeTypes(): string[] {\n\t\treturn [...this._inlineNodeSpecs.keys()];\n\t}\n\n\t// --- Parse Rules & Sanitize Config ---\n\n\t/** Returns all NodeSpec parseHTML rules, sorted by priority descending. */\n\tgetBlockParseRules(): readonly { readonly rule: ParseRule; readonly type: string }[] {\n\t\tconst results: { readonly rule: ParseRule; readonly type: string }[] = [];\n\t\tfor (const [type, spec] of this._nodeSpecs) {\n\t\t\tif (spec.parseHTML) {\n\t\t\t\tfor (const rule of spec.parseHTML) {\n\t\t\t\t\tresults.push({ rule, type });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results.sort((a, b) => (b.rule.priority ?? 50) - (a.rule.priority ?? 50));\n\t}\n\n\t/** Returns all InlineNodeSpec parseHTML rules, sorted by priority descending. */\n\tgetInlineParseRules(): readonly { readonly rule: ParseRule; readonly type: string }[] {\n\t\tconst results: { readonly rule: ParseRule; readonly type: string }[] = [];\n\t\tfor (const [type, spec] of this._inlineNodeSpecs) {\n\t\t\tif (spec.parseHTML) {\n\t\t\t\tfor (const rule of spec.parseHTML) {\n\t\t\t\t\tresults.push({ rule, type });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results.sort((a, b) => (b.rule.priority ?? 50) - (a.rule.priority ?? 50));\n\t}\n\n\t/** Returns all MarkSpec parseHTML rules, sorted by priority descending. */\n\tgetMarkParseRules(): readonly { readonly rule: ParseRule; readonly type: string }[] {\n\t\tconst results: { readonly rule: ParseRule; readonly type: string }[] = [];\n\t\tfor (const [type, spec] of this._markSpecs) {\n\t\t\tif (spec.parseHTML) {\n\t\t\t\tfor (const rule of spec.parseHTML) {\n\t\t\t\t\tresults.push({ rule, type });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results.sort((a, b) => (b.rule.priority ?? 50) - (a.rule.priority ?? 50));\n\t}\n\n\t/** Returns all allowed HTML tags from base defaults + all spec sanitize configs. */\n\tgetAllowedTags(): string[] {\n\t\tconst tags = new Set<string>(['p', 'br', 'div', 'span']);\n\t\tfor (const spec of this._nodeSpecs.values()) {\n\t\t\tif (spec.sanitize?.tags) {\n\t\t\t\tfor (const tag of spec.sanitize.tags) tags.add(tag);\n\t\t\t}\n\t\t}\n\t\tfor (const spec of this._inlineNodeSpecs.values()) {\n\t\t\tif (spec.sanitize?.tags) {\n\t\t\t\tfor (const tag of spec.sanitize.tags) tags.add(tag);\n\t\t\t}\n\t\t}\n\t\tfor (const spec of this._markSpecs.values()) {\n\t\t\tif (spec.sanitize?.tags) {\n\t\t\t\tfor (const tag of spec.sanitize.tags) tags.add(tag);\n\t\t\t}\n\t\t}\n\t\treturn [...tags];\n\t}\n\n\t/** Returns all allowed HTML attributes from base defaults + all spec sanitize configs. */\n\tgetAllowedAttrs(): string[] {\n\t\tconst attrs = new Set<string>(['style']);\n\t\tfor (const spec of this._nodeSpecs.values()) {\n\t\t\tif (spec.sanitize?.attrs) {\n\t\t\t\tfor (const attr of spec.sanitize.attrs) attrs.add(attr);\n\t\t\t}\n\t\t}\n\t\tfor (const spec of this._inlineNodeSpecs.values()) {\n\t\t\tif (spec.sanitize?.attrs) {\n\t\t\t\tfor (const attr of spec.sanitize.attrs) attrs.add(attr);\n\t\t\t}\n\t\t}\n\t\tfor (const spec of this._markSpecs.values()) {\n\t\t\tif (spec.sanitize?.attrs) {\n\t\t\t\tfor (const attr of spec.sanitize.attrs) attrs.add(attr);\n\t\t\t}\n\t\t}\n\t\treturn [...attrs];\n\t}\n\n\t// --- Bulk ---\n\n\tclear(): void {\n\t\tthis._nodeSpecs.clear();\n\t\tthis._markSpecs.clear();\n\t\tthis._inlineNodeSpecs.clear();\n\t}\n}\n","/**\n * Content model validation for nested document structures.\n * Validates whether a parent node type can contain given child types.\n */\n\nimport type { SchemaRegistry } from './SchemaRegistry.js';\n\n/**\n * Checks if a parent node type can contain a child node type,\n * using the content rules and group system from NodeSpec.\n */\nexport function canContain(\n\tregistry: SchemaRegistry,\n\tparentType: string,\n\tchildType: string,\n): boolean {\n\tconst parentSpec = registry.getNodeSpec(parentType);\n\tif (!parentSpec?.content) return true; // No content rule = anything allowed\n\n\tconst childSpec = registry.getNodeSpec(childType);\n\tconst childGroup = childSpec?.group;\n\n\tfor (const allowed of parentSpec.content.allow) {\n\t\tif (allowed === childType) return true;\n\t\tif (allowed === 'text') continue; // 'text' refers to TextNodes, not BlockNodes\n\t\tif (childGroup && allowed === childGroup) return true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Validates whether the given children types are valid for a parent node type.\n * Checks allow list, min/max constraints.\n */\nexport function validateContent(\n\tregistry: SchemaRegistry,\n\tparentType: string,\n\tchildTypes: readonly string[],\n): boolean {\n\tconst parentSpec = registry.getNodeSpec(parentType);\n\tif (!parentSpec?.content) return true;\n\n\tconst { min = 0, max = Number.POSITIVE_INFINITY } = parentSpec.content;\n\n\t// Check count constraints (only for block children, not text)\n\tconst blockChildTypes = childTypes.filter((t) => t !== 'text');\n\tif (blockChildTypes.length < min || blockChildTypes.length > max) return false;\n\n\t// Check each child is allowed\n\tfor (const childType of blockChildTypes) {\n\t\tif (!canContain(registry, parentType, childType)) return false;\n\t}\n\n\treturn true;\n}\n","/**\n * Registers built-in node specs on a SchemaRegistry.\n * Called during editor initialization before plugins.\n *\n * Note: Mark specs (bold, italic, underline) are registered by the\n * TextFormattingPlugin, not here. Only structural node types belong here.\n */\n\nimport { createBlockElement } from './NodeSpec.js';\nimport type { SchemaRegistry } from './SchemaRegistry.js';\n\n/** Registers the built-in paragraph NodeSpec. */\nexport function registerBuiltinSpecs(registry: SchemaRegistry): void {\n\tregistry.registerNodeSpec({\n\t\ttype: 'paragraph',\n\t\tgroup: 'block',\n\t\tcontent: { allow: ['text'] },\n\t\ttoDOM(node) {\n\t\t\treturn createBlockElement('p', node.id);\n\t\t},\n\t\ttoHTML(_node, content) {\n\t\t\treturn `<p>${content || '<br>'}</p>`;\n\t\t},\n\t\tparseHTML: [{ tag: 'p' }, { tag: 'div', priority: 10 }],\n\t\tsanitize: { tags: ['p'] },\n\t});\n}\n","/**\n * Pure functions for recursive block-tree traversal and transformation.\n * Extracted from StepApplication.ts to keep files under ~500 lines.\n */\n\nimport { type BlockNode, type ChildNode, type Document, isBlockNode } from '../model/Document.js';\n\n/** Finds a block by ID anywhere in the tree and applies a transform. */\nexport function mapBlock(\n\tdoc: Document,\n\tblockId: string,\n\tfn: (block: BlockNode) => BlockNode,\n): Document {\n\treturn {\n\t\tchildren: mapBlockInChildren(doc.children, blockId, fn) as BlockNode[],\n\t};\n}\n\n/** Recursively maps over children to find and transform a block by ID. */\nexport function mapBlockInChildren(\n\tchildren: readonly ChildNode[],\n\tblockId: string,\n\tfn: (block: BlockNode) => BlockNode,\n): ChildNode[] {\n\treturn children.map((child) => {\n\t\tif (!isBlockNode(child)) return child;\n\t\tif (child.id === blockId) return fn(child);\n\t\t// Recurse into block children\n\t\tconst mappedChildren: ChildNode[] = mapBlockInChildren(child.children, blockId, fn);\n\t\tif (mappedChildren === child.children) return child;\n\t\treturn { ...child, children: mappedChildren };\n\t});\n}\n\n/**\n * Maps a node at the given path, replacing it with the result of fn.\n * Navigates down the path immutably, creating new parent nodes as needed.\n */\nexport function mapNodeByPath(\n\tdoc: Document,\n\tpath: readonly string[],\n\tfn: (node: BlockNode) => BlockNode,\n): Document {\n\tif (path.length === 0) return doc;\n\n\tconst rootId: string | undefined = path[0];\n\tif (!rootId) return doc;\n\treturn {\n\t\tchildren: doc.children.map((child) => {\n\t\t\tif (!isBlockNode(child) || child.id !== rootId) return child;\n\t\t\tif (path.length === 1) return fn(child);\n\t\t\treturn mapNodeByPathRecursive(child, path, 1, fn);\n\t\t}),\n\t};\n}\n\n/** Recursive helper for mapNodeByPath — walks one level deeper. */\nexport function mapNodeByPathRecursive(\n\tnode: BlockNode,\n\tpath: readonly string[],\n\tdepth: number,\n\tfn: (node: BlockNode) => BlockNode,\n): BlockNode {\n\tconst targetId: string | undefined = path[depth];\n\tif (!targetId) return node;\n\tconst newChildren: ChildNode[] = node.children.map((child) => {\n\t\tif (!isBlockNode(child) || child.id !== targetId) return child;\n\t\tif (depth === path.length - 1) return fn(child);\n\t\treturn mapNodeByPathRecursive(child, path, depth + 1, fn);\n\t});\n\treturn { ...node, children: newChildren };\n}\n\n/**\n * Searches children for a level where `predicate` matches,\n * then applies `transform` at that level.\n * Recurses into nested BlockNodes if not found at the current level.\n *\n * Returns `null` if no matching level was found.\n */\nexport function findAndTransformChildren(\n\tchildren: readonly ChildNode[],\n\tpredicate: (children: readonly ChildNode[]) => boolean,\n\ttransform: (children: readonly ChildNode[]) => readonly ChildNode[],\n): readonly ChildNode[] | null {\n\tif (predicate(children)) {\n\t\treturn transform(children);\n\t}\n\n\tlet changed = false;\n\tconst newChildren: ChildNode[] = children.map((child) => {\n\t\tif (!isBlockNode(child)) return child;\n\t\tconst result: readonly ChildNode[] | null = findAndTransformChildren(\n\t\t\tchild.children,\n\t\t\tpredicate,\n\t\t\ttransform,\n\t\t);\n\t\tif (result) {\n\t\t\tchanged = true;\n\t\t\treturn { ...child, children: result };\n\t\t}\n\t\treturn child;\n\t});\n\n\treturn changed ? newChildren : null;\n}\n","/**\n * Pure functions for manipulating inline content (TextNode / InlineNode arrays).\n * Extracted from StepApplication.ts to keep files under ~500 lines.\n */\n\nimport {\n\ttype ChildNode,\n\ttype InlineNode,\n\ttype Mark,\n\ttype TextNode,\n\ttype TextSegment,\n\taddMarkToSet,\n\tcreateTextNode,\n\tisInlineNode,\n\tisTextNode,\n\tremoveMarkFromSet,\n} from '../model/Document.js';\n\n/**\n * Inserts text into mixed inline content at the given offset.\n * Handles both TextNode and InlineNode children.\n */\nexport function insertTextIntoInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n\ttext: string,\n\tmarks: readonly Mark[],\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\tlet inserted = false;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (!inserted && offset === pos) {\n\t\t\t\tresult.push(createTextNode(text, marks));\n\t\t\t\tinserted = true;\n\t\t\t}\n\t\t\tresult.push(node);\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (!inserted && offset >= pos && offset <= nodeEnd) {\n\t\t\tconst localOffset: number = offset - pos;\n\t\t\tconst before: string = node.text.slice(0, localOffset);\n\t\t\tconst after: string = node.text.slice(localOffset);\n\n\t\t\tif (before) result.push(createTextNode(before, node.marks));\n\t\t\tresult.push(createTextNode(text, marks));\n\t\t\tif (after) result.push(createTextNode(after, node.marks));\n\t\t\tinserted = true;\n\t\t} else {\n\t\t\tresult.push(node);\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\tif (!inserted) {\n\t\tresult.push(createTextNode(text, marks));\n\t}\n\n\treturn result;\n}\n\n/**\n * Inserts segments into mixed inline content at the given offset.\n */\nexport function insertSegmentsIntoInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n\tsegments: readonly TextSegment[],\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\tlet inserted = false;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (!inserted && offset === pos) {\n\t\t\t\tfor (const seg of segments) {\n\t\t\t\t\tresult.push(createTextNode(seg.text, seg.marks));\n\t\t\t\t}\n\t\t\t\tinserted = true;\n\t\t\t}\n\t\t\tresult.push(node);\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (!inserted && offset >= pos && offset <= nodeEnd) {\n\t\t\tconst localOffset: number = offset - pos;\n\t\t\tconst before: string = node.text.slice(0, localOffset);\n\t\t\tconst after: string = node.text.slice(localOffset);\n\n\t\t\tif (before) result.push(createTextNode(before, node.marks));\n\t\t\tfor (const seg of segments) {\n\t\t\t\tresult.push(createTextNode(seg.text, seg.marks));\n\t\t\t}\n\t\t\tif (after) result.push(createTextNode(after, node.marks));\n\t\t\tinserted = true;\n\t\t} else {\n\t\t\tresult.push(node);\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\tif (!inserted) {\n\t\tfor (const seg of segments) {\n\t\t\tresult.push(createTextNode(seg.text, seg.marks));\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Deletes content from mixed inline content in the given range.\n * Removes InlineNodes that fall within the range.\n */\nexport function deleteFromInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\tfrom: number,\n\tto: number,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tconst nodeEnd: number = pos + 1;\n\t\t\t// Keep if outside the delete range\n\t\t\tif (nodeEnd <= from || pos >= to) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t\tpos = nodeEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (nodeEnd <= from || pos >= to) {\n\t\t\tresult.push(node);\n\t\t} else {\n\t\t\tconst deleteFrom: number = Math.max(0, from - pos);\n\t\t\tconst deleteTo: number = Math.min(node.text.length, to - pos);\n\t\t\tconst remaining: string = node.text.slice(0, deleteFrom) + node.text.slice(deleteTo);\n\t\t\tif (remaining.length > 0) {\n\t\t\t\tresult.push(createTextNode(remaining, node.marks));\n\t\t\t}\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\treturn result;\n}\n\n/**\n * Slices mixed inline content to the given range.\n * InlineNodes are preserved as atoms (included if within range).\n */\nexport function sliceInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\tfrom: number,\n\tto: number,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tconst nodeEnd: number = pos + 1;\n\t\t\tif (nodeEnd > from && pos < to) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t\tpos = nodeEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (nodeEnd <= from || pos >= to) {\n\t\t\t// Outside the slice range\n\t\t} else {\n\t\t\tconst sliceFrom: number = Math.max(0, from - pos);\n\t\t\tconst sliceTo: number = Math.min(node.text.length, to - pos);\n\t\t\tconst text: string = node.text.slice(sliceFrom, sliceTo);\n\t\t\tif (text.length > 0) {\n\t\t\t\tresult.push(createTextNode(text, node.marks));\n\t\t\t}\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\tif (result.length === 0) {\n\t\tresult.push(createTextNode(''));\n\t}\n\n\treturn result;\n}\n\n/**\n * Applies or removes a mark from mixed inline content in the given range.\n * InlineNodes are passed through unchanged (marks only apply to text).\n */\nexport function applyMarkToInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\tfrom: number,\n\tto: number,\n\tmark: Mark,\n\tadd: boolean,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tresult.push(node);\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (nodeEnd <= from || pos >= to) {\n\t\t\tresult.push(node);\n\t\t} else if (pos >= from && nodeEnd <= to) {\n\t\t\tconst newMarks: readonly Mark[] = add\n\t\t\t\t? addMarkToSet(node.marks, mark)\n\t\t\t\t: removeMarkFromSet(node.marks, mark.type);\n\t\t\tresult.push(createTextNode(node.text, newMarks));\n\t\t} else {\n\t\t\tconst overlapStart: number = Math.max(0, from - pos);\n\t\t\tconst overlapEnd: number = Math.min(node.text.length, to - pos);\n\n\t\t\tconst beforeText: string = node.text.slice(0, overlapStart);\n\t\t\tconst insideText: string = node.text.slice(overlapStart, overlapEnd);\n\t\t\tconst afterText: string = node.text.slice(overlapEnd);\n\n\t\t\tif (beforeText) result.push(createTextNode(beforeText, node.marks));\n\t\t\tif (insideText) {\n\t\t\t\tconst newMarks: readonly Mark[] = add\n\t\t\t\t\t? addMarkToSet(node.marks, mark)\n\t\t\t\t\t: removeMarkFromSet(node.marks, mark.type);\n\t\t\t\tresult.push(createTextNode(insideText, newMarks));\n\t\t\t}\n\t\t\tif (afterText) result.push(createTextNode(afterText, node.marks));\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\treturn result;\n}\n\n/** Inserts an InlineNode at the given offset in mixed inline content. */\nexport function insertInlineNodeAtOffset(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n\tinlineNode: InlineNode,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\tlet inserted = false;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (!inserted && offset === pos) {\n\t\t\t\tresult.push(inlineNode);\n\t\t\t\tinserted = true;\n\t\t\t}\n\t\t\tresult.push(node);\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (!inserted && offset >= pos && offset <= nodeEnd) {\n\t\t\tconst localOffset: number = offset - pos;\n\t\t\tconst before: string = node.text.slice(0, localOffset);\n\t\t\tconst after: string = node.text.slice(localOffset);\n\n\t\t\tif (before) result.push(createTextNode(before, node.marks));\n\t\t\tresult.push(inlineNode);\n\t\t\tif (after) result.push(createTextNode(after, node.marks));\n\t\t\tinserted = true;\n\t\t} else {\n\t\t\tresult.push(node);\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\tif (!inserted) {\n\t\tresult.push(inlineNode);\n\t}\n\n\treturn result;\n}\n\n/** Removes the InlineNode at the given offset from mixed inline content. */\nexport function removeInlineNodeAtOffset(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (pos !== offset) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tresult.push(node);\n\t\tpos += node.text.length;\n\t}\n\n\treturn result;\n}\n\n/** Replaces the attrs of an InlineNode at the given offset. */\nexport function setInlineNodeAttrsAtOffset(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n\tattrs: Readonly<Record<string, string | number | boolean>>,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (pos === offset) {\n\t\t\t\tresult.push({ ...node, attrs });\n\t\t\t} else {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tresult.push(node);\n\t\tpos += node.text.length;\n\t}\n\n\treturn result;\n}\n\n/**\n * Replaces the inline content children of a ChildNode array,\n * preserving any BlockNode children in their original positions.\n */\nexport function replaceInlineChildren(\n\toriginal: readonly ChildNode[],\n\tnewInlineChildren: readonly (TextNode | InlineNode)[],\n): readonly ChildNode[] {\n\t// Fast path: if no block children exist, just return new inline nodes\n\tif (original.every((c) => isTextNode(c) || isInlineNode(c))) {\n\t\treturn newInlineChildren;\n\t}\n\t// Mixed: put inline nodes first, then block nodes (preserves structure)\n\tconst blockChildren: ChildNode[] = original.filter((c) => !isTextNode(c) && !isInlineNode(c));\n\treturn [...newInlineChildren, ...blockChildren];\n}\n","/**\n * Pure step-application functions operating on Document.\n * Extracted from EditorState for reuse in TransactionBuilder.\n */\n\nimport {\n\ttype BlockNode,\n\ttype ChildNode,\n\ttype Document,\n\ttype InlineNode,\n\ttype TextNode,\n\tcreateBlockNode,\n\tgetBlockLength,\n\tgetInlineChildren,\n\tisBlockNode,\n\tnormalizeInlineContent,\n} from '../model/Document.js';\nimport { findAndTransformChildren, mapBlock, mapNodeByPath } from './BlockTreeOps.js';\nimport {\n\tapplyMarkToInlineContent,\n\tdeleteFromInlineContent,\n\tinsertInlineNodeAtOffset,\n\tinsertSegmentsIntoInlineContent,\n\tinsertTextIntoInlineContent,\n\tremoveInlineNodeAtOffset,\n\treplaceInlineChildren,\n\tsetInlineNodeAttrsAtOffset,\n\tsliceInlineContent,\n} from './InlineContentOps.js';\nimport type {\n\tAddMarkStep,\n\tDeleteTextStep,\n\tInsertInlineNodeStep,\n\tInsertNodeStep,\n\tInsertTextStep,\n\tMergeBlocksStep,\n\tRemoveInlineNodeStep,\n\tRemoveMarkStep,\n\tRemoveNodeStep,\n\tSetBlockTypeStep,\n\tSetInlineNodeAttrStep,\n\tSetNodeAttrStep,\n\tSplitBlockStep,\n\tStep,\n} from './Transaction.js';\n\n/** Applies a single step to a document and returns the new document. */\nexport function applyStep(doc: Document, step: Step): Document {\n\tswitch (step.type) {\n\t\tcase 'insertText':\n\t\t\treturn applyInsertText(doc, step);\n\t\tcase 'deleteText':\n\t\t\treturn applyDeleteText(doc, step);\n\t\tcase 'splitBlock':\n\t\t\treturn applySplitBlock(doc, step);\n\t\tcase 'mergeBlocks':\n\t\t\treturn applyMergeBlocks(doc, step);\n\t\tcase 'addMark':\n\t\t\treturn applyAddMark(doc, step);\n\t\tcase 'removeMark':\n\t\t\treturn applyRemoveMark(doc, step);\n\t\tcase 'setStoredMarks':\n\t\t\treturn doc; // Stored marks are handled at the state level, not document\n\t\tcase 'setBlockType':\n\t\t\treturn applySetBlockType(doc, step);\n\t\tcase 'insertNode':\n\t\t\treturn applyInsertNode(doc, step);\n\t\tcase 'removeNode':\n\t\t\treturn applyRemoveNode(doc, step);\n\t\tcase 'setNodeAttr':\n\t\t\treturn applySetNodeAttr(doc, step);\n\t\tcase 'insertInlineNode':\n\t\t\treturn applyInsertInlineNode(doc, step);\n\t\tcase 'removeInlineNode':\n\t\t\treturn applyRemoveInlineNode(doc, step);\n\t\tcase 'setInlineNodeAttr':\n\t\t\treturn applySetInlineNodeAttr(doc, step);\n\t}\n}\n\nfunction applyInsertText(doc: Document, step: InsertTextStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = step.segments\n\t\t\t? insertSegmentsIntoInlineContent(inlineChildren, step.offset, step.segments)\n\t\t\t: insertTextIntoInlineContent(inlineChildren, step.offset, step.text, step.marks);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applyDeleteText(doc: Document, step: DeleteTextStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = deleteFromInlineContent(\n\t\t\tinlineChildren,\n\t\t\tstep.from,\n\t\t\tstep.to,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applySplitBlock(doc: Document, step: SplitBlockStep): Document {\n\tconst splitAtLevel = (children: readonly ChildNode[]): readonly ChildNode[] => {\n\t\tconst blockIndex: number = children.findIndex((c) => isBlockNode(c) && c.id === step.blockId);\n\t\tif (blockIndex === -1) return children;\n\n\t\tconst block: BlockNode = children[blockIndex] as BlockNode;\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst len: number = getBlockLength(block);\n\t\tconst nodesBeforeSplit: (TextNode | InlineNode)[] = sliceInlineContent(\n\t\t\tinlineChildren,\n\t\t\t0,\n\t\t\tstep.offset,\n\t\t);\n\t\tconst nodesAfterSplit: (TextNode | InlineNode)[] = sliceInlineContent(\n\t\t\tinlineChildren,\n\t\t\tstep.offset,\n\t\t\tlen,\n\t\t);\n\n\t\tconst updatedBlock: BlockNode = {\n\t\t\t...block,\n\t\t\tchildren: normalizeInlineContent(nodesBeforeSplit),\n\t\t};\n\t\tconst newBlock: BlockNode = createBlockNode(\n\t\t\tblock.type,\n\t\t\tnormalizeInlineContent(nodesAfterSplit),\n\t\t\tstep.newBlockId,\n\t\t\tblock.attrs,\n\t\t);\n\n\t\tconst result: ChildNode[] = [...children];\n\t\tresult.splice(blockIndex, 1, updatedBlock, newBlock);\n\t\treturn result;\n\t};\n\n\tconst hasTarget = (children: readonly ChildNode[]): boolean =>\n\t\tchildren.some((c) => isBlockNode(c) && c.id === step.blockId);\n\n\tconst transformed: readonly ChildNode[] | null = findAndTransformChildren(\n\t\tdoc.children,\n\t\thasTarget,\n\t\tsplitAtLevel,\n\t);\n\treturn transformed ? { children: transformed as BlockNode[] } : doc;\n}\n\nfunction applyMergeBlocks(doc: Document, step: MergeBlocksStep): Document {\n\tconst mergeAtLevel = (children: readonly ChildNode[]): readonly ChildNode[] => {\n\t\tconst targetIdx: number = children.findIndex(\n\t\t\t(c) => isBlockNode(c) && c.id === step.targetBlockId,\n\t\t);\n\t\tconst sourceIdx: number = children.findIndex(\n\t\t\t(c) => isBlockNode(c) && c.id === step.sourceBlockId,\n\t\t);\n\t\tif (targetIdx === -1 || sourceIdx === -1) return children;\n\n\t\tconst target: BlockNode = children[targetIdx] as BlockNode;\n\t\tconst source: BlockNode = children[sourceIdx] as BlockNode;\n\t\tconst targetInline: readonly (TextNode | InlineNode)[] = getInlineChildren(target);\n\t\tconst sourceInline: readonly (TextNode | InlineNode)[] = getInlineChildren(source);\n\t\tconst mergedChildren: readonly (TextNode | InlineNode)[] = normalizeInlineContent([\n\t\t\t...targetInline,\n\t\t\t...sourceInline,\n\t\t]);\n\t\tconst mergedBlock: BlockNode = { ...target, children: mergedChildren };\n\n\t\tconst filtered: ChildNode[] = children.filter(\n\t\t\t(c) => !isBlockNode(c) || c.id !== step.sourceBlockId,\n\t\t);\n\t\treturn filtered.map((c) => (isBlockNode(c) && c.id === step.targetBlockId ? mergedBlock : c));\n\t};\n\n\tconst hasTargetAndSource = (children: readonly ChildNode[]): boolean =>\n\t\tchildren.some((c) => isBlockNode(c) && c.id === step.targetBlockId) &&\n\t\tchildren.some((c) => isBlockNode(c) && c.id === step.sourceBlockId);\n\n\tconst transformed: readonly ChildNode[] | null = findAndTransformChildren(\n\t\tdoc.children,\n\t\thasTargetAndSource,\n\t\tmergeAtLevel,\n\t);\n\treturn transformed ? { children: transformed as BlockNode[] } : doc;\n}\n\nfunction applyAddMark(doc: Document, step: AddMarkStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = applyMarkToInlineContent(\n\t\t\tinlineChildren,\n\t\t\tstep.from,\n\t\t\tstep.to,\n\t\t\tstep.mark,\n\t\t\ttrue,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applyRemoveMark(doc: Document, step: RemoveMarkStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = applyMarkToInlineContent(\n\t\t\tinlineChildren,\n\t\t\tstep.from,\n\t\t\tstep.to,\n\t\t\tstep.mark,\n\t\t\tfalse,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\n// --- InlineNode Step Application ---\n\nfunction applyInsertInlineNode(doc: Document, step: InsertInlineNodeStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = insertInlineNodeAtOffset(\n\t\t\tinlineChildren,\n\t\t\tstep.offset,\n\t\t\tstep.node,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applyRemoveInlineNode(doc: Document, step: RemoveInlineNodeStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = removeInlineNodeAtOffset(\n\t\t\tinlineChildren,\n\t\t\tstep.offset,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applySetInlineNodeAttr(doc: Document, step: SetInlineNodeAttrStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = setInlineNodeAttrsAtOffset(\n\t\t\tinlineChildren,\n\t\t\tstep.offset,\n\t\t\tstep.attrs,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, newChildren),\n\t\t};\n\t});\n}\n\nfunction applySetBlockType(doc: Document, step: SetBlockTypeStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => ({\n\t\t...block,\n\t\ttype: step.nodeType,\n\t\t...(step.attrs ? { attrs: step.attrs } : { attrs: undefined }),\n\t}));\n}\n\n// --- Structural Step Application ---\n\nfunction applyInsertNode(doc: Document, step: InsertNodeStep): Document {\n\tif (step.parentPath.length === 0) {\n\t\t// Insert at document root\n\t\tconst newChildren: BlockNode[] = [...doc.children];\n\t\tnewChildren.splice(step.index, 0, step.node);\n\t\treturn { children: newChildren };\n\t}\n\n\treturn mapNodeByPath(doc, step.parentPath, (parent) => {\n\t\tconst newChildren: ChildNode[] = [...parent.children];\n\t\tnewChildren.splice(step.index, 0, step.node);\n\t\treturn { ...parent, children: newChildren };\n\t});\n}\n\nfunction applyRemoveNode(doc: Document, step: RemoveNodeStep): Document {\n\tif (step.parentPath.length === 0) {\n\t\t// Remove from document root\n\t\tconst newChildren: BlockNode[] = [...doc.children];\n\t\tnewChildren.splice(step.index, 1);\n\t\treturn { children: newChildren };\n\t}\n\n\treturn mapNodeByPath(doc, step.parentPath, (parent) => {\n\t\tconst newChildren: ChildNode[] = [...parent.children];\n\t\tnewChildren.splice(step.index, 1);\n\t\treturn { ...parent, children: newChildren };\n\t});\n}\n\nfunction applySetNodeAttr(doc: Document, step: SetNodeAttrStep): Document {\n\tconst nodeId: string | undefined = step.path[step.path.length - 1];\n\tif (!nodeId) return doc;\n\n\treturn mapBlock(doc, nodeId, (block) => ({\n\t\t...block,\n\t\tattrs: step.attrs,\n\t}));\n}\n","/**\n * Transaction system for the Notectl editor.\n * Transactions describe atomic, invertible state changes.\n */\n\nimport type {\n\tBlockAttrs,\n\tBlockNode,\n\tDocument,\n\tInlineNode,\n\tMark,\n\tTextSegment,\n} from '../model/Document.js';\nimport {\n\tgetBlockLength,\n\tgetBlockMarksAtOffset,\n\tgetBlockSegmentsInRange,\n\tgetBlockText,\n\tgetContentAtOffset,\n\tgetInlineChildren,\n\tisBlockNode,\n\tisInlineNode,\n} from '../model/Document.js';\nimport { findNode, resolveNodeByPath } from '../model/NodeResolver.js';\nimport type { EditorSelection } from '../model/Selection.js';\nimport { createNodeSelection } from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport { applyStep } from './StepApplication.js';\n\n// --- Step Types ---\n\nexport interface InsertTextStep {\n\treadonly type: 'insertText';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly text: string;\n\treadonly marks: readonly Mark[];\n\treadonly segments?: readonly TextSegment[];\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface DeleteTextStep {\n\treadonly type: 'deleteText';\n\treadonly blockId: BlockId;\n\treadonly from: number;\n\treadonly to: number;\n\treadonly deletedText: string;\n\treadonly deletedMarks: readonly Mark[];\n\treadonly deletedSegments: readonly TextSegment[];\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface SplitBlockStep {\n\treadonly type: 'splitBlock';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly newBlockId: BlockId;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface MergeBlocksStep {\n\treadonly type: 'mergeBlocks';\n\treadonly targetBlockId: BlockId;\n\treadonly sourceBlockId: BlockId;\n\treadonly targetLengthBefore: number;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface AddMarkStep {\n\treadonly type: 'addMark';\n\treadonly blockId: BlockId;\n\treadonly from: number;\n\treadonly to: number;\n\treadonly mark: Mark;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface RemoveMarkStep {\n\treadonly type: 'removeMark';\n\treadonly blockId: BlockId;\n\treadonly from: number;\n\treadonly to: number;\n\treadonly mark: Mark;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface SetStoredMarksStep {\n\treadonly type: 'setStoredMarks';\n\treadonly marks: readonly Mark[] | null;\n\treadonly previousMarks: readonly Mark[] | null;\n}\n\nexport interface SetBlockTypeStep {\n\treadonly type: 'setBlockType';\n\treadonly blockId: BlockId;\n\treadonly nodeType: NodeTypeName;\n\treadonly attrs?: BlockAttrs;\n\treadonly previousNodeType: NodeTypeName;\n\treadonly previousAttrs?: BlockAttrs;\n\treadonly path?: readonly BlockId[];\n}\n\n// --- Structural Steps (for nested documents) ---\n\nexport interface InsertNodeStep {\n\treadonly type: 'insertNode';\n\treadonly parentPath: readonly BlockId[];\n\treadonly index: number;\n\treadonly node: BlockNode;\n}\n\nexport interface RemoveNodeStep {\n\treadonly type: 'removeNode';\n\treadonly parentPath: readonly BlockId[];\n\treadonly index: number;\n\treadonly removedNode: BlockNode;\n}\n\nexport interface SetNodeAttrStep {\n\treadonly type: 'setNodeAttr';\n\treadonly path: readonly BlockId[];\n\treadonly attrs: BlockAttrs | undefined;\n\treadonly previousAttrs?: BlockAttrs;\n}\n\n// --- InlineNode Steps ---\n\nexport interface InsertInlineNodeStep {\n\treadonly type: 'insertInlineNode';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly node: InlineNode;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface RemoveInlineNodeStep {\n\treadonly type: 'removeInlineNode';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly removedNode: InlineNode;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface SetInlineNodeAttrStep {\n\treadonly type: 'setInlineNodeAttr';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly attrs: Readonly<Record<string, string | number | boolean>>;\n\treadonly previousAttrs: Readonly<Record<string, string | number | boolean>>;\n\treadonly path?: readonly BlockId[];\n}\n\nexport type Step =\n\t| InsertTextStep\n\t| DeleteTextStep\n\t| SplitBlockStep\n\t| MergeBlocksStep\n\t| AddMarkStep\n\t| RemoveMarkStep\n\t| SetStoredMarksStep\n\t| SetBlockTypeStep\n\t| InsertNodeStep\n\t| RemoveNodeStep\n\t| SetNodeAttrStep\n\t| InsertInlineNodeStep\n\t| RemoveInlineNodeStep\n\t| SetInlineNodeAttrStep;\n\n// --- Transaction ---\n\nexport type TransactionOrigin = 'input' | 'paste' | 'command' | 'history' | 'api';\n\nexport interface TransactionMetadata {\n\treadonly origin: TransactionOrigin;\n\treadonly timestamp: number;\n\treadonly historyDirection?: 'undo' | 'redo';\n\treadonly readonlyAllowed?: boolean;\n}\n\nexport interface Transaction {\n\treadonly steps: readonly Step[];\n\treadonly selectionBefore: EditorSelection;\n\treadonly selectionAfter: EditorSelection;\n\treadonly storedMarksAfter: readonly Mark[] | null;\n\treadonly metadata: TransactionMetadata;\n}\n\n// --- Step Inversion ---\n\n/** Inverts a single step for undo. */\nexport function invertStep(step: Step): Step {\n\tswitch (step.type) {\n\t\tcase 'insertText':\n\t\t\treturn {\n\t\t\t\ttype: 'deleteText',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\tfrom: step.offset,\n\t\t\t\tto: step.offset + step.text.length,\n\t\t\t\tdeletedText: step.text,\n\t\t\t\tdeletedMarks: step.marks,\n\t\t\t\tdeletedSegments: step.segments ?? [{ text: step.text, marks: [...step.marks] }],\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'deleteText':\n\t\t\treturn {\n\t\t\t\ttype: 'insertText',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\toffset: step.from,\n\t\t\t\ttext: step.deletedText,\n\t\t\t\tmarks: step.deletedMarks,\n\t\t\t\tsegments: step.deletedSegments,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'splitBlock':\n\t\t\treturn {\n\t\t\t\ttype: 'mergeBlocks',\n\t\t\t\ttargetBlockId: step.blockId,\n\t\t\t\tsourceBlockId: step.newBlockId,\n\t\t\t\ttargetLengthBefore: step.offset,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'mergeBlocks':\n\t\t\treturn {\n\t\t\t\ttype: 'splitBlock',\n\t\t\t\tblockId: step.targetBlockId,\n\t\t\t\toffset: step.targetLengthBefore,\n\t\t\t\tnewBlockId: step.sourceBlockId,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'addMark':\n\t\t\treturn {\n\t\t\t\ttype: 'removeMark',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\tfrom: step.from,\n\t\t\t\tto: step.to,\n\t\t\t\tmark: step.mark,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'removeMark':\n\t\t\treturn {\n\t\t\t\ttype: 'addMark',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\tfrom: step.from,\n\t\t\t\tto: step.to,\n\t\t\t\tmark: step.mark,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'setStoredMarks':\n\t\t\treturn {\n\t\t\t\ttype: 'setStoredMarks',\n\t\t\t\tmarks: step.previousMarks,\n\t\t\t\tpreviousMarks: step.marks,\n\t\t\t};\n\t\tcase 'setBlockType':\n\t\t\treturn {\n\t\t\t\ttype: 'setBlockType',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\tnodeType: step.previousNodeType,\n\t\t\t\tattrs: step.previousAttrs,\n\t\t\t\tpreviousNodeType: step.nodeType,\n\t\t\t\tpreviousAttrs: step.attrs,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'insertNode':\n\t\t\treturn {\n\t\t\t\ttype: 'removeNode',\n\t\t\t\tparentPath: step.parentPath,\n\t\t\t\tindex: step.index,\n\t\t\t\tremovedNode: step.node,\n\t\t\t};\n\t\tcase 'removeNode':\n\t\t\treturn {\n\t\t\t\ttype: 'insertNode',\n\t\t\t\tparentPath: step.parentPath,\n\t\t\t\tindex: step.index,\n\t\t\t\tnode: step.removedNode,\n\t\t\t};\n\t\tcase 'setNodeAttr':\n\t\t\treturn {\n\t\t\t\ttype: 'setNodeAttr',\n\t\t\t\tpath: step.path,\n\t\t\t\tattrs: step.previousAttrs,\n\t\t\t\tpreviousAttrs: step.attrs,\n\t\t\t};\n\t\tcase 'insertInlineNode':\n\t\t\treturn {\n\t\t\t\ttype: 'removeInlineNode',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\toffset: step.offset,\n\t\t\t\tremovedNode: step.node,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'removeInlineNode':\n\t\t\treturn {\n\t\t\t\ttype: 'insertInlineNode',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\toffset: step.offset,\n\t\t\t\tnode: step.removedNode,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'setInlineNodeAttr':\n\t\t\treturn {\n\t\t\t\ttype: 'setInlineNodeAttr',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\toffset: step.offset,\n\t\t\t\tattrs: step.previousAttrs,\n\t\t\t\tpreviousAttrs: step.attrs,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t}\n}\n\n/** Inverts an entire transaction (reverses step order and swaps selections). */\nexport function invertTransaction(tr: Transaction): Transaction {\n\treturn {\n\t\tsteps: tr.steps.map(invertStep).reverse(),\n\t\tselectionBefore: tr.selectionAfter,\n\t\tselectionAfter: tr.selectionBefore,\n\t\tstoredMarksAfter: null,\n\t\tmetadata: {\n\t\t\torigin: 'history',\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t};\n}\n\n// --- TransactionBuilder ---\n\n/** Fluent API for building transactions. */\nexport class TransactionBuilder {\n\tprivate readonly steps: Step[] = [];\n\tprivate selection: EditorSelection;\n\tprivate storedMarks: readonly Mark[] | null;\n\tprivate readonly selectionBefore: EditorSelection;\n\tprivate readonly origin: TransactionOrigin;\n\tprivate workingDoc: Document | null;\n\tprivate _readonlyAllowed = false;\n\n\tconstructor(\n\t\tcurrentSelection: EditorSelection,\n\t\tcurrentStoredMarks: readonly Mark[] | null,\n\t\torigin: TransactionOrigin = 'api',\n\t\tdoc?: Document,\n\t) {\n\t\tthis.selection = currentSelection;\n\t\tthis.selectionBefore = currentSelection;\n\t\tthis.storedMarks = currentStoredMarks;\n\t\tthis.origin = origin;\n\t\tthis.workingDoc = doc ?? null;\n\t}\n\n\t/** Adds an insert-text step. Updates workingDoc if available. */\n\tinsertText(\n\t\tblockId: BlockId,\n\t\toffset: number,\n\t\ttext: string,\n\t\tmarks: readonly Mark[],\n\t\tsegments?: readonly TextSegment[],\n\t): this {\n\t\tconst step: InsertTextStep = {\n\t\t\ttype: 'insertText',\n\t\t\tblockId,\n\t\t\toffset,\n\t\t\ttext,\n\t\t\tmarks,\n\t\t\t...(segments ? { segments } : {}),\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Adds a delete-text step with explicit data. Updates workingDoc if available. */\n\tdeleteText(\n\t\tblockId: BlockId,\n\t\tfrom: number,\n\t\tto: number,\n\t\tdeletedText: string,\n\t\tdeletedMarks: readonly Mark[],\n\t\tdeletedSegments?: readonly TextSegment[],\n\t): this {\n\t\tlet segments: readonly TextSegment[];\n\t\tif (deletedSegments) {\n\t\t\tsegments = deletedSegments;\n\t\t} else if (this.workingDoc) {\n\t\t\tconst block = findNode(this.workingDoc, blockId);\n\t\t\tsegments = block\n\t\t\t\t? getBlockSegmentsInRange(block, from, to)\n\t\t\t\t: [{ text: deletedText, marks: [...deletedMarks] }];\n\t\t} else {\n\t\t\tsegments = [{ text: deletedText, marks: [...deletedMarks] }];\n\t\t}\n\t\tconst step: DeleteTextStep = {\n\t\t\ttype: 'deleteText',\n\t\t\tblockId,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\tdeletedText,\n\t\t\tdeletedMarks,\n\t\t\tdeletedSegments: segments,\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Deletes text at the given range, auto-deriving deletedText, deletedMarks, and deletedSegments\n\t * from the working document. Requires a document to be provided at construction.\n\t */\n\tdeleteTextAt(blockId: BlockId, from: number, to: number): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'deleteTextAt requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\n\t\tconst block = findNode(doc, blockId);\n\t\tif (!block) {\n\t\t\tthrow new Error(`Block \"${blockId}\" not found in working document.`);\n\t\t}\n\n\t\tconst text = getBlockText(block);\n\t\tconst deletedText = text.slice(from, to);\n\t\tconst deletedMarks = getBlockMarksAtOffset(block, from);\n\t\tconst deletedSegments = getBlockSegmentsInRange(block, from, to);\n\n\t\treturn this.deleteText(blockId, from, to, deletedText, deletedMarks, deletedSegments);\n\t}\n\n\t/** Adds a split-block step. Updates workingDoc if available. */\n\tsplitBlock(blockId: BlockId, offset: number, newBlockId: BlockId): this {\n\t\tconst step: SplitBlockStep = { type: 'splitBlock', blockId, offset, newBlockId };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Adds a merge-blocks step with explicit targetLengthBefore. Updates workingDoc if available. */\n\tmergeBlocks(targetBlockId: BlockId, sourceBlockId: BlockId, targetLengthBefore: number): this {\n\t\tconst step: MergeBlocksStep = {\n\t\t\ttype: 'mergeBlocks',\n\t\t\ttargetBlockId,\n\t\t\tsourceBlockId,\n\t\t\ttargetLengthBefore,\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Merges two blocks, auto-deriving targetLengthBefore from the working document.\n\t * Requires a document to be provided at construction.\n\t */\n\tmergeBlocksAt(targetBlockId: BlockId, sourceBlockId: BlockId): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'mergeBlocksAt requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\n\t\tconst targetBlock = findNode(doc, targetBlockId);\n\t\tif (!targetBlock) {\n\t\t\tthrow new Error(`Target block \"${targetBlockId}\" not found in working document.`);\n\t\t}\n\n\t\tconst targetLengthBefore = getBlockLength(targetBlock);\n\t\treturn this.mergeBlocks(targetBlockId, sourceBlockId, targetLengthBefore);\n\t}\n\n\t/** Adds an add-mark step. Updates workingDoc if available. */\n\taddMark(blockId: BlockId, from: number, to: number, mark: Mark): this {\n\t\tconst step: AddMarkStep = { type: 'addMark', blockId, from, to, mark };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Adds a remove-mark step. Updates workingDoc if available. */\n\tremoveMark(blockId: BlockId, from: number, to: number, mark: Mark): this {\n\t\tconst step: RemoveMarkStep = { type: 'removeMark', blockId, from, to, mark };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Adds a set-block-type step, changing a block's node type and optionally its attrs. */\n\tsetBlockType(blockId: BlockId, nodeType: NodeTypeName, attrs?: BlockAttrs): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'setBlockType requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\t\tconst block = findNode(doc, blockId);\n\t\tif (!block) {\n\t\t\tthrow new Error(`Block \"${blockId}\" not found in working document.`);\n\t\t}\n\t\tconst step: SetBlockTypeStep = {\n\t\t\ttype: 'setBlockType',\n\t\t\tblockId,\n\t\t\tnodeType,\n\t\t\t...(attrs ? { attrs } : {}),\n\t\t\tpreviousNodeType: block.type,\n\t\t\t...(block.attrs ? { previousAttrs: block.attrs } : {}),\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Inserts a node as a child of the parent at the given path and index. */\n\tinsertNode(parentPath: readonly BlockId[], index: number, node: BlockNode): this {\n\t\tconst step: InsertNodeStep = { type: 'insertNode', parentPath, index, node };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Removes a node at the given index from the parent at the given path. */\n\tremoveNode(parentPath: readonly BlockId[], index: number): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'removeNode requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\n\t\tconst removedNode = resolveRemovedNode(doc, parentPath, index);\n\t\tif (!removedNode) {\n\t\t\tthrow new Error(\n\t\t\t\t`Node at index ${index} not found under parent path [${parentPath.join(', ')}].`,\n\t\t\t);\n\t\t}\n\n\t\tconst step: RemoveNodeStep = { type: 'removeNode', parentPath, index, removedNode };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Sets attributes on a node at the given path. */\n\tsetNodeAttr(path: readonly BlockId[], attrs: BlockAttrs): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'setNodeAttr requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\n\t\tconst node = resolveNodeByPath(doc, path);\n\t\tif (!node) {\n\t\t\tthrow new Error(`Node not found at path [${path.join(', ')}].`);\n\t\t}\n\n\t\tconst step: SetNodeAttrStep = {\n\t\t\ttype: 'setNodeAttr',\n\t\t\tpath,\n\t\t\tattrs,\n\t\t\t...(node.attrs ? { previousAttrs: node.attrs } : {}),\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Inserts an InlineNode at the given offset within a block. */\n\tinsertInlineNode(blockId: BlockId, offset: number, node: InlineNode): this {\n\t\tconst step: InsertInlineNodeStep = {\n\t\t\ttype: 'insertInlineNode',\n\t\t\tblockId,\n\t\t\toffset,\n\t\t\tnode,\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Removes an InlineNode at the given offset, deriving removedNode from workingDoc. */\n\tremoveInlineNode(blockId: BlockId, offset: number): this {\n\t\tconst doc: Document | null = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'removeInlineNode requires a document. Use state.transaction() or provide doc.',\n\t\t\t);\n\t\t}\n\t\tconst block: BlockNode | undefined = findNode(doc, blockId);\n\t\tif (!block) {\n\t\t\tthrow new Error(`Block \"${blockId}\" not found in working document.`);\n\t\t}\n\t\tconst content = getContentAtOffset(block, offset);\n\t\tif (!content || content.kind !== 'inline') {\n\t\t\tthrow new Error(`No InlineNode at offset ${offset} in block \"${blockId}\".`);\n\t\t}\n\t\tconst step: RemoveInlineNodeStep = {\n\t\t\ttype: 'removeInlineNode',\n\t\t\tblockId,\n\t\t\toffset,\n\t\t\tremovedNode: content.node,\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Sets attributes on an InlineNode at the given offset. */\n\tsetInlineNodeAttr(\n\t\tblockId: BlockId,\n\t\toffset: number,\n\t\tattrs: Readonly<Record<string, string | number | boolean>>,\n\t): this {\n\t\tconst doc: Document | null = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'setInlineNodeAttr requires a document. Use state.transaction() or provide doc.',\n\t\t\t);\n\t\t}\n\t\tconst block: BlockNode | undefined = findNode(doc, blockId);\n\t\tif (!block) {\n\t\t\tthrow new Error(`Block \"${blockId}\" not found in working document.`);\n\t\t}\n\t\tconst inlineChildren = getInlineChildren(block);\n\t\tlet pos = 0;\n\t\tfor (const child of inlineChildren) {\n\t\t\tif (isInlineNode(child) && pos === offset) {\n\t\t\t\tconst step: SetInlineNodeAttrStep = {\n\t\t\t\t\ttype: 'setInlineNodeAttr',\n\t\t\t\t\tblockId,\n\t\t\t\t\toffset,\n\t\t\t\t\tattrs,\n\t\t\t\t\tpreviousAttrs: child.attrs,\n\t\t\t\t};\n\t\t\t\tthis.steps.push(step);\n\t\t\t\tthis.advanceDoc(step);\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tpos += isInlineNode(child) ? 1 : child.text.length;\n\t\t}\n\t\tthrow new Error(`No InlineNode at offset ${offset} in block \"${blockId}\".`);\n\t}\n\n\t/** Marks this transaction as allowed in readonly mode. */\n\treadonlyAllowed(): this {\n\t\tthis._readonlyAllowed = true;\n\t\treturn this;\n\t}\n\n\t/** Sets the selection for the resulting state. */\n\tsetSelection(selection: EditorSelection): this {\n\t\tthis.selection = selection;\n\t\treturn this;\n\t}\n\n\t/** Sets a NodeSelection for the resulting state. */\n\tsetNodeSelection(nodeId: BlockId, path: readonly BlockId[]): this {\n\t\tthis.selection = createNodeSelection(nodeId, path);\n\t\treturn this;\n\t}\n\n\t/** Sets stored marks for the resulting state. */\n\tsetStoredMarks(marks: readonly Mark[] | null, previousMarks: readonly Mark[] | null): this {\n\t\tthis.steps.push({ type: 'setStoredMarks', marks, previousMarks });\n\t\tthis.storedMarks = marks;\n\t\treturn this;\n\t}\n\n\t/** Builds the final transaction. */\n\tbuild(): Transaction {\n\t\treturn {\n\t\t\tsteps: [...this.steps],\n\t\t\tselectionBefore: this.selectionBefore,\n\t\t\tselectionAfter: this.selection,\n\t\t\tstoredMarksAfter: this.storedMarks,\n\t\t\tmetadata: {\n\t\t\t\torigin: this.origin,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t...(this._readonlyAllowed ? { readonlyAllowed: true } : {}),\n\t\t\t},\n\t\t};\n\t}\n\n\t/** Advances the working document by applying a step. */\n\tprivate advanceDoc(step: Step): void {\n\t\tif (this.workingDoc) {\n\t\t\tthis.workingDoc = applyStep(this.workingDoc, step);\n\t\t}\n\t}\n}\n\n/** Helper to create a TransactionBuilder with input origin. */\nexport function inputTransaction(\n\tselection: EditorSelection,\n\tstoredMarks: readonly Mark[] | null,\n): TransactionBuilder {\n\treturn new TransactionBuilder(selection, storedMarks, 'input');\n}\n\n/** Helper to create a TransactionBuilder with command origin. */\nexport function commandTransaction(\n\tselection: EditorSelection,\n\tstoredMarks: readonly Mark[] | null,\n): TransactionBuilder {\n\treturn new TransactionBuilder(selection, storedMarks, 'command');\n}\n\n/** Resolves the block node to be removed from a parent path and index. */\nfunction resolveRemovedNode(\n\tdoc: Document,\n\tparentPath: readonly BlockId[],\n\tindex: number,\n): BlockNode | undefined {\n\tif (parentPath.length === 0) {\n\t\tconst child = doc.children[index];\n\t\treturn child && isBlockNode(child) ? child : undefined;\n\t}\n\tconst parent = resolveNodeByPath(doc, parentPath);\n\tif (!parent) return undefined;\n\tconst child = parent.children[index];\n\treturn child && isBlockNode(child) ? child : undefined;\n}\n","/**\n * Immutable editor state container.\n * Every mutation produces a new EditorState instance.\n */\n\nimport {\n\ttype BlockNode,\n\ttype Document,\n\ttype Mark,\n\tcreateDocument,\n\tgetBlockLength,\n\tisBlockNode,\n\tisLeafBlock,\n} from '../model/Document.js';\nimport { findNode, findNodePath } from '../model/NodeResolver.js';\nimport type { Schema } from '../model/Schema.js';\nimport { defaultSchema } from '../model/Schema.js';\nimport type { EditorSelection, Position } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreatePosition,\n\tcreateSelection,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport { type BlockId, blockId } from '../model/TypeBrands.js';\nimport { applyStep } from './StepApplication.js';\nimport type { Transaction } from './Transaction.js';\nimport { TransactionBuilder } from './Transaction.js';\n\nexport class EditorState {\n\treadonly doc: Document;\n\treadonly selection: EditorSelection;\n\treadonly storedMarks: readonly Mark[] | null;\n\treadonly schema: Schema;\n\n\tprivate _blockMap: Map<BlockId, BlockNode> | null = null;\n\tprivate _blockOrder: readonly BlockId[] | null = null;\n\n\tprivate constructor(\n\t\tdoc: Document,\n\t\tselection: EditorSelection,\n\t\tstoredMarks: readonly Mark[] | null,\n\t\tschema: Schema,\n\t) {\n\t\tthis.doc = doc;\n\t\tthis.selection = selection;\n\t\tthis.storedMarks = storedMarks;\n\t\tthis.schema = schema;\n\t}\n\n\t/** Creates a new EditorState with default document. */\n\tstatic create(options?: {\n\t\tdoc?: Document;\n\t\tselection?: EditorSelection;\n\t\tschema?: Schema;\n\t}): EditorState {\n\t\tconst schema = options?.schema ?? defaultSchema();\n\t\tconst doc = options?.doc ?? createDocument();\n\t\tconst firstBlock = doc.children[0];\n\t\tconst selection =\n\t\t\toptions?.selection ?? createCollapsedSelection(firstBlock ? firstBlock.id : blockId(''), 0);\n\n\t\treturn new EditorState(doc, selection, null, schema);\n\t}\n\n\t/** Creates a TransactionBuilder from this state. */\n\ttransaction(\n\t\torigin: 'input' | 'paste' | 'command' | 'history' | 'api' = 'api',\n\t): TransactionBuilder {\n\t\treturn new TransactionBuilder(this.selection, this.storedMarks, origin, this.doc);\n\t}\n\n\t/** Applies a transaction and returns a new EditorState. */\n\tapply(tr: Transaction): EditorState {\n\t\tlet doc = this.doc;\n\n\t\tfor (const step of tr.steps) {\n\t\t\tdoc = applyStep(doc, step);\n\t\t}\n\n\t\tconst selection = validateSelection(doc, tr.selectionAfter);\n\t\treturn new EditorState(doc, selection, tr.storedMarksAfter, this.schema);\n\t}\n\n\t/** Finds a block by its ID anywhere in the tree. Uses a lazy-built Map for O(1) lookup. */\n\tgetBlock(blockId: BlockId): BlockNode | undefined {\n\t\tthis._blockMap ??= buildBlockMap(this.doc);\n\t\treturn this._blockMap.get(blockId);\n\t}\n\n\t/** Returns leaf-block IDs in depth-first order. Cached after first call. */\n\tgetBlockOrder(): readonly BlockId[] {\n\t\tthis._blockOrder ??= buildBlockOrder(this.doc);\n\t\treturn this._blockOrder;\n\t}\n\n\t/** Returns the path (array of block IDs) to a node. */\n\tgetNodePath(nodeId: BlockId): BlockId[] | undefined {\n\t\treturn findNodePath(this.doc, nodeId) as BlockId[] | undefined;\n\t}\n\n\t/** Returns the parent BlockNode of a node, or undefined for top-level blocks. */\n\tgetParent(nodeId: BlockId): BlockNode | undefined {\n\t\tconst path = findNodePath(this.doc, nodeId);\n\t\tif (!path || path.length <= 1) return undefined;\n\t\tconst parentId = path[path.length - 2] as BlockId | undefined;\n\t\tif (!parentId) return undefined;\n\t\treturn findNode(this.doc, parentId);\n\t}\n\n\t/** Serializes the state to JSON. */\n\ttoJSON(): { readonly doc: Document; readonly selection: EditorSelection } {\n\t\treturn {\n\t\t\tdoc: this.doc,\n\t\t\tselection: this.selection,\n\t\t};\n\t}\n\n\t/** Deserializes a state from JSON. */\n\tstatic fromJSON(\n\t\tjson: { doc: Document; selection: EditorSelection },\n\t\tschema?: Schema,\n\t): EditorState {\n\t\treturn new EditorState(json.doc, json.selection, null, schema ?? defaultSchema());\n\t}\n}\n\n/** Validates a position against the document, clamping or falling back as needed. */\nfunction validatePosition(doc: Document, pos: Position): Position {\n\tconst block = findNode(doc, pos.blockId);\n\tif (block) {\n\t\tconst length = getBlockLength(block);\n\t\tif (pos.offset > length) {\n\t\t\treturn createPosition(pos.blockId, length, pos.path);\n\t\t}\n\t\treturn pos;\n\t}\n\n\tconst firstBlock = doc.children[0];\n\tif (!firstBlock) return pos;\n\treturn createPosition(firstBlock.id, 0);\n}\n\n/** Validates a selection against the document, ensuring blockIds exist and offsets are in bounds. */\nfunction validateSelection(doc: Document, sel: EditorSelection): EditorSelection {\n\tif (isNodeSelection(sel)) {\n\t\tconst node = findNode(doc, sel.nodeId);\n\t\tif (node) return sel;\n\t\t// Node was deleted — fall back to first leaf block\n\t\treturn fallbackSelection(doc, sel);\n\t}\n\tif (isGapCursor(sel)) {\n\t\tconst node = findNode(doc, sel.blockId);\n\t\tif (node) return sel;\n\t\t// Referenced block was deleted — fall back to first leaf block\n\t\treturn fallbackSelection(doc, sel);\n\t}\n\tconst anchor = validatePosition(doc, sel.anchor);\n\tconst head = validatePosition(doc, sel.head);\n\tif (anchor === sel.anchor && head === sel.head) return sel;\n\treturn createSelection(anchor, head);\n}\n\n/** Returns a collapsed selection on the first leaf block, or the original selection if no blocks exist. */\nfunction fallbackSelection(doc: Document, sel: EditorSelection): EditorSelection {\n\tconst leaf = findFirstLeafBlock(doc.children);\n\tif (!leaf) return sel;\n\treturn createCollapsedSelection(leaf.id, 0);\n}\n\n/** Descends into the first child of each container block to find the first leaf block. */\nfunction findFirstLeafBlock(\n\tchildren: readonly import('../model/Document.js').ChildNode[],\n): BlockNode | null {\n\tfor (const child of children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tif (isLeafBlock(child)) return child;\n\t\tconst nested: BlockNode | null = findFirstLeafBlock(child.children);\n\t\tif (nested) return nested;\n\t}\n\treturn null;\n}\n\n/** Recursively builds a Map of blockId → BlockNode for all nodes in the tree. */\nfunction buildBlockMap(doc: Document): Map<BlockId, BlockNode> {\n\tconst map = new Map<BlockId, BlockNode>();\n\tfunction walk(blocks: readonly import('../model/Document.js').ChildNode[]): void {\n\t\tfor (const child of blocks) {\n\t\t\tif (isBlockNode(child)) {\n\t\t\t\tmap.set(child.id, child);\n\t\t\t\twalk(child.children);\n\t\t\t}\n\t\t}\n\t}\n\twalk(doc.children);\n\treturn map;\n}\n\n/** Returns leaf-block IDs in depth-first order. */\nfunction buildBlockOrder(doc: Document): BlockId[] {\n\tconst order: BlockId[] = [];\n\tfunction walk(blocks: readonly import('../model/Document.js').ChildNode[]): void {\n\t\tfor (const child of blocks) {\n\t\t\tif (isBlockNode(child)) {\n\t\t\t\tif (isLeafBlock(child)) {\n\t\t\t\t\torder.push(child.id);\n\t\t\t\t} else {\n\t\t\t\t\twalk(child.children);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\twalk(doc.children);\n\treturn order;\n}\n","/**\n * Pure guard functions for readonly mode enforcement.\n * Used by the central dispatch guard to determine whether a transaction\n * should be allowed in readonly mode.\n */\n\nimport type { Transaction } from './Transaction.js';\n\n/** Returns true if the transaction contains no document-mutating steps. */\nexport function isSelectionOnlyTransaction(tr: Transaction): boolean {\n\tfor (const step of tr.steps) {\n\t\tif (step.type !== 'setStoredMarks') return false;\n\t}\n\treturn true;\n}\n\n/** Returns true if the transaction is allowed to proceed in readonly mode. */\nexport function isAllowedInReadonly(tr: Transaction): boolean {\n\tif (tr.metadata.readonlyAllowed) return true;\n\treturn isSelectionOnlyTransaction(tr);\n}\n","/**\n * History manager for undo/redo with transaction grouping.\n */\n\nimport type { EditorState } from './EditorState.js';\nimport type { Step, Transaction } from './Transaction.js';\nimport { invertTransaction } from './Transaction.js';\n\nexport interface HistoryResult {\n\treadonly state: EditorState;\n\treadonly transaction: Transaction;\n}\n\ninterface HistoryGroup {\n\treadonly transactions: readonly Transaction[];\n\treadonly timestamp: number;\n}\n\nconst DEFAULT_GROUP_TIMEOUT_MS = 500;\nconst DEFAULT_MAX_DEPTH = 100;\n\nexport class HistoryManager {\n\tprivate undoStack: HistoryGroup[] = [];\n\tprivate redoStack: HistoryGroup[] = [];\n\tprivate readonly groupTimeoutMs: number;\n\tprivate readonly maxDepth: number;\n\tprivate lastOrigin: string | null = null;\n\n\tconstructor(options?: { groupTimeoutMs?: number; maxDepth?: number }) {\n\t\tthis.groupTimeoutMs = options?.groupTimeoutMs ?? DEFAULT_GROUP_TIMEOUT_MS;\n\t\tthis.maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH;\n\t}\n\n\t/**\n\t * Pushes a transaction onto the undo stack.\n\t * Groups consecutive input transactions within the timeout window.\n\t */\n\tpush(tr: Transaction): void {\n\t\t// History and redo transactions are not pushed\n\t\tif (tr.metadata.origin === 'history') return;\n\n\t\t// Skip transactions with no document changes (selection/stored marks only)\n\t\t// but break grouping so the next insertion starts a new undo group.\n\t\tif (!tr.steps.some((step: Step) => step.type !== 'setStoredMarks')) {\n\t\t\tthis.lastOrigin = null;\n\t\t\treturn;\n\t\t}\n\n\t\tconst now = tr.metadata.timestamp;\n\t\tconst lastGroup = this.undoStack[this.undoStack.length - 1];\n\t\tconst shouldGroup =\n\t\t\tlastGroup &&\n\t\t\ttr.metadata.origin === 'input' &&\n\t\t\tthis.lastOrigin === 'input' &&\n\t\t\tnow - lastGroup.timestamp < this.groupTimeoutMs &&\n\t\t\tthis.isSameInputType(lastGroup.transactions, tr);\n\n\t\tif (shouldGroup && lastGroup) {\n\t\t\t// Merge into existing group\n\t\t\tthis.undoStack[this.undoStack.length - 1] = {\n\t\t\t\ttransactions: [...lastGroup.transactions, tr],\n\t\t\t\ttimestamp: now,\n\t\t\t};\n\t\t} else {\n\t\t\t// Start new group\n\t\t\tthis.undoStack.push({\n\t\t\t\ttransactions: [tr],\n\t\t\t\ttimestamp: now,\n\t\t\t});\n\t\t}\n\n\t\tthis.lastOrigin = tr.metadata.origin;\n\n\t\t// Clear redo stack on new input\n\t\tthis.redoStack = [];\n\n\t\t// Enforce max depth\n\t\twhile (this.undoStack.length > this.maxDepth) {\n\t\t\tthis.undoStack.shift();\n\t\t}\n\t}\n\n\t/** Undoes the last group and returns the new state with transaction, or null if nothing to undo. */\n\tundo(state: EditorState): HistoryResult | null {\n\t\tconst group = this.undoStack.pop();\n\t\tif (!group) return null;\n\n\t\tlet currentState = state;\n\t\tconst allSteps: Step[] = [];\n\n\t\t// Apply inverted transactions in reverse order\n\t\tfor (let i = group.transactions.length - 1; i >= 0; i--) {\n\t\t\tconst tr = group.transactions[i];\n\t\t\tif (!tr) continue;\n\t\t\tconst inverted = invertTransaction(tr);\n\t\t\tcurrentState = currentState.apply(inverted);\n\t\t\tallSteps.push(...inverted.steps);\n\t\t}\n\n\t\t// Push to redo stack\n\t\tthis.redoStack.push({\n\t\t\ttransactions: group.transactions,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\n\t\tthis.lastOrigin = null;\n\n\t\tconst transaction: Transaction = {\n\t\t\tsteps: allSteps,\n\t\t\tselectionBefore: state.selection,\n\t\t\tselectionAfter: currentState.selection,\n\t\t\tstoredMarksAfter: currentState.storedMarks,\n\t\t\tmetadata: { origin: 'history', timestamp: Date.now(), historyDirection: 'undo' },\n\t\t};\n\n\t\treturn { state: currentState, transaction };\n\t}\n\n\t/** Redoes the last undone group and returns the new state with transaction, or null if nothing to redo. */\n\tredo(state: EditorState): HistoryResult | null {\n\t\tconst group = this.redoStack.pop();\n\t\tif (!group) return null;\n\n\t\tlet currentState = state;\n\t\tconst allSteps: Step[] = [];\n\n\t\t// Re-apply transactions in original order\n\t\tfor (const tr of group.transactions) {\n\t\t\tcurrentState = currentState.apply(tr);\n\t\t\tallSteps.push(...tr.steps);\n\t\t}\n\n\t\t// Push back to undo stack\n\t\tthis.undoStack.push({\n\t\t\ttransactions: group.transactions,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\n\t\tthis.lastOrigin = null;\n\n\t\tconst transaction: Transaction = {\n\t\t\tsteps: allSteps,\n\t\t\tselectionBefore: state.selection,\n\t\t\tselectionAfter: currentState.selection,\n\t\t\tstoredMarksAfter: currentState.storedMarks,\n\t\t\tmetadata: { origin: 'history', timestamp: Date.now(), historyDirection: 'redo' },\n\t\t};\n\n\t\treturn { state: currentState, transaction };\n\t}\n\n\t/** Returns true if there are entries to undo. */\n\tcanUndo(): boolean {\n\t\treturn this.undoStack.length > 0;\n\t}\n\n\t/** Returns true if there are entries to redo. */\n\tcanRedo(): boolean {\n\t\treturn this.redoStack.length > 0;\n\t}\n\n\t/** Clears all history. */\n\tclear(): void {\n\t\tthis.undoStack = [];\n\t\tthis.redoStack = [];\n\t\tthis.lastOrigin = null;\n\t}\n\n\t/**\n\t * Checks if consecutive transactions are of the same \"type\" for grouping.\n\t * Groups text insertion together, deletion together, but not mixed.\n\t */\n\tprivate isSameInputType(existing: readonly Transaction[], incoming: Transaction): boolean {\n\t\tconst lastTr = existing[existing.length - 1];\n\t\tif (!lastTr) return false;\n\n\t\tconst lastStepType = lastTr.steps[0]?.type;\n\t\tconst incomingStepType = incoming.steps[0]?.type;\n\n\t\t// Group same step types (insertText with insertText, deleteText with deleteText)\n\t\treturn lastStepType === incomingStepType;\n\t}\n}\n","/**\n * Delete commands: character, word, and soft-line deletion in both directions.\n */\n\nimport { type BlockNode, getBlockLength } from '../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { deleteSelectionCommand, mergeBlockBackward, mergeBlockForward } from './Commands.js';\nimport { deleteNodeSelection } from './NodeSelectionCommands.js';\nimport { findWordBoundaryBackward, findWordBoundaryForward } from './WordBoundary.js';\n\ninterface DeleteConfig {\n\treadonly merge: (state: EditorState) => Transaction | null;\n\treadonly range: (block: BlockNode, offset: number) => readonly [number, number] | null;\n}\n\nfunction deleteInDirection(state: EditorState, config: DeleteConfig): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) return deleteNodeSelection(state, sel);\n\tif (isGapCursor(sel)) return null;\n\tif (!isCollapsed(sel)) return deleteSelectionCommand(state);\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\n\tconst range = config.range(block, sel.anchor.offset);\n\tif (!range) return config.merge(state);\n\n\tconst [from, to] = range;\n\treturn state\n\t\t.transaction('input')\n\t\t.deleteTextAt(block.id, from, to)\n\t\t.setSelection(createCollapsedSelection(block.id, from))\n\t\t.build();\n}\n\n/** Handles backspace key. */\nexport function deleteBackward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockBackward,\n\t\trange: (_block, offset) => (offset > 0 ? [offset - 1, offset] : null),\n\t});\n}\n\n/** Handles delete key. */\nexport function deleteForward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockForward,\n\t\trange: (block, offset) => {\n\t\t\tconst len = getBlockLength(block);\n\t\t\treturn offset < len ? [offset, offset + 1] : null;\n\t\t},\n\t});\n}\n\n/** Handles Ctrl+Backspace: delete word backward. */\nexport function deleteWordBackward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockBackward,\n\t\trange: (block, offset) =>\n\t\t\toffset > 0 ? [findWordBoundaryBackward(block, offset), offset] : null,\n\t});\n}\n\n/** Handles Ctrl+Delete: delete word forward. */\nexport function deleteWordForward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockForward,\n\t\trange: (block, offset) => {\n\t\t\tconst len = getBlockLength(block);\n\t\t\treturn offset < len ? [offset, findWordBoundaryForward(block, offset)] : null;\n\t\t},\n\t});\n}\n\n/** Handles Cmd+Backspace: delete to start of line/block. */\nexport function deleteSoftLineBackward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockBackward,\n\t\trange: (_block, offset) => (offset > 0 ? [0, offset] : null),\n\t});\n}\n\n/** Handles Cmd+Delete: delete to end of line/block. */\nexport function deleteSoftLineForward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockForward,\n\t\trange: (block, offset) => {\n\t\t\tconst len = getBlockLength(block);\n\t\t\treturn offset < len ? [offset, len] : null;\n\t\t},\n\t});\n}\n","/**\n * Keyboard handler: intercepts keydown events for shortcuts.\n * Checks plugin-registered keymaps first, then falls back to built-in\n * structural shortcuts (undo, redo, select all) and NodeSelection navigation.\n *\n * Mark-specific shortcuts (Mod-B, Mod-I, Mod-U) are registered by\n * their respective plugins via keymaps, not hardcoded here.\n */\n\nimport {\n\tdeleteBackwardAtGap,\n\tdeleteForwardAtGap,\n\tdeleteNodeSelection,\n\tinsertTextCommand,\n\tnavigateArrowIntoVoid,\n\tselectAll,\n\tsplitBlockCommand,\n} from '../commands/Commands.js';\nimport { isGapCursor, isNodeSelection, selectionsEqual } from '../model/Selection.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { navigateFromGapCursor } from '../view/CaretNavigation.js';\nimport type { CompositionTracker } from './CompositionTracker.js';\nimport type { DispatchFn, GetStateFn, RedoFn, UndoFn } from './InputHandler.js';\nimport type { KeymapRegistry } from './KeymapRegistry.js';\n\nexport interface KeyboardHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tundo: UndoFn;\n\tredo: RedoFn;\n\tkeymapRegistry?: KeymapRegistry;\n\tisReadOnly?: () => boolean;\n\tcompositionTracker?: CompositionTracker;\n}\n\nexport class KeyboardHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly undo: UndoFn;\n\tprivate readonly redo: RedoFn;\n\tprivate readonly keymapRegistry?: KeymapRegistry;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate readonly compositionTracker?: CompositionTracker;\n\tprivate readonly handleKeydown: (e: KeyboardEvent) => void;\n\n\tconstructor(\n\t\tprivate readonly element: HTMLElement,\n\t\toptions: KeyboardHandlerOptions,\n\t) {\n\t\tthis.getState = options.getState;\n\t\tthis.dispatch = options.dispatch;\n\t\tthis.undo = options.undo;\n\t\tthis.redo = options.redo;\n\t\tthis.keymapRegistry = options.keymapRegistry;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\t\tthis.compositionTracker = options.compositionTracker;\n\n\t\tthis.handleKeydown = this.onKeydown.bind(this);\n\t\telement.addEventListener('keydown', this.handleKeydown);\n\t}\n\n\tprivate onKeydown(e: KeyboardEvent): void {\n\t\t// During IME composition, let the browser handle all keys\n\t\tif (this.compositionTracker?.isComposing) return;\n\n\t\t// Handle NodeSelection keys before plugin keymaps\n\t\tif (this.handleNodeSelectionKeys(e)) return;\n\n\t\t// Handle GapCursor keys (typing, Enter, Backspace, Delete)\n\t\tif (this.handleGapCursorKeys(e)) return;\n\n\t\t// Readonly mode: allow navigation keymaps + escape, block everything else\n\t\tif (this.isReadOnly()) {\n\t\t\tif (this.keymapRegistry) {\n\t\t\t\tconst descriptor: string = normalizeKeyDescriptor(e);\n\t\t\t\tconst navKeymaps = this.keymapRegistry.getKeymapsByPriority().navigation;\n\t\t\t\tfor (let i = navKeymaps.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst handler = navKeymaps[i]?.[descriptor];\n\t\t\t\t\tif (handler?.()) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.handleEscape(e)) return;\n\t\t\treturn;\n\t\t}\n\n\t\t// Normal mode: try plugin keymaps in priority order (context > navigation > default).\n\t\t// Within each priority, iterate in reverse so later-registered keymaps take precedence.\n\t\tif (this.keymapRegistry) {\n\t\t\tconst descriptor: string = normalizeKeyDescriptor(e);\n\t\t\tconst groups = this.keymapRegistry.getKeymapsByPriority();\n\t\t\tfor (const keymaps of [groups.context, groups.navigation, groups.default]) {\n\t\t\t\tfor (let i = keymaps.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst handler = keymaps[i]?.[descriptor];\n\t\t\t\t\tif (handler?.()) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// GapCursor arrow fallback: if no plugin keymap handled the arrow,\n\t\t// provide basic escape from GapCursor state.\n\t\tif (this.handleGapCursorArrowFallback(e)) return;\n\n\t\t// Tab fallback: insert tab character when no plugin handled it\n\t\tif (this.handleTab(e)) return;\n\n\t\t// Escape fallback: exit editor when no plugin handled it (WCAG 2.1.2)\n\t\tif (this.handleEscape(e)) return;\n\n\t\t// Fall back to built-in structural shortcuts\n\t\tconst mod = e.metaKey || e.ctrlKey;\n\t\tif (!mod) return;\n\n\t\tconst key = e.key.toLowerCase();\n\t\tconst state = this.getState();\n\t\tlet tr: Transaction | null = null;\n\n\t\tif (key === 'z' && !e.shiftKey) {\n\t\t\te.preventDefault();\n\t\t\tthis.undo();\n\t\t\treturn;\n\t\t}\n\n\t\tif ((key === 'z' && e.shiftKey) || (key === 'y' && !e.shiftKey)) {\n\t\t\te.preventDefault();\n\t\t\tthis.redo();\n\t\t\treturn;\n\t\t}\n\n\t\tif (key === 'a' && !e.shiftKey) {\n\t\t\te.preventDefault();\n\t\t\ttr = selectAll(state);\n\t\t}\n\n\t\tif (tr) {\n\t\t\tthis.dispatch(tr);\n\t\t}\n\t}\n\n\t/** Handles arrow keys, Enter, Backspace, Delete, Escape when a NodeSelection is active. */\n\tprivate handleNodeSelectionKeys(e: KeyboardEvent): boolean {\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return false;\n\n\t\tconst key = e.key;\n\n\t\t// Arrow keys: navigate away from NodeSelection (only unmodified arrows)\n\t\tif (\n\t\t\t(key === 'ArrowLeft' || key === 'ArrowUp' || key === 'ArrowRight' || key === 'ArrowDown') &&\n\t\t\t!e.shiftKey &&\n\t\t\t!e.metaKey &&\n\t\t\t!e.ctrlKey &&\n\t\t\t!e.altKey\n\t\t) {\n\t\t\tconst direction =\n\t\t\t\tkey === 'ArrowLeft'\n\t\t\t\t\t? 'left'\n\t\t\t\t\t: key === 'ArrowRight'\n\t\t\t\t\t\t? 'right'\n\t\t\t\t\t\t: key === 'ArrowUp'\n\t\t\t\t\t\t\t? 'up'\n\t\t\t\t\t\t\t: 'down';\n\t\t\tconst tr = navigateArrowIntoVoid(state, direction);\n\t\t\tif (tr) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// Backspace / Delete: remove the selected void block\n\t\tif (key === 'Backspace' || key === 'Delete') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr = deleteNodeSelection(state, sel);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Enter: insert paragraph after\n\t\tif (key === 'Enter') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr = splitBlockCommand(state);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Escape: move to start of next block\n\t\tif (key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\tconst tr = navigateArrowIntoVoid(state, 'right');\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Handles keyboard input when a GapCursor is active.\n\t *\n\t * Since the browser has no DOM selection at a GapCursor position,\n\t * no `beforeinput` events fire. This method intercepts printable\n\t * characters, Enter, Backspace, and Delete to dispatch the\n\t * corresponding editor commands.\n\t */\n\tprivate handleGapCursorKeys(e: KeyboardEvent): boolean {\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isGapCursor(sel)) return false;\n\n\t\tconst key: string = e.key;\n\n\t\t// Arrow keys: let GapCursorPlugin keymaps handle them\n\t\tif (key === 'ArrowLeft' || key === 'ArrowRight' || key === 'ArrowUp' || key === 'ArrowDown') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Escape / Tab: pass through\n\t\tif (key === 'Escape' || key === 'Tab') return false;\n\n\t\t// Modifier combos (Ctrl/Meta/Alt): let shortcuts like Ctrl+Z through\n\t\tif (e.ctrlKey || e.metaKey || e.altKey) return false;\n\n\t\t// Enter: insert paragraph at gap\n\t\tif (key === 'Enter') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr: Transaction | null = splitBlockCommand(state);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Backspace: delete backward at gap\n\t\tif (key === 'Backspace') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr: Transaction | null = deleteBackwardAtGap(state, sel);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Delete: delete forward at gap\n\t\tif (key === 'Delete') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr: Transaction | null = deleteForwardAtGap(state, sel);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Printable characters: insert text in a new paragraph\n\t\tif (key.length === 1) {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr: Transaction = insertTextCommand(state, key);\n\t\t\tthis.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Fallback arrow handler for GapCursor when no plugin keymap handled the arrow.\n\t * Provides basic escape from GapCursor state even without GapCursorPlugin.\n\t */\n\tprivate handleGapCursorArrowFallback(e: KeyboardEvent): boolean {\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isGapCursor(sel)) return false;\n\n\t\tconst key: string = e.key;\n\t\tif (key !== 'ArrowLeft' && key !== 'ArrowRight' && key !== 'ArrowUp' && key !== 'ArrowDown') {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst direction =\n\t\t\tkey === 'ArrowLeft'\n\t\t\t\t? 'left'\n\t\t\t\t: key === 'ArrowRight'\n\t\t\t\t\t? 'right'\n\t\t\t\t\t: key === 'ArrowUp'\n\t\t\t\t\t\t? 'up'\n\t\t\t\t\t\t: 'down';\n\t\tconst tr: Transaction | null = navigateFromGapCursor(state, direction);\n\t\tif (tr && !selectionsEqual(tr.selectionAfter, sel)) {\n\t\t\te.preventDefault();\n\t\t\tthis.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Inserts a tab character when Tab is pressed and no plugin handled it.\n\t * Shift-Tab is suppressed to prevent focus leaving the editor.\n\t */\n\tprivate handleTab(e: KeyboardEvent): boolean {\n\t\tif (e.key !== 'Tab') return false;\n\t\tif (e.metaKey || e.ctrlKey || e.altKey) return false;\n\n\t\te.preventDefault();\n\n\t\tif (e.shiftKey) return true;\n\n\t\tconst state = this.getState();\n\t\tconst tr: Transaction = insertTextCommand(state, '\\t');\n\t\tthis.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Exits the editor when Escape is pressed and no plugin handled it.\n\t * Satisfies WCAG 2.1.2 \"No Keyboard Trap\" — since Tab is intercepted\n\t * for indent/insert, Escape provides the keyboard exit mechanism.\n\t */\n\tprivate handleEscape(e: KeyboardEvent): boolean {\n\t\tif (e.key !== 'Escape') return false;\n\n\t\tthis.element.blur();\n\t\treturn true;\n\t}\n\n\tdestroy(): void {\n\t\tthis.element.removeEventListener('keydown', this.handleKeydown);\n\t}\n}\n\n/**\n * Normalizes a KeyboardEvent into a consistent key descriptor string.\n * Format: `\"Mod-Shift-Alt-Key\"` where Mod = Ctrl/Cmd.\n */\nexport function normalizeKeyDescriptor(e: KeyboardEvent): string {\n\tconst parts: string[] = [];\n\tif (e.metaKey || e.ctrlKey) parts.push('Mod');\n\tif (e.shiftKey) parts.push('Shift');\n\tif (e.altKey) parts.push('Alt');\n\n\tlet key = e.key;\n\t// Normalize common keys\n\tif (key === ' ') key = 'Space';\n\telse if (key.length === 1) key = key.toUpperCase();\n\t// For special keys like Enter, Tab, Backspace, keep as-is\n\n\tparts.push(key);\n\treturn parts.join('-');\n}\n","/**\n * MarkSerializer: shared mark serialization logic for DocumentSerializer and ClipboardHandler.\n * Separates style-based marks (merged into a single `<span style>`) from tag-based marks\n * (nested wrappers in rank order).\n */\n\nimport type { Mark } from '../model/Document.js';\nimport { escapeHTML } from '../model/HTMLUtils.js';\nimport type { MarkSpec } from '../model/MarkSpec.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\n\n/** Builds a map of mark type name to rank from the registry (compute once per pass). */\nexport function buildMarkOrder(registry: SchemaRegistry): Map<string, number> {\n\tconst types: readonly string[] = registry.getMarkTypes();\n\tconst order = new Map<string, number>();\n\tfor (const t of types) {\n\t\tconst spec: MarkSpec | undefined = registry.getMarkSpec(t);\n\t\tif (spec) order.set(t, spec.rank ?? 99);\n\t}\n\treturn order;\n}\n\n/**\n * Serializes text with marks to HTML.\n * Style-based marks (`toHTMLStyle`) are merged into a single `<span style=\"...\">`.\n * Tag-based marks (`toHTMLString`) wrap the content in rank order.\n */\nexport function serializeMarksToHTML(\n\ttext: string,\n\tmarks: readonly Mark[],\n\tregistry: SchemaRegistry,\n\tmarkOrder?: Map<string, number>,\n): string {\n\tif (text === '') return '';\n\n\tlet html: string = escapeHTML(text);\n\n\tif (marks.length === 0) return html;\n\n\tconst order: Map<string, number> = markOrder ?? buildMarkOrder(registry);\n\tconst sortedMarks: Mark[] = [...marks].sort(\n\t\t(a, b) => (order.get(a.type) ?? 99) - (order.get(b.type) ?? 99),\n\t);\n\n\tconst styleParts: string[] = [];\n\tconst tagMarks: Mark[] = [];\n\n\tfor (const mark of sortedMarks) {\n\t\tconst markSpec: MarkSpec | undefined = registry.getMarkSpec(mark.type);\n\t\tif (markSpec?.toHTMLStyle) {\n\t\t\tconst style: string | null = markSpec.toHTMLStyle(mark);\n\t\t\tif (style) {\n\t\t\t\tstyleParts.push(style);\n\t\t\t}\n\t\t} else {\n\t\t\ttagMarks.push(mark);\n\t\t}\n\t}\n\n\t// Wrap with merged style span first (closest to text)\n\tif (styleParts.length > 0) {\n\t\thtml = `<span style=\"${styleParts.join('; ')}\">${html}</span>`;\n\t}\n\n\t// Then wrap with tag-based marks in rank order\n\tfor (const mark of tagMarks) {\n\t\tconst markSpec: MarkSpec | undefined = registry.getMarkSpec(mark.type);\n\t\tif (markSpec?.toHTMLString) {\n\t\t\thtml = markSpec.toHTMLString(mark, html);\n\t\t}\n\t}\n\n\treturn html;\n}\n","/**\n * In-memory clipboard for rich block data that cannot survive the system\n * clipboard (which only preserves standard MIME types like text/plain\n * and text/html). This store is keyed by the plain-text content so that\n * a paste event can verify the text matches before using the rich data.\n */\n\n/** A serialized block from a text-selection copy. */\nexport interface RichBlockData {\n\treadonly type: string;\n\treadonly text: string;\n\treadonly attrs?: Record<string, unknown>;\n}\n\ninterface RichClipboardEntry {\n\treadonly plainText: string;\n\treadonly blocks: readonly RichBlockData[];\n}\n\nlet current: RichClipboardEntry | undefined;\n\n/** Stores rich block data alongside its plain-text fingerprint. */\nexport function setRichClipboard(plainText: string, blocks: readonly RichBlockData[]): void {\n\tcurrent = { plainText, blocks };\n}\n\n/**\n * Returns rich block data if the given plain text matches the stored\n * fingerprint (proving it came from our editor, not an external source).\n * Consumes the entry to prevent stale reuse.\n */\nexport function consumeRichClipboard(plainText: string): readonly RichBlockData[] | undefined {\n\tif (!current) return undefined;\n\tif (current.plainText !== plainText) return undefined;\n\tconst blocks = current.blocks;\n\t// Don't clear — allow multiple pastes from same copy\n\treturn blocks;\n}\n\n/** Clears the stored rich clipboard data. */\nexport function clearRichClipboard(): void {\n\tcurrent = undefined;\n}\n","/**\n * Clipboard handler: intercepts copy and cut events, serializes the current\n * selection to clipboard data. Works with both NodeSelection (void blocks)\n * and text selections.\n */\n\nimport { deleteNodeSelection, deleteSelectionCommand } from '../commands/Commands.js';\nimport { buildMarkOrder, serializeMarksToHTML } from '../editor/MarkSerializer.js';\nimport type { BlockNode } from '../model/Document.js';\nimport {\n\tgetBlockLength,\n\tgetBlockText,\n\tgetInlineChildren,\n\tisInlineNode,\n\tisTextNode,\n} from '../model/Document.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport {\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n\tisTextSelection,\n\tselectionRange,\n} from '../model/Selection.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { DispatchFn, GetStateFn } from './InputHandler.js';\nimport { setRichClipboard } from './InternalClipboard.js';\n\nexport interface ClipboardHandlerOptions {\n\treadonly getState: GetStateFn;\n\treadonly dispatch: DispatchFn;\n\treadonly schemaRegistry?: SchemaRegistry;\n\t/** Force-sync DOM selection to state (selectionchange may fire async). */\n\treadonly syncSelection?: () => void;\n\treadonly isReadOnly?: () => boolean;\n}\n\n/** Custom MIME type for internal block copy/paste round-trips (void/NodeSelection). */\nconst BLOCK_MIME = 'application/x-notectl-block';\n\nexport class ClipboardHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate readonly syncSelection?: () => void;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate readonly handleCopy: (e: ClipboardEvent) => void;\n\tprivate readonly handleCut: (e: ClipboardEvent) => void;\n\n\tconstructor(\n\t\tprivate readonly element: HTMLElement,\n\t\toptions: ClipboardHandlerOptions,\n\t) {\n\t\tthis.getState = options.getState;\n\t\tthis.dispatch = options.dispatch;\n\t\tthis.schemaRegistry = options.schemaRegistry;\n\t\tthis.syncSelection = options.syncSelection;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\n\t\tthis.handleCopy = this.onCopy.bind(this);\n\t\tthis.handleCut = this.onCut.bind(this);\n\t\telement.addEventListener('copy', this.handleCopy);\n\t\telement.addEventListener('cut', this.handleCut);\n\t}\n\n\tprivate onCopy(e: ClipboardEvent): void {\n\t\t// Sync DOM selection → state first; selectionchange may lag behind\n\t\tthis.syncSelection?.();\n\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\n\t\t// GapCursor: nothing to copy\n\t\tif (isGapCursor(sel)) return;\n\n\t\t// Collapsed selection: let the browser handle it\n\t\tif (isTextSelection(sel) && isCollapsed(sel)) return;\n\n\t\te.preventDefault();\n\t\tconst clipboardData = e.clipboardData;\n\t\tif (!clipboardData) return;\n\n\t\tif (isNodeSelection(sel)) {\n\t\t\tthis.writeNodeSelectionToClipboard(clipboardData, state);\n\t\t} else {\n\t\t\tthis.writeTextSelectionToClipboard(clipboardData, state);\n\t\t}\n\t}\n\n\tprivate onCut(e: ClipboardEvent): void {\n\t\tif (this.isReadOnly()) return;\n\n\t\t// Sync DOM selection → state first; selectionchange may lag behind\n\t\tthis.syncSelection?.();\n\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\n\t\t// GapCursor: nothing to cut\n\t\tif (isGapCursor(sel)) return;\n\n\t\t// Collapsed selection: nothing to cut\n\t\tif (isTextSelection(sel) && isCollapsed(sel)) return;\n\n\t\te.preventDefault();\n\t\tconst clipboardData = e.clipboardData;\n\t\tif (!clipboardData) return;\n\n\t\t// Write to clipboard first\n\t\tif (isNodeSelection(sel)) {\n\t\t\tthis.writeNodeSelectionToClipboard(clipboardData, state);\n\t\t\tconst tr = deleteNodeSelection(state, sel);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t} else {\n\t\t\tthis.writeTextSelectionToClipboard(clipboardData, state);\n\t\t\tconst tr = deleteSelectionCommand(state);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t}\n\t}\n\n\tprivate writeNodeSelectionToClipboard(clipboardData: DataTransfer, state: EditorState): void {\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\n\t\tconst block = state.getBlock(sel.nodeId);\n\t\tif (!block) return;\n\n\t\t// Internal format: block type + attrs for round-trip paste\n\t\tconst blockData: { readonly type: string; readonly attrs?: Record<string, unknown> } = {\n\t\t\ttype: block.type,\n\t\t\t...(block.attrs ? { attrs: { ...block.attrs } } : {}),\n\t\t};\n\t\tclipboardData.setData(BLOCK_MIME, JSON.stringify(blockData));\n\n\t\t// HTML representation via NodeSpec.toHTML if available\n\t\tconst spec = this.schemaRegistry?.getNodeSpec(block.type);\n\t\tif (spec?.toHTML) {\n\t\t\tclipboardData.setData('text/html', spec.toHTML(block, ''));\n\t\t}\n\n\t\t// Plain text: use alt text for images, empty for other voids\n\t\tconst attrs = block.attrs as Record<string, unknown> | undefined;\n\t\tconst altText: string = typeof attrs?.alt === 'string' ? attrs.alt : '';\n\t\tclipboardData.setData('text/plain', altText);\n\t}\n\n\tprivate writeTextSelectionToClipboard(clipboardData: DataTransfer, state: EditorState): void {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return;\n\t\tif (isGapCursor(sel)) return;\n\t\tif (isCollapsed(sel)) return;\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t\tconst lines: string[] = [];\n\t\tconst richBlocks: Array<{\n\t\t\ttype: string;\n\t\t\ttext: string;\n\t\t\tattrs?: Record<string, unknown>;\n\t\t}> = [];\n\n\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\tconst bid = blockOrder[i];\n\t\t\tif (!bid) continue;\n\t\t\tconst block = state.getBlock(bid);\n\t\t\tif (!block) continue;\n\n\t\t\tconst text = getBlockText(block);\n\t\t\tconst blockLen = getBlockLength(block);\n\t\t\tconst start = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst end = i === toIdx ? range.to.offset : blockLen;\n\t\t\tconst sliced: string = text.slice(start, end);\n\t\t\tlines.push(sliced);\n\n\t\t\trichBlocks.push({\n\t\t\t\ttype: block.type,\n\t\t\t\ttext: sliced,\n\t\t\t\t...(block.attrs ? { attrs: { ...block.attrs } } : {}),\n\t\t\t});\n\t\t}\n\n\t\tconst plainText: string = lines.join('\\n');\n\t\tclipboardData.setData('text/plain', plainText);\n\n\t\t// Write text/html with inline marks so paste preserves formatting\n\t\tif (this.schemaRegistry) {\n\t\t\tconst markOrder: Map<string, number> = buildMarkOrder(this.schemaRegistry);\n\t\t\tconst htmlParts: string[] = [];\n\t\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\t\tconst bid = blockOrder[i];\n\t\t\t\tif (!bid) continue;\n\t\t\t\tconst block = state.getBlock(bid);\n\t\t\t\tif (!block) continue;\n\n\t\t\t\tconst start = i === fromIdx ? range.from.offset : 0;\n\t\t\t\tconst end = i === toIdx ? range.to.offset : getBlockLength(block);\n\t\t\t\thtmlParts.push(this.serializeBlockRangeToHTML(block, start, end, markOrder));\n\t\t\t}\n\t\t\tclipboardData.setData('text/html', htmlParts.join(''));\n\t\t}\n\n\t\t// Store rich block data in memory — system clipboard strips custom MIME\n\t\t// types and rewrites text/html, so we use an in-memory store keyed by\n\t\t// the plain-text fingerprint to verify origin on paste.\n\t\tsetRichClipboard(plainText, richBlocks);\n\t}\n\n\t/** Serializes a range of inline content within a block to an HTML string. */\n\tprivate serializeBlockRangeToHTML(\n\t\tblock: BlockNode,\n\t\tstart: number,\n\t\tend: number,\n\t\tmarkOrder?: Map<string, number>,\n\t): string {\n\t\tconst children = getInlineChildren(block);\n\t\tconst parts: string[] = [];\n\t\tlet pos = 0;\n\n\t\tfor (const child of children) {\n\t\t\tconst width: number = isInlineNode(child) ? 1 : child.text.length;\n\t\t\tconst childEnd: number = pos + width;\n\n\t\t\tif (childEnd <= start || pos >= end) {\n\t\t\t\tpos = childEnd;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (isTextNode(child)) {\n\t\t\t\tconst sliceFrom: number = Math.max(0, start - pos);\n\t\t\t\tconst sliceTo: number = Math.min(child.text.length, end - pos);\n\t\t\t\tconst text: string = child.text.slice(sliceFrom, sliceTo);\n\t\t\t\tif (text.length > 0 && this.schemaRegistry) {\n\t\t\t\t\tparts.push(serializeMarksToHTML(text, child.marks, this.schemaRegistry, markOrder));\n\t\t\t\t}\n\t\t\t} else if (isInlineNode(child)) {\n\t\t\t\tconst spec = this.schemaRegistry?.getInlineNodeSpec(child.inlineType);\n\t\t\t\tif (spec?.toHTMLString) {\n\t\t\t\t\tparts.push(spec.toHTMLString(child));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpos = childEnd;\n\t\t}\n\n\t\treturn parts.join('');\n\t}\n\n\tdestroy(): void {\n\t\tthis.element.removeEventListener('copy', this.handleCopy);\n\t\tthis.element.removeEventListener('cut', this.handleCut);\n\t}\n}\n","/**\n * Centralized composition state tracker.\n * Exposes the current IME composition status so that KeyboardHandler,\n * SelectionSync, and Reconciler can guard against DOM mutations\n * that would break an active browser composition session.\n */\n\nimport type { BlockId } from '../model/TypeBrands.js';\n\nexport class CompositionTracker {\n\tprivate _composing = false;\n\tprivate _activeBlockId: BlockId | null = null;\n\n\t/** Whether an IME composition session is currently active. */\n\tget isComposing(): boolean {\n\t\treturn this._composing;\n\t}\n\n\t/** The block in which the composition is happening, or null if idle. */\n\tget activeBlockId(): BlockId | null {\n\t\treturn this._activeBlockId;\n\t}\n\n\t/** Marks the start of a composition session in the given block. */\n\tstart(blockId: BlockId): void {\n\t\tthis._composing = true;\n\t\tthis._activeBlockId = blockId;\n\t}\n\n\t/** Marks the end of a composition session. */\n\tend(): void {\n\t\tthis._composing = false;\n\t\tthis._activeBlockId = null;\n\t}\n}\n","/**\n * KeymapRegistry: manages plugin-registered keyboard shortcuts\n * with a 3-priority system (context > navigation > default).\n */\n\nimport type { Keymap, KeymapOptions, KeymapPriority } from './Keymap.js';\n\nexport class KeymapRegistry {\n\tprivate readonly _contextKeymaps: Keymap[] = [];\n\tprivate readonly _navigationKeymaps: Keymap[] = [];\n\tprivate readonly _defaultKeymaps: Keymap[] = [];\n\n\tregisterKeymap(keymap: Keymap, options?: KeymapOptions): void {\n\t\tconst allKeymaps: Keymap[] = [\n\t\t\t...this._contextKeymaps,\n\t\t\t...this._navigationKeymaps,\n\t\t\t...this._defaultKeymaps,\n\t\t];\n\t\tfor (const key of Object.keys(keymap)) {\n\t\t\tfor (const existing of allKeymaps) {\n\t\t\t\tif (key in existing) {\n\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t`[notectl] Keymap shortcut \"${key}\" is already registered and will be overridden.`,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.keymapArrayForPriority(options?.priority ?? 'default').push(keymap);\n\t}\n\n\t/** Returns all keymaps in priority order: context > navigation > default. */\n\tgetKeymaps(): readonly Keymap[] {\n\t\treturn [...this._contextKeymaps, ...this._navigationKeymaps, ...this._defaultKeymaps];\n\t}\n\n\t/** Returns keymaps grouped by priority level (defensive copies). */\n\tgetKeymapsByPriority(): {\n\t\treadonly context: readonly Keymap[];\n\t\treadonly navigation: readonly Keymap[];\n\t\treadonly default: readonly Keymap[];\n\t} {\n\t\treturn {\n\t\t\tcontext: [...this._contextKeymaps],\n\t\t\tnavigation: [...this._navigationKeymaps],\n\t\t\tdefault: [...this._defaultKeymaps],\n\t\t};\n\t}\n\n\tremoveKeymap(keymap: Keymap): void {\n\t\tfor (const arr of [this._contextKeymaps, this._navigationKeymaps, this._defaultKeymaps]) {\n\t\t\tconst idx: number = arr.indexOf(keymap);\n\t\t\tif (idx !== -1) {\n\t\t\t\tarr.splice(idx, 1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis._contextKeymaps.length = 0;\n\t\tthis._navigationKeymaps.length = 0;\n\t\tthis._defaultKeymaps.length = 0;\n\t}\n\n\tprivate keymapArrayForPriority(priority: KeymapPriority): Keymap[] {\n\t\tswitch (priority) {\n\t\t\tcase 'context':\n\t\t\t\treturn this._contextKeymaps;\n\t\t\tcase 'navigation':\n\t\t\t\treturn this._navigationKeymaps;\n\t\t\tcase 'default':\n\t\t\t\treturn this._defaultKeymaps;\n\t\t}\n\t}\n}\n","/**\n * InputRuleRegistry: manages plugin-registered input rules\n * (pattern-based text transformations triggered on text input).\n */\n\nimport type { InputRule } from './InputRule.js';\n\nexport class InputRuleRegistry {\n\tprivate readonly _inputRules: InputRule[] = [];\n\n\tregisterInputRule(rule: InputRule): void {\n\t\tthis._inputRules.push(rule);\n\t}\n\n\tgetInputRules(): readonly InputRule[] {\n\t\treturn this._inputRules;\n\t}\n\n\tremoveInputRule(rule: InputRule): void {\n\t\tconst idx = this._inputRules.indexOf(rule);\n\t\tif (idx !== -1) this._inputRules.splice(idx, 1);\n\t}\n\n\tclear(): void {\n\t\tthis._inputRules.length = 0;\n\t}\n}\n","/**\n * FileHandlerRegistry: manages plugin-registered file handlers\n * for paste and drop operations, with MIME pattern matching.\n */\n\nimport type { Position } from '../model/Selection.js';\n\n/** Handler for a single file pasted or dropped into the editor. */\nexport type FileHandler = (file: File, position: Position | null) => boolean | Promise<boolean>;\n\nexport interface FileHandlerEntry {\n\treadonly pattern: string;\n\treadonly handler: FileHandler;\n}\n\nexport class FileHandlerRegistry {\n\tprivate readonly _fileHandlers: FileHandlerEntry[] = [];\n\n\tregisterFileHandler(pattern: string, handler: FileHandler): void {\n\t\tthis._fileHandlers.push({ pattern, handler });\n\t}\n\n\tgetFileHandlers(): readonly FileHandlerEntry[] {\n\t\treturn this._fileHandlers;\n\t}\n\n\tmatchFileHandlers(mimeType: string): FileHandler[] {\n\t\tconst handlers: FileHandler[] = [];\n\t\tfor (const entry of this._fileHandlers) {\n\t\t\tif (matchMimePattern(entry.pattern, mimeType)) {\n\t\t\t\thandlers.push(entry.handler);\n\t\t\t}\n\t\t}\n\t\treturn handlers;\n\t}\n\n\tremoveFileHandler(handler: FileHandler): void {\n\t\tconst idx = this._fileHandlers.findIndex((e) => e.handler === handler);\n\t\tif (idx !== -1) this._fileHandlers.splice(idx, 1);\n\t}\n\n\tclear(): void {\n\t\tthis._fileHandlers.length = 0;\n\t}\n}\n\n/** Matches a MIME pattern (e.g. 'image/*') against a concrete MIME type. */\nfunction matchMimePattern(pattern: string, mimeType: string): boolean {\n\tif (pattern === '*' || pattern === '*/*') return true;\n\tif (pattern === mimeType) return true;\n\tif (pattern.endsWith('/*')) {\n\t\tconst prefix = pattern.slice(0, -1);\n\t\treturn mimeType.startsWith(prefix);\n\t}\n\treturn false;\n}\n","/**\n * NodeViewRegistry: manages plugin-registered custom NodeView factories\n * for block-level rendering.\n */\n\nimport type { NodeViewFactory } from './NodeView.js';\n\nexport class NodeViewRegistry {\n\tprivate readonly _nodeViews = new Map<string, NodeViewFactory>();\n\n\tregisterNodeView(type: string, factory: NodeViewFactory): void {\n\t\tif (this._nodeViews.has(type)) {\n\t\t\tthrow new Error(`NodeView for type \"${type}\" is already registered.`);\n\t\t}\n\t\tthis._nodeViews.set(type, factory);\n\t}\n\n\tgetNodeViewFactory(type: string): NodeViewFactory | undefined {\n\t\treturn this._nodeViews.get(type);\n\t}\n\n\tremoveNodeView(type: string): void {\n\t\tthis._nodeViews.delete(type);\n\t}\n\n\tclear(): void {\n\t\tthis._nodeViews.clear();\n\t}\n}\n","/**\n * ToolbarRegistry: manages plugin-registered toolbar items\n * with per-plugin tracking for clean teardown.\n */\n\nimport type { ToolbarItem } from './ToolbarItem.js';\n\nexport class ToolbarRegistry {\n\tprivate readonly _toolbarItems = new Map<string, ToolbarItem>();\n\tprivate readonly _toolbarItemPluginMap = new Map<string, string[]>();\n\n\tregisterToolbarItem(item: ToolbarItem, pluginId?: string): void {\n\t\tif (this._toolbarItems.has(item.id)) {\n\t\t\tthrow new Error(`ToolbarItem with id \"${item.id}\" is already registered.`);\n\t\t}\n\t\tthis._toolbarItems.set(item.id, item);\n\t\tif (pluginId) {\n\t\t\tconst ids = this._toolbarItemPluginMap.get(pluginId) ?? [];\n\t\t\tids.push(item.id);\n\t\t\tthis._toolbarItemPluginMap.set(pluginId, ids);\n\t\t}\n\t}\n\n\tgetToolbarItemsByPlugin(pluginId: string): ToolbarItem[] {\n\t\tconst ids = this._toolbarItemPluginMap.get(pluginId) ?? [];\n\t\tconst items: ToolbarItem[] = [];\n\t\tfor (const id of ids) {\n\t\t\tconst item = this._toolbarItems.get(id);\n\t\t\tif (item) items.push(item);\n\t\t}\n\t\treturn items;\n\t}\n\n\tgetToolbarItem(id: string): ToolbarItem | undefined {\n\t\treturn this._toolbarItems.get(id);\n\t}\n\n\tgetToolbarItems(): ToolbarItem[] {\n\t\treturn [...this._toolbarItems.values()];\n\t}\n\n\tremoveToolbarItem(id: string): void {\n\t\tthis._toolbarItems.delete(id);\n\t\tfor (const [pluginId, ids] of this._toolbarItemPluginMap) {\n\t\t\tconst idx = ids.indexOf(id);\n\t\t\tif (idx !== -1) {\n\t\t\t\tids.splice(idx, 1);\n\t\t\t\tif (ids.length === 0) this._toolbarItemPluginMap.delete(pluginId);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis._toolbarItems.clear();\n\t\tthis._toolbarItemPluginMap.clear();\n\t}\n}\n","/**\n * BlockTypePickerRegistry: manages plugin-registered block type picker entries\n * displayed in the heading/block type dropdown, sorted by priority.\n */\n\nimport type { BlockTypePickerEntry } from './BlockTypePickerEntry.js';\n\nexport class BlockTypePickerRegistry {\n\tprivate readonly _entries = new Map<string, BlockTypePickerEntry>();\n\n\tregisterBlockTypePickerEntry(entry: BlockTypePickerEntry): void {\n\t\tif (this._entries.has(entry.id)) {\n\t\t\tthrow new Error(`BlockTypePickerEntry with id \"${entry.id}\" is already registered.`);\n\t\t}\n\t\tthis._entries.set(entry.id, entry);\n\t}\n\n\tgetBlockTypePickerEntries(): readonly BlockTypePickerEntry[] {\n\t\treturn [...this._entries.values()].sort((a, b) => a.priority - b.priority);\n\t}\n\n\tremoveBlockTypePickerEntry(id: string): void {\n\t\tthis._entries.delete(id);\n\t}\n\n\tclear(): void {\n\t\tthis._entries.clear();\n\t}\n}\n","/**\n * Shared mark rendering utilities used by Reconciler and CursorWrapper.\n *\n * Provides mark rank ordering and DOM element creation for marks,\n * using the SchemaRegistry when available and falling back to\n * built-in defaults.\n */\n\nimport type { MarkAttrsFor } from '../model/AttrRegistry.js';\nimport type { Mark } from '../model/Document.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\n\n/** Returns the rank for a mark (lower = outermost in the DOM nesting). */\nexport function getMarkRank(mark: Mark, registry?: SchemaRegistry): number {\n\tif (registry) {\n\t\tconst spec = registry.getMarkSpec(mark.type);\n\t\tif (spec) return spec.rank ?? 100;\n\t}\n\tswitch (mark.type) {\n\t\tcase 'bold':\n\t\t\treturn 0;\n\t\tcase 'italic':\n\t\t\treturn 1;\n\t\tcase 'underline':\n\t\t\treturn 2;\n\t\tdefault:\n\t\t\treturn 100;\n\t}\n}\n\n/** Creates a DOM element for a mark, using the registry spec or a built-in fallback. */\nexport function createMarkElement(mark: Mark, registry?: SchemaRegistry): HTMLElement {\n\tif (registry) {\n\t\tconst spec = registry.getMarkSpec(mark.type);\n\t\tif (spec) {\n\t\t\treturn spec.toDOM(mark as Omit<Mark, 'attrs'> & { readonly attrs: MarkAttrsFor<string> });\n\t\t}\n\t}\n\tswitch (mark.type) {\n\t\tcase 'bold':\n\t\t\treturn document.createElement('strong');\n\t\tcase 'italic':\n\t\t\treturn document.createElement('em');\n\t\tcase 'underline':\n\t\t\treturn document.createElement('u');\n\t\tdefault:\n\t\t\treturn document.createElement('span');\n\t}\n}\n","/**\n * CursorWrapper: creates a temporary mark-wrapped DOM element during IME\n * composition so that composed text inherits the stored marks (e.g. bold).\n *\n * Without this, toggling Bold with a collapsed cursor and then starting an\n * IME composition would produce unformatted text because the browser has no\n * formatted DOM node to compose into.\n *\n * The wrapper is a `<span data-cursor-wrapper>` containing a zero-width space\n * (`\\u200B`), nested inside mark elements matching the stored marks.\n */\n\nimport type { Mark } from '../model/Document.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { isCollapsed, isGapCursor, isNodeSelection } from '../model/Selection.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport { createMarkElement, getMarkRank } from './MarkRendering.js';\nimport { getSelection } from './SelectionSync.js';\n\nconst ZWS = '\\u200B';\nconst CURSOR_WRAPPER_ATTR = 'data-cursor-wrapper';\n\nexport class CursorWrapper {\n\tprivate wrapperElement: HTMLElement | null = null;\n\tprivate readonly container: HTMLElement;\n\tprivate readonly registry: SchemaRegistry | undefined;\n\n\tconstructor(container: HTMLElement, registry?: SchemaRegistry) {\n\t\tthis.container = container;\n\t\tthis.registry = registry;\n\t}\n\n\t/** Whether a cursor wrapper is currently in the DOM. */\n\tget isActive(): boolean {\n\t\treturn this.wrapperElement !== null;\n\t}\n\n\t/**\n\t * Creates a mark-wrapped cursor element if storedMarks are present.\n\t * Places the browser cursor inside the ZWS text node so that IME\n\t * composition inherits the mark formatting.\n\t */\n\tonCompositionStart(state: EditorState): void {\n\t\tthis.cleanup();\n\n\t\tconst marks: readonly Mark[] | null = state.storedMarks;\n\t\tif (!marks || marks.length === 0) return;\n\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return;\n\t\tif (!isCollapsed(sel)) return;\n\n\t\t// Build the wrapper: <span data-cursor-wrapper>ZWS</span>\n\t\tconst wrapper: HTMLElement = document.createElement('span');\n\t\twrapper.setAttribute(CURSOR_WRAPPER_ATTR, '');\n\t\tconst textNode: Text = document.createTextNode(ZWS);\n\n\t\t// Wrap the text node in sorted mark elements (innermost → outermost)\n\t\tlet current: Node = textNode;\n\t\tconst sortedMarks: readonly Mark[] = [...marks].sort(\n\t\t\t(a, b) => getMarkRank(a, this.registry) - getMarkRank(b, this.registry),\n\t\t);\n\n\t\tfor (let i: number = sortedMarks.length - 1; i >= 0; i--) {\n\t\t\tconst mark: Mark | undefined = sortedMarks[i];\n\t\t\tif (!mark) continue;\n\t\t\tconst el: HTMLElement = createMarkElement(mark, this.registry);\n\t\t\tel.appendChild(current);\n\t\t\tcurrent = el;\n\t\t}\n\n\t\twrapper.appendChild(current);\n\n\t\t// Insert at the current DOM cursor position\n\t\tconst domSel: globalThis.Selection | null = getSelection(this.container);\n\t\tif (!domSel || domSel.rangeCount === 0) return;\n\n\t\tconst range: Range = domSel.getRangeAt(0);\n\t\trange.insertNode(wrapper);\n\n\t\t// Place browser cursor inside the ZWS text node\n\t\ttry {\n\t\t\tdomSel.collapse(textNode, textNode.length);\n\t\t} catch {\n\t\t\t// May fail in test environments\n\t\t}\n\n\t\tthis.wrapperElement = wrapper;\n\t}\n\n\t/** Removes the wrapper element from the DOM. */\n\tcleanup(): void {\n\t\tif (!this.wrapperElement) return;\n\t\tthis.wrapperElement.remove();\n\t\tthis.wrapperElement = null;\n\t}\n}\n","/**\n * Pure functions that attach WAI-ARIA keyboard patterns to popup containers.\n * Supports menu, listbox, and grid navigation patterns.\n * Delegates to ToolbarKeyboardNav for shared navigation logic.\n */\n\nimport {\n\tapplyRovingTabindex,\n\tfindNextDropdownItem,\n\tnavigateGrid,\n} from '../toolbar/ToolbarKeyboardNav.js';\n\n// --- Types ---\n\nexport interface MenuKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly itemSelector: string;\n\treadonly onActivate: (item: HTMLElement) => void;\n\treadonly onClose: () => void;\n\treadonly getActiveElement: () => Element | null;\n}\n\nexport interface ListboxKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly itemSelector: string;\n\treadonly onSelect: (item: HTMLElement) => void;\n\treadonly onClose: () => void;\n}\n\nexport interface GridKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly cellSelector: string;\n\treadonly columns: number;\n\treadonly totalCells: number;\n\treadonly onSelect: (cell: HTMLElement) => void;\n\treadonly onClose: () => void;\n\treadonly onNavigate?: (index: number) => void;\n}\n\n// --- Constants ---\n\nconst GRID_NAV_KEYS: ReadonlySet<string> = new Set([\n\t'ArrowUp',\n\t'ArrowDown',\n\t'ArrowLeft',\n\t'ArrowRight',\n]);\n\n// --- Menu Keyboard ---\n\n/**\n * Attaches menu keyboard navigation (ArrowUp/Down, Enter/Space, Home/End, Escape).\n * Returns a cleanup function that removes the event listener.\n */\nexport function attachMenuKeyboard(config: MenuKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\te.stopPropagation();\n\t\tconst items: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.itemSelector),\n\t\t) as HTMLElement[];\n\t\tif (items.length === 0) return;\n\n\t\tswitch (e.key) {\n\t\t\tcase 'Escape': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconfig.onClose();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, 1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, -1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst item: HTMLElement | undefined = items[focusedIndex];\n\t\t\t\tif (item) config.onActivate(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Home': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = 0;\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'End': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = items.length - 1;\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n\n// --- Listbox Keyboard ---\n\n/**\n * Attaches listbox keyboard navigation (ArrowUp/Down, Enter/Space, Escape).\n * Returns a cleanup function.\n */\nexport function attachListboxKeyboard(config: ListboxKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\tconst items: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.itemSelector),\n\t\t) as HTMLElement[];\n\t\tif (items.length === 0) return;\n\n\t\tswitch (e.key) {\n\t\t\tcase 'Escape': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconfig.onClose();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, 1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, -1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst item: HTMLElement | undefined = items[focusedIndex];\n\t\t\t\tif (item) config.onSelect(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n\n// --- Grid Keyboard ---\n\n/**\n * Attaches grid keyboard navigation (2D arrows, Home/End per row, Enter/Space, Escape).\n * Returns a cleanup function.\n */\nexport function attachGridKeyboard(config: GridKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\tconst columns: number = config.columns;\n\tconst totalCells: number = config.totalCells;\n\tconst totalRows: number = Math.ceil(totalCells / columns);\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\tconst cells: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.cellSelector),\n\t\t) as HTMLElement[];\n\t\tif (cells.length === 0) return;\n\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\tconfig.onClose();\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\te.preventDefault();\n\t\t\tconst cell: HTMLElement | undefined = cells[focusedIndex];\n\t\t\tif (cell) config.onSelect(cell);\n\t\t\treturn;\n\t\t}\n\n\t\tif (GRID_NAV_KEYS.has(e.key)) {\n\t\t\te.preventDefault();\n\t\t\tconst currentRow: number = Math.floor(focusedIndex / columns) + 1;\n\t\t\tconst currentCol: number = (focusedIndex % columns) + 1;\n\n\t\t\tconst [newRow, newCol] = navigateGrid(\n\t\t\t\tcurrentRow,\n\t\t\t\tcurrentCol,\n\t\t\t\ttotalRows,\n\t\t\t\tcolumns,\n\t\t\t\te.key as 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight',\n\t\t\t);\n\n\t\t\tlet newIdx: number = (newRow - 1) * columns + (newCol - 1);\n\t\t\tif (newIdx >= totalCells) {\n\t\t\t\tnewIdx = totalCells - 1;\n\t\t\t}\n\n\t\t\tfocusedIndex = newIdx;\n\t\t\tapplyRovingTabindex(cells as HTMLButtonElement[], focusedIndex);\n\t\t\tcells[focusedIndex]?.focus();\n\t\t\tconfig.onNavigate?.(focusedIndex);\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Home' || e.key === 'End') {\n\t\t\te.preventDefault();\n\t\t\tconst currentRow: number = Math.floor(focusedIndex / columns);\n\t\t\tconst rowStart: number = currentRow * columns;\n\t\t\tconst rowEnd: number = Math.min(rowStart + columns - 1, totalCells - 1);\n\n\t\t\tfocusedIndex = e.key === 'Home' ? rowStart : rowEnd;\n\t\t\tapplyRovingTabindex(cells as HTMLButtonElement[], focusedIndex);\n\t\t\tcells[focusedIndex]?.focus();\n\t\t\tconfig.onNavigate?.(focusedIndex);\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n","/**\n * Standalone event bus with error isolation and type-safe event keys.\n * Each listener is wrapped in try/catch — a failing listener never affects others.\n */\n\nimport type { EventKey, PluginEventCallback } from './Plugin.js';\n\nexport class EventBus {\n\tprivate readonly listeners = new Map<string, Set<PluginEventCallback>>();\n\n\t/** Emits an event to all registered listeners. Errors are caught per listener. */\n\temit<T>(key: EventKey<T>, payload: T): void {\n\t\tconst set = this.listeners.get(key.id);\n\t\tif (!set) return;\n\n\t\tfor (const listener of set) {\n\t\t\ttry {\n\t\t\t\tlistener(payload);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[EventBus] Listener error on \"${key.id}\":`, err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Subscribes to an event. Returns an unsubscribe function. */\n\ton<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void {\n\t\tconst id = key.id;\n\t\tif (!this.listeners.has(id)) {\n\t\t\tthis.listeners.set(id, new Set());\n\t\t}\n\t\tconst set = this.listeners.get(id) ?? new Set();\n\t\tset.add(callback as PluginEventCallback);\n\n\t\treturn () => {\n\t\t\tset.delete(callback as PluginEventCallback);\n\t\t\tif (set.size === 0) this.listeners.delete(id);\n\t\t};\n\t}\n\n\t/** Removes a specific listener from an event. */\n\toff<T>(key: EventKey<T>, callback: PluginEventCallback<T>): void {\n\t\tconst set = this.listeners.get(key.id);\n\t\tif (!set) return;\n\t\tset.delete(callback as PluginEventCallback);\n\t\tif (set.size === 0) this.listeners.delete(key.id);\n\t}\n\n\t/** Removes all listeners for all events. */\n\tclear(): void {\n\t\tthis.listeners.clear();\n\t}\n}\n","/**\n * Plugin manager: handles plugin lifecycle, dependency resolution,\n * middleware chain, command/service registries, and error isolation.\n *\n * Per-plugin registration tracking ensures clean teardown —\n * commands, services, middleware, event subscriptions, and schema\n * registrations are automatically cleaned up when a plugin is destroyed.\n */\n\nimport { DecorationSet } from '../decorations/Decoration.js';\nimport { type FileHandler, FileHandlerRegistry } from '../input/FileHandlerRegistry.js';\nimport type { InputRule } from '../input/InputRule.js';\nimport { InputRuleRegistry } from '../input/InputRuleRegistry.js';\nimport type { Keymap, KeymapOptions } from '../input/Keymap.js';\nimport { KeymapRegistry } from '../input/KeymapRegistry.js';\nimport { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { NodeViewRegistry } from '../view/NodeViewRegistry.js';\nimport { EventBus } from './EventBus.js';\nimport type {\n\tCommandEntry,\n\tCommandHandler,\n\tCommandOptions,\n\tEventKey,\n\tMiddlewareNext,\n\tMiddlewareOptions,\n\tPlugin,\n\tPluginConfig,\n\tPluginContext,\n\tPluginEventBus,\n\tPluginEventCallback,\n\tServiceKey,\n\tTransactionMiddleware,\n} from './Plugin.js';\nimport { BlockTypePickerRegistry } from './heading/BlockTypePickerRegistry.js';\nimport { ToolbarRegistry } from './toolbar/ToolbarRegistry.js';\n\nconst DEFAULT_PRIORITY = 100;\n\ninterface MiddlewareEntry {\n\treadonly name: string;\n\treadonly pluginId: string;\n\treadonly middleware: TransactionMiddleware;\n\treadonly priority: number;\n}\n\n/** Describes a registered middleware for introspection. */\nexport interface MiddlewareInfo {\n\treadonly name: string;\n\treadonly priority: number;\n\treadonly pluginId: string;\n}\n\ninterface PluginRegistrations {\n\tcommands: string[];\n\tservices: string[];\n\tmiddlewares: MiddlewareEntry[];\n\tunsubscribers: (() => void)[];\n\tnodeSpecs: string[];\n\tmarkSpecs: string[];\n\tinlineNodeSpecs: string[];\n\tnodeViews: string[];\n\tkeymaps: Keymap[];\n\tinputRules: InputRule[];\n\ttoolbarItems: string[];\n\tfileHandlers: FileHandler[];\n\tblockTypePickerEntries: string[];\n\tstylesheets: CSSStyleSheet[];\n}\n\nexport interface PluginManagerInitOptions {\n\tgetState(): EditorState;\n\tdispatch(transaction: Transaction): void;\n\tgetContainer(): HTMLElement;\n\tgetPluginContainer(position: 'top' | 'bottom'): HTMLElement;\n\t/** Pushes a screen reader announcement via the editor's aria-live region. */\n\tannounce?(text: string): void;\n\t/** Returns whether the announcer live region currently has content. */\n\thasAnnouncement?(): boolean;\n\t/** Called after all plugin init() calls complete, before onReady(). */\n\tonBeforeReady?(): void | Promise<void>;\n}\n\nexport class PluginManager {\n\tprivate readonly plugins = new Map<string, Plugin>();\n\tprivate readonly commands = new Map<string, CommandEntry>();\n\tprivate readonly services = new Map<string, unknown>();\n\tprivate readonly middlewares: MiddlewareEntry[] = [];\n\tprivate readonly registrations = new Map<string, PluginRegistrations>();\n\tprivate readonly eventBus = new EventBus();\n\tprivate readonly pluginStyleSheets: CSSStyleSheet[] = [];\n\treadonly schemaRegistry = new SchemaRegistry();\n\treadonly keymapRegistry = new KeymapRegistry();\n\treadonly inputRuleRegistry = new InputRuleRegistry();\n\treadonly fileHandlerRegistry = new FileHandlerRegistry();\n\treadonly nodeViewRegistry = new NodeViewRegistry();\n\treadonly toolbarRegistry = new ToolbarRegistry();\n\treadonly blockTypePickerRegistry = new BlockTypePickerRegistry();\n\tprivate middlewareSorted: MiddlewareEntry[] | null = null;\n\tprivate initOrder: string[] = [];\n\tprivate initialized = false;\n\tprivate initializing = false;\n\tprivate readOnly = false;\n\tprivate readonlyBypassActive = false;\n\n\t/**\n\t * Registers a system-level service before plugin init.\n\t * Used by the editor to provide global services (e.g. LocaleService).\n\t */\n\tregisterService<T>(key: ServiceKey<T>, service: T): void {\n\t\tif (this.services.has(key.id)) {\n\t\t\tthrow new Error(`Service \"${key.id}\" is already registered.`);\n\t\t}\n\t\tthis.services.set(key.id, service);\n\t}\n\n\t/** Registers a plugin. Must be called before init(). */\n\tregister(plugin: Plugin): void {\n\t\tif (this.initialized || this.initializing) {\n\t\t\tthrow new Error(`Cannot register plugin \"${plugin.id}\" after initialization.`);\n\t\t}\n\t\tif (this.plugins.has(plugin.id)) {\n\t\t\tthrow new Error(`Plugin \"${plugin.id}\" is already registered.`);\n\t\t}\n\t\tthis.plugins.set(plugin.id, plugin);\n\t}\n\n\t/** Initializes all registered plugins in dependency/priority order. */\n\tasync init(options: PluginManagerInitOptions): Promise<void> {\n\t\tif (this.initialized || this.initializing) return;\n\t\tthis.initializing = true;\n\n\t\tthis.initOrder = this.resolveOrder();\n\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin) continue;\n\t\t\tconst context = this.createContext(id, options);\n\t\t\ttry {\n\t\t\t\tawait plugin.init(context);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" failed to initialize:`, err);\n\t\t\t}\n\t\t}\n\n\t\t// Hook between init and onReady — lets the host rebuild schema/state\n\t\t// after all plugins have registered their specs but before plugins render.\n\t\tif (options.onBeforeReady) {\n\t\t\tawait options.onBeforeReady();\n\t\t}\n\n\t\t// Call onReady on all plugins after all init() calls have completed\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin?.onReady) continue;\n\t\t\ttry {\n\t\t\t\tawait plugin.onReady();\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in onReady:`, err);\n\t\t\t}\n\t\t}\n\n\t\tthis.initialized = true;\n\t\tthis.initializing = false;\n\t}\n\n\t/** Notifies all plugins of a state change, in init order. */\n\tnotifyStateChange(oldState: EditorState, newState: EditorState, tr: Transaction): void {\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin?.onStateChange) continue;\n\t\t\ttry {\n\t\t\t\tplugin.onStateChange(oldState, newState, tr);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in onStateChange:`, err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Collects and merges decorations from all plugins. */\n\tcollectDecorations(state: EditorState, tr?: Transaction): DecorationSet {\n\t\tlet result: DecorationSet = DecorationSet.empty;\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin?.decorations) continue;\n\t\t\ttry {\n\t\t\t\tconst decos = plugin.decorations(state, tr);\n\t\t\t\tif (!decos.isEmpty) {\n\t\t\t\t\tresult = result.merge(decos);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in decorations():`, err);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Dispatches a transaction through the middleware chain, then calls the final dispatch.\n\t * If no middleware is registered, calls finalDispatch directly.\n\t */\n\tdispatchWithMiddleware(\n\t\ttr: Transaction,\n\t\tstate: EditorState,\n\t\tfinalDispatch: (tr: Transaction) => void,\n\t): void {\n\t\tif (this.middlewares.length === 0) {\n\t\t\tfinalDispatch(tr);\n\t\t\treturn;\n\t\t}\n\n\t\tconst sorted = this.getSortedMiddleware();\n\t\tlet index = 0;\n\t\tlet dispatched = false;\n\n\t\tconst next: MiddlewareNext = (currentTr) => {\n\t\t\tif (index < sorted.length) {\n\t\t\t\tconst entry = sorted[index++];\n\t\t\t\tif (!entry) return;\n\t\t\t\tlet called = false;\n\t\t\t\tconst guardedNext: MiddlewareNext = (tr) => {\n\t\t\t\t\tif (called) return;\n\t\t\t\t\tcalled = true;\n\t\t\t\t\tnext(tr);\n\t\t\t\t};\n\t\t\t\ttry {\n\t\t\t\t\tentry.middleware(currentTr, state, guardedNext);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(`[PluginManager] Middleware \"${entry.name}\" error:`, err);\n\t\t\t\t\tguardedNext(currentTr);\n\t\t\t\t}\n\t\t\t} else if (!dispatched) {\n\t\t\t\tdispatched = true;\n\t\t\t\tfinalDispatch(currentTr);\n\t\t\t}\n\t\t};\n\n\t\tnext(tr);\n\t}\n\n\t/** Returns whether a named command can be executed (registered and not blocked by readonly). */\n\tcanExecuteCommand(name: string): boolean {\n\t\tconst entry = this.commands.get(name);\n\t\tif (!entry) return false;\n\t\tif (this.readOnly && !entry.readonlyAllowed) return false;\n\t\treturn true;\n\t}\n\n\t/** Executes a named command. Returns false if command not found or editor is read-only. */\n\texecuteCommand(name: string): boolean {\n\t\tconst entry = this.commands.get(name);\n\t\tif (!entry) return false;\n\t\tif (this.readOnly && !entry.readonlyAllowed) return false;\n\n\t\tconst enableBypass: boolean = this.readOnly && entry.readonlyAllowed;\n\t\tif (enableBypass) this.readonlyBypassActive = true;\n\t\ttry {\n\t\t\treturn entry.handler();\n\t\t} catch (err) {\n\t\t\tconsole.error(`[PluginManager] Command \"${name}\" error:`, err);\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tif (enableBypass) this.readonlyBypassActive = false;\n\t\t}\n\t}\n\n\t/** Returns true when a readonlyAllowed command is currently executing. */\n\tisReadonlyBypassed(): boolean {\n\t\treturn this.readonlyBypassActive;\n\t}\n\n\t/** Configures a plugin at runtime via onConfigure(). */\n\tconfigurePlugin(pluginId: string, config: PluginConfig): void {\n\t\tconst plugin = this.plugins.get(pluginId);\n\t\tif (!plugin) {\n\t\t\tthrow new Error(`Plugin \"${pluginId}\" not found.`);\n\t\t}\n\t\tif (!plugin.onConfigure) return;\n\t\ttry {\n\t\t\tplugin.onConfigure(config);\n\t\t} catch (err) {\n\t\t\tconsole.error(`[PluginManager] Plugin \"${pluginId}\" error in onConfigure:`, err);\n\t\t}\n\t}\n\n\t/** Returns the current read-only state. */\n\tisReadOnly(): boolean {\n\t\treturn this.readOnly;\n\t}\n\n\t/** Updates read-only state and notifies all plugins. */\n\tsetReadOnly(readonly: boolean): void {\n\t\tif (this.readOnly === readonly) return;\n\t\tthis.readOnly = readonly;\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin?.onReadOnlyChange) continue;\n\t\t\ttry {\n\t\t\t\tplugin.onReadOnlyChange(readonly);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in onReadOnlyChange:`, err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Returns all registered plugin IDs. */\n\tgetPluginIds(): string[] {\n\t\treturn [...this.plugins.keys()];\n\t}\n\n\t/** Returns the middleware chain in execution order, for debugging and introspection. */\n\tgetMiddlewareChain(): readonly MiddlewareInfo[] {\n\t\treturn this.getSortedMiddleware().map((entry) => ({\n\t\t\tname: entry.name,\n\t\t\tpriority: entry.priority,\n\t\t\tpluginId: entry.pluginId,\n\t\t}));\n\t}\n\n\t/** Gets a plugin by ID. */\n\tget(id: string): Plugin | undefined {\n\t\treturn this.plugins.get(id);\n\t}\n\n\t/** Gets a registered service by typed key. */\n\tgetService<T>(key: ServiceKey<T>): T | undefined {\n\t\treturn this.services.get(key.id) as T | undefined;\n\t}\n\n\t/** Subscribes to a plugin event from outside the plugin system. Returns an unsubscribe function. */\n\tonEvent<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void {\n\t\treturn this.eventBus.on(key, callback);\n\t}\n\n\t/** Returns all plugin-registered stylesheets. */\n\tgetPluginStyleSheets(): readonly CSSStyleSheet[] {\n\t\treturn this.pluginStyleSheets;\n\t}\n\n\t/** Destroys all plugins in reverse init order. */\n\tasync destroy(): Promise<void> {\n\t\tconst reversed = [...this.initOrder].reverse();\n\t\tfor (const id of reversed) {\n\t\t\tawait this.destroyPlugin(id);\n\t\t}\n\t\tthis.plugins.clear();\n\t\tthis.commands.clear();\n\t\tthis.services.clear();\n\t\tthis.middlewares.length = 0;\n\t\tthis.middlewareSorted = null;\n\t\tthis.pluginStyleSheets.length = 0;\n\t\tthis.eventBus.clear();\n\t\tthis.registrations.clear();\n\t\tthis.schemaRegistry.clear();\n\t\tthis.keymapRegistry.clear();\n\t\tthis.inputRuleRegistry.clear();\n\t\tthis.fileHandlerRegistry.clear();\n\t\tthis.nodeViewRegistry.clear();\n\t\tthis.toolbarRegistry.clear();\n\t\tthis.blockTypePickerRegistry.clear();\n\t\tthis.initOrder = [];\n\t\tthis.initialized = false;\n\t}\n\n\t// --- Private ---\n\n\tprivate async destroyPlugin(id: string): Promise<void> {\n\t\tconst plugin = this.plugins.get(id);\n\t\tif (plugin?.destroy) {\n\t\t\ttry {\n\t\t\t\tawait plugin.destroy();\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in destroy:`, err);\n\t\t\t}\n\t\t}\n\t\tthis.cleanupRegistrations(id);\n\t}\n\n\tprivate cleanupRegistrations(id: string): void {\n\t\tconst reg = this.registrations.get(id);\n\t\tif (!reg) return;\n\n\t\tfor (const name of reg.commands) this.commands.delete(name);\n\t\tfor (const serviceId of reg.services) this.services.delete(serviceId);\n\t\tfor (const entry of reg.middlewares) {\n\t\t\tconst idx = this.middlewares.indexOf(entry);\n\t\t\tif (idx !== -1) this.middlewares.splice(idx, 1);\n\t\t}\n\t\tfor (const unsub of reg.unsubscribers) unsub();\n\n\t\t// Clean up schema registrations\n\t\tfor (const type of reg.nodeSpecs) this.schemaRegistry.removeNodeSpec(type);\n\t\tfor (const type of reg.markSpecs) this.schemaRegistry.removeMarkSpec(type);\n\t\tfor (const type of reg.inlineNodeSpecs) {\n\t\t\tthis.schemaRegistry.removeInlineNodeSpec(type);\n\t\t}\n\n\t\t// Clean up focused registries\n\t\tfor (const type of reg.nodeViews) this.nodeViewRegistry.removeNodeView(type);\n\t\tfor (const keymap of reg.keymaps) this.keymapRegistry.removeKeymap(keymap);\n\t\tfor (const rule of reg.inputRules) this.inputRuleRegistry.removeInputRule(rule);\n\t\tfor (const itemId of reg.toolbarItems) this.toolbarRegistry.removeToolbarItem(itemId);\n\t\tfor (const handler of reg.fileHandlers) {\n\t\t\tthis.fileHandlerRegistry.removeFileHandler(handler);\n\t\t}\n\t\tfor (const entryId of reg.blockTypePickerEntries) {\n\t\t\tthis.blockTypePickerRegistry.removeBlockTypePickerEntry(entryId);\n\t\t}\n\t\tfor (const sheet of reg.stylesheets) {\n\t\t\tconst idx = this.pluginStyleSheets.indexOf(sheet);\n\t\t\tif (idx !== -1) this.pluginStyleSheets.splice(idx, 1);\n\t\t}\n\n\t\tthis.middlewareSorted = null;\n\t\tthis.registrations.delete(id);\n\t}\n\n\tprivate getSortedMiddleware(): MiddlewareEntry[] {\n\t\tif (!this.middlewareSorted) {\n\t\t\tthis.middlewareSorted = [...this.middlewares].sort((a, b) => a.priority - b.priority);\n\t\t}\n\t\treturn this.middlewareSorted;\n\t}\n\n\tprivate createContext(pluginId: string, options: PluginManagerInitOptions): PluginContext {\n\t\tconst reg: PluginRegistrations = {\n\t\t\tcommands: [],\n\t\t\tservices: [],\n\t\t\tmiddlewares: [],\n\t\t\tunsubscribers: [],\n\t\t\tnodeSpecs: [],\n\t\t\tmarkSpecs: [],\n\t\t\tinlineNodeSpecs: [],\n\t\t\tnodeViews: [],\n\t\t\tkeymaps: [],\n\t\t\tinputRules: [],\n\t\t\ttoolbarItems: [],\n\t\t\tfileHandlers: [],\n\t\t\tblockTypePickerEntries: [],\n\t\t\tstylesheets: [],\n\t\t};\n\t\tthis.registrations.set(pluginId, reg);\n\n\t\tconst pluginEventBus: PluginEventBus = {\n\t\t\temit: (key, payload) => this.eventBus.emit(key, payload),\n\t\t\ton: (key, callback) => {\n\t\t\t\tconst unsub = this.eventBus.on(key, callback);\n\t\t\t\treg.unsubscribers.push(unsub);\n\t\t\t\treturn unsub;\n\t\t\t},\n\t\t\toff: (key, callback) => this.eventBus.off(key, callback),\n\t\t};\n\n\t\treturn {\n\t\t\tgetState: options.getState,\n\t\t\tdispatch: options.dispatch,\n\t\t\tgetContainer: options.getContainer,\n\t\t\tgetPluginContainer: options.getPluginContainer,\n\t\t\tisReadOnly: () => this.readOnly,\n\n\t\t\tregisterCommand: (name: string, handler: CommandHandler, options?: CommandOptions) => {\n\t\t\t\tif (this.commands.has(name)) {\n\t\t\t\t\tconst existing = this.commands.get(name);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Command \"${name}\" is already registered by plugin \"${existing?.pluginId}\".`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst readonlyAllowed: boolean = options?.readonlyAllowed ?? false;\n\t\t\t\tthis.commands.set(name, { name, handler, pluginId, readonlyAllowed });\n\t\t\t\treg.commands.push(name);\n\t\t\t},\n\n\t\t\texecuteCommand: (name: string) => this.executeCommand(name),\n\n\t\t\tgetEventBus: () => pluginEventBus,\n\n\t\t\tregisterMiddleware: (middleware: TransactionMiddleware, options?: MiddlewareOptions) => {\n\t\t\t\tconst name: string = options?.name ?? (middleware.name || 'anonymous');\n\t\t\t\tconst priority: number = options?.priority ?? DEFAULT_PRIORITY;\n\t\t\t\tconst entry: MiddlewareEntry = { name, pluginId, middleware, priority };\n\t\t\t\tthis.middlewares.push(entry);\n\t\t\t\treg.middlewares.push(entry);\n\t\t\t\tthis.middlewareSorted = null;\n\t\t\t},\n\n\t\t\tregisterService: <T>(key: ServiceKey<T>, service: T) => {\n\t\t\t\tif (this.services.has(key.id)) {\n\t\t\t\t\tthrow new Error(`Service \"${key.id}\" is already registered by another plugin.`);\n\t\t\t\t}\n\t\t\t\tthis.services.set(key.id, service);\n\t\t\t\treg.services.push(key.id);\n\t\t\t},\n\n\t\t\tgetService: <T>(key: ServiceKey<T>) => this.services.get(key.id) as T | undefined,\n\n\t\t\tupdateConfig: (config: PluginConfig) => {\n\t\t\t\tconst plugin = this.plugins.get(pluginId);\n\t\t\t\tif (plugin?.onConfigure) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tplugin.onConfigure(config);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.error(`[PluginManager] Plugin \"${pluginId}\" error in onConfigure:`, err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// --- Schema Extension Methods ---\n\n\t\t\tregisterNodeSpec: (spec) => {\n\t\t\t\tthis.schemaRegistry.registerNodeSpec(spec);\n\t\t\t\treg.nodeSpecs.push(spec.type);\n\t\t\t},\n\n\t\t\tregisterMarkSpec: (spec) => {\n\t\t\t\tthis.schemaRegistry.registerMarkSpec(spec);\n\t\t\t\treg.markSpecs.push(spec.type);\n\t\t\t},\n\n\t\t\tregisterNodeView: (type, factory) => {\n\t\t\t\tthis.nodeViewRegistry.registerNodeView(type, factory);\n\t\t\t\treg.nodeViews.push(type);\n\t\t\t},\n\n\t\t\tregisterKeymap: (keymap: Keymap, options?: KeymapOptions) => {\n\t\t\t\tthis.keymapRegistry.registerKeymap(keymap, options);\n\t\t\t\treg.keymaps.push(keymap);\n\t\t\t},\n\n\t\t\tregisterInputRule: (rule) => {\n\t\t\t\tthis.inputRuleRegistry.registerInputRule(rule);\n\t\t\t\treg.inputRules.push(rule);\n\t\t\t},\n\n\t\t\tregisterToolbarItem: (item) => {\n\t\t\t\tthis.toolbarRegistry.registerToolbarItem(item, pluginId);\n\t\t\t\treg.toolbarItems.push(item.id);\n\t\t\t},\n\n\t\t\tregisterInlineNodeSpec: (spec) => {\n\t\t\t\tthis.schemaRegistry.registerInlineNodeSpec(spec);\n\t\t\t\treg.inlineNodeSpecs.push(spec.type);\n\t\t\t},\n\n\t\t\tregisterFileHandler: (pattern, handler) => {\n\t\t\t\tthis.fileHandlerRegistry.registerFileHandler(pattern, handler);\n\t\t\t\treg.fileHandlers.push(handler);\n\t\t\t},\n\n\t\t\tregisterBlockTypePickerEntry: (entry) => {\n\t\t\t\tthis.blockTypePickerRegistry.registerBlockTypePickerEntry(entry);\n\t\t\t\treg.blockTypePickerEntries.push(entry.id);\n\t\t\t},\n\n\t\t\tgetSchemaRegistry: () => this.schemaRegistry,\n\t\t\tgetKeymapRegistry: () => this.keymapRegistry,\n\t\t\tgetInputRuleRegistry: () => this.inputRuleRegistry,\n\t\t\tgetFileHandlerRegistry: () => this.fileHandlerRegistry,\n\t\t\tgetNodeViewRegistry: () => this.nodeViewRegistry,\n\t\t\tgetToolbarRegistry: () => this.toolbarRegistry,\n\t\t\tgetBlockTypePickerRegistry: () => this.blockTypePickerRegistry,\n\n\t\t\tregisterStyleSheet: (css: string) => {\n\t\t\t\tconst sheet: CSSStyleSheet = new CSSStyleSheet();\n\t\t\t\tsheet.replaceSync(css);\n\t\t\t\tthis.pluginStyleSheets.push(sheet);\n\t\t\t\treg.stylesheets.push(sheet);\n\t\t\t},\n\n\t\t\tannounce: (text: string) => {\n\t\t\t\toptions.announce?.(text);\n\t\t\t},\n\n\t\t\thasAnnouncement: () => options.hasAnnouncement?.() ?? false,\n\t\t};\n\t}\n\n\t/**\n\t * Resolves plugin initialization order via topological sort + priority.\n\t * Throws on dependency cycles or missing dependencies.\n\t */\n\tprivate resolveOrder(): string[] {\n\t\tconst ids = [...this.plugins.keys()];\n\n\t\t// Validate dependencies exist\n\t\tfor (const id of ids) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin) continue;\n\t\t\tfor (const dep of plugin.dependencies ?? []) {\n\t\t\t\tif (!this.plugins.has(dep)) {\n\t\t\t\t\tthrow new Error(`Plugin \"${id}\" depends on \"${dep}\", which is not registered.`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Topological sort (Kahn's algorithm)\n\t\tconst inDegree = new Map<string, number>();\n\t\tconst dependents = new Map<string, string[]>();\n\n\t\tfor (const id of ids) {\n\t\t\tinDegree.set(id, 0);\n\t\t\tdependents.set(id, []);\n\t\t}\n\n\t\tfor (const id of ids) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tconst deps = plugin?.dependencies ?? [];\n\t\t\tinDegree.set(id, deps.length);\n\t\t\tfor (const dep of deps) {\n\t\t\t\tconst depList = dependents.get(dep);\n\t\t\t\tif (depList) depList.push(id);\n\t\t\t}\n\t\t}\n\n\t\tconst queue: string[] = [];\n\t\tfor (const [id, deg] of inDegree) {\n\t\t\tif (deg === 0) queue.push(id);\n\t\t}\n\n\t\tconst sorted: string[] = [];\n\t\twhile (queue.length > 0) {\n\t\t\tqueue.sort((a, b) => {\n\t\t\t\tconst pa = this.plugins.get(a)?.priority ?? DEFAULT_PRIORITY;\n\t\t\t\tconst pb = this.plugins.get(b)?.priority ?? DEFAULT_PRIORITY;\n\t\t\t\treturn pa - pb;\n\t\t\t});\n\n\t\t\tconst id = queue.shift();\n\t\t\tif (!id) break;\n\t\t\tsorted.push(id);\n\n\t\t\tfor (const dep of dependents.get(id) ?? []) {\n\t\t\t\tconst newDeg = (inDegree.get(dep) ?? 0) - 1;\n\t\t\t\tinDegree.set(dep, newDeg);\n\t\t\t\tif (newDeg === 0) queue.push(dep);\n\t\t\t}\n\t\t}\n\n\t\tif (sorted.length !== ids.length) {\n\t\t\tconst missing = ids.filter((id) => !sorted.includes(id));\n\t\t\tthrow new Error(`Circular dependency detected among plugins: ${missing.join(', ')}`);\n\t\t}\n\n\t\treturn sorted;\n\t}\n}\n","/** Locale interface and default English locale for the PrintPlugin. */\n\n// --- Locale Interface ---\n\nexport interface PrintLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n\treadonly printingAnnouncement: string;\n}\n\n// --- Default English Locale ---\n\nexport const PRINT_LOCALE_EN: PrintLocale = {\n\tlabel: 'Print',\n\ttooltip: (shortcut: string) => `Print (${shortcut})`,\n\tprintingAnnouncement: 'Printing',\n};\n\n// --- German Locale ---\n\nexport const PRINT_LOCALE_DE: PrintLocale = {\n\tlabel: 'Drucken',\n\ttooltip: (shortcut: string) => `Drucken (${shortcut})`,\n\tprintingAnnouncement: 'Druckvorgang',\n};\n\n// --- Spanish Locale ---\n\nexport const PRINT_LOCALE_ES: PrintLocale = {\n\tlabel: 'Imprimir',\n\ttooltip: (shortcut: string) => `Imprimir (${shortcut})`,\n\tprintingAnnouncement: 'Imprimiendo',\n};\n\n// --- French Locale ---\n\nexport const PRINT_LOCALE_FR: PrintLocale = {\n\tlabel: 'Imprimer',\n\ttooltip: (shortcut: string) => `Imprimer (${shortcut})`,\n\tprintingAnnouncement: 'Impression',\n};\n\n// --- Chinese (Simplified) Locale ---\n\nexport const PRINT_LOCALE_ZH: PrintLocale = {\n\tlabel: '打印',\n\ttooltip: (shortcut: string) => `打印 (${shortcut})`,\n\tprintingAnnouncement: '正在打印',\n};\n\n// --- Russian Locale ---\n\nexport const PRINT_LOCALE_RU: PrintLocale = {\n\tlabel: 'Печать',\n\ttooltip: (shortcut: string) => `Печать (${shortcut})`,\n\tprintingAnnouncement: 'Печать',\n};\n\n// --- Arabic Locale ---\n\nexport const PRINT_LOCALE_AR: PrintLocale = {\n\tlabel: 'طباعة',\n\ttooltip: (shortcut: string) => `طباعة (${shortcut})`,\n\tprintingAnnouncement: 'جارٍ الطباعة',\n};\n\n// --- Hindi Locale ---\n\nexport const PRINT_LOCALE_HI: PrintLocale = {\n\tlabel: 'प्रिंट',\n\ttooltip: (shortcut: string) => `प्रिंट (${shortcut})`,\n\tprintingAnnouncement: 'प्रिंट हो रहा है',\n};\n\n// --- Locale Map ---\n\nexport const PRINT_LOCALES: Record<string, PrintLocale> = {\n\ten: PRINT_LOCALE_EN,\n\tde: PRINT_LOCALE_DE,\n\tes: PRINT_LOCALE_ES,\n\tfr: PRINT_LOCALE_FR,\n\tzh: PRINT_LOCALE_ZH,\n\tru: PRINT_LOCALE_RU,\n\tar: PRINT_LOCALE_AR,\n\thi: PRINT_LOCALE_HI,\n};\n","/**\n * Prepares editor content for print output.\n * Clones the DOM, sanitizes interactive attributes, applies block filters,\n * and inserts header/footer elements.\n */\n\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Deep-clones the .notectl-content element from the editor container. */\nexport function cloneContent(container: HTMLElement): HTMLElement {\n\tconst content: HTMLElement | null = container.querySelector('.notectl-content');\n\tconst source: HTMLElement = content ?? container;\n\treturn source.cloneNode(true) as HTMLElement;\n}\n\n/** Sanitizes the cloned content for print: removes interactive attributes and selection styling. */\nexport function sanitize(clone: HTMLElement): void {\n\t// Remove contenteditable from the root\n\tclone.removeAttribute('contenteditable');\n\n\t// Remove selection-related CSS classes\n\tconst selectionClasses: readonly string[] = ['notectl-node-selected', 'notectl-content--empty'];\n\tfor (const cls of selectionClasses) {\n\t\tclone.classList.remove(cls);\n\t\tfor (const el of clone.querySelectorAll(`.${cls}`)) {\n\t\t\tel.classList.remove(cls);\n\t\t}\n\t}\n\n\t// Remove data-placeholder to avoid showing placeholder in print\n\tclone.removeAttribute('data-placeholder');\n}\n\n/** Removes excluded block types and applies page-break-before to configured block types. */\nexport function applyBlockFilters(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.excludeBlockTypes) {\n\t\tfor (const type of options.excludeBlockTypes) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tel.remove();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (options.pageBreakBefore) {\n\t\tfor (const type of options.pageBreakBefore) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\t(el as HTMLElement).style.breakBefore = 'page';\n\t\t\t\t(el as HTMLElement).style.pageBreakBefore = 'always';\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Resolves a header/footer value to an HTML string. */\nfunction resolveContent(value: string | (() => string)): string {\n\treturn typeof value === 'function' ? value() : value;\n}\n\n/** Inserts header and footer elements into the cloned content. */\nexport function insertHeaderFooter(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.header) {\n\t\tconst headerEl: HTMLDivElement = document.createElement('div');\n\t\theaderEl.className = 'notectl-print-header';\n\t\theaderEl.innerHTML = resolveContent(options.header);\n\t\tclone.insertBefore(headerEl, clone.firstChild);\n\t}\n\n\tif (options.footer) {\n\t\tconst footerEl: HTMLDivElement = document.createElement('div');\n\t\tfooterEl.className = 'notectl-print-footer';\n\t\tfooterEl.innerHTML = resolveContent(options.footer);\n\t\tclone.appendChild(footerEl);\n\t}\n}\n\n/** Orchestrates all content preparation steps. Returns a ready-to-print DOM element. */\nexport function prepare(container: HTMLElement, options: PrintOptions): HTMLElement {\n\tconst clone: HTMLElement = cloneContent(container);\n\tsanitize(clone);\n\tapplyBlockFilters(clone, options);\n\tinsertHeaderFooter(clone, options);\n\treturn clone;\n}\n","/**\n * Paper size definitions and dimension helpers.\n * Used by PaperLayoutController for WYSIWYG page layout\n * and by PrintStyleCollector for @page CSS rules.\n */\n\n/** Conversion factor: 1mm = 96/25.4 px at CSS reference pixel (96 DPI). */\nconst MM_TO_PX: number = 96 / 25.4;\n\n/** Physical dimensions of a paper size. */\nexport interface PaperDimensions {\n\treadonly widthMm: number;\n\treadonly heightMm: number;\n\treadonly widthPx: number;\n\treadonly heightPx: number;\n}\n\n/** Available paper size presets. */\nexport const PaperSize = {\n\tDINA4: 'din-a4',\n\tDINA5: 'din-a5',\n\tUSLetter: 'us-letter',\n\tUSLegal: 'us-legal',\n} as const;\nexport type PaperSize = (typeof PaperSize)[keyof typeof PaperSize];\n\n/** Rounds to nearest integer for pixel dimensions. */\nfunction mmToPx(mm: number): number {\n\treturn Math.round(mm * MM_TO_PX);\n}\n\n/** Lookup table for paper dimensions. */\nconst PAPER_DIMENSIONS: ReadonlyMap<PaperSize, PaperDimensions> = new Map<\n\tPaperSize,\n\tPaperDimensions\n>([\n\t[PaperSize.DINA4, { widthMm: 210, heightMm: 297, widthPx: mmToPx(210), heightPx: mmToPx(297) }],\n\t[PaperSize.DINA5, { widthMm: 148, heightMm: 210, widthPx: mmToPx(148), heightPx: mmToPx(210) }],\n\t[\n\t\tPaperSize.USLetter,\n\t\t{ widthMm: 215.9, heightMm: 279.4, widthPx: mmToPx(215.9), heightPx: mmToPx(279.4) },\n\t],\n\t[\n\t\tPaperSize.USLegal,\n\t\t{ widthMm: 215.9, heightMm: 355.6, widthPx: mmToPx(215.9), heightPx: mmToPx(355.6) },\n\t],\n]);\n\n/** CSS @page size keywords for each paper size. */\nconst CSS_SIZE_KEYWORDS: ReadonlyMap<PaperSize, string> = new Map<PaperSize, string>([\n\t[PaperSize.DINA4, 'A4'],\n\t[PaperSize.DINA5, 'A5'],\n\t[PaperSize.USLetter, 'letter'],\n\t[PaperSize.USLegal, 'legal'],\n]);\n\n/** Returns the physical and pixel dimensions for a paper size. */\nexport function getPaperDimensions(size: PaperSize): PaperDimensions {\n\tconst dims: PaperDimensions | undefined = PAPER_DIMENSIONS.get(size);\n\tif (!dims) {\n\t\tthrow new Error(`Unknown paper size: ${size}`);\n\t}\n\treturn dims;\n}\n\n/**\n * Document margin constants for paper mode (in px).\n * These define the content padding inside the paper surface in the editor,\n * and become @page margins in print output to ensure WYSIWYG fidelity.\n */\nexport const PAPER_MARGIN_TOP_PX: number = 48;\nexport const PAPER_MARGIN_HORIZONTAL_PX: number = 56;\nexport const PAPER_VIEWPORT_PADDING_PX: number = 24;\n\n/** Type guard: returns true if the value is a valid PaperSize string. */\nexport function isValidPaperSize(value: string): value is PaperSize {\n\treturn (Object.values(PaperSize) as string[]).includes(value);\n}\n\n/** Returns the CSS @page size keyword (e.g. 'A4', 'letter') for a paper size. */\nexport function getPaperCSSSize(size: PaperSize): string {\n\tconst keyword: string | undefined = CSS_SIZE_KEYWORDS.get(size);\n\tif (!keyword) {\n\t\tthrow new Error(`Unknown paper size: ${size}`);\n\t}\n\treturn keyword;\n}\n","/**\n * Type definitions, service keys, and event keys for the PrintPlugin.\n */\n\nimport type { PaperSize } from '../../editor/PaperSize.js';\nimport type { NodeTypeName } from '../../model/TypeBrands.js';\nimport { EventKey, ServiceKey } from '../Plugin.js';\n\n// --- Print Options ---\n\nexport interface PrintOptions {\n\t/** Page title shown in the browser print header. */\n\treadonly title?: string;\n\n\t/** Additional CSS appended to the print stylesheet. */\n\treadonly customCSS?: string;\n\n\t/**\n\t * Header HTML inserted once at the top of the print document.\n\t * For repeating per-page headers, use toHTML() with server-side PDF generation.\n\t */\n\treadonly header?: string | (() => string);\n\n\t/**\n\t * Footer HTML inserted once at the bottom of the print document.\n\t * For repeating per-page footers, use toHTML() with server-side PDF generation.\n\t */\n\treadonly footer?: string | (() => string);\n\n\t/** Page margins as CSS value (e.g. '2cm'). */\n\treadonly margin?: string;\n\n\t/** Force page break before these block types. */\n\treadonly pageBreakBefore?: readonly NodeTypeName[];\n\n\t/** Exclude these block types from print output. */\n\treadonly excludeBlockTypes?: readonly NodeTypeName[];\n\n\t/**\n\t * Whether to preserve background colors and images in print output.\n\t * Defaults to `true` (WYSIWYG). Set to `false` to let the browser strip\n\t * backgrounds (e.g. to save ink).\n\t */\n\treadonly printBackground?: boolean;\n\n\t/** Page orientation. */\n\treadonly orientation?: 'portrait' | 'landscape';\n\n\t/** Paper size for @page CSS rule. When set, overrides the default A4 page size. */\n\treadonly paperSize?: PaperSize;\n}\n\n// --- Plugin Configuration ---\n\nexport interface PrintPluginConfig {\n\t/** Default options applied to every print() call. */\n\treadonly defaults?: PrintOptions;\n\n\t/** Keyboard shortcut (default: 'Mod-P'). */\n\treadonly keyBinding?: string;\n\n\t/** Show toolbar button (default: true). */\n\treadonly showToolbarItem?: boolean;\n\n\t/** Locale override for user-facing strings. */\n\treadonly locale?: import('./PrintLocale.js').PrintLocale;\n}\n\n// --- Service Interface ---\n\nexport interface PrintService {\n\t/** Prints the editor content with optional configuration. */\n\tprint(options?: PrintOptions): void;\n\n\t/** Generates print-ready HTML as a complete document string. */\n\ttoHTML(options?: PrintOptions): string;\n}\n\n// --- Service & Event Keys ---\n\nexport const PRINT_SERVICE_KEY: ServiceKey<PrintService> = new ServiceKey<PrintService>('print');\n\nexport const BEFORE_PRINT: EventKey<BeforePrintEvent> = new EventKey<BeforePrintEvent>(\n\t'print:before',\n);\n\nexport const AFTER_PRINT: EventKey<AfterPrintEvent> = new EventKey<AfterPrintEvent>('print:after');\n\n// --- Event Payloads ---\n\nexport interface BeforePrintEvent {\n\t/** Options can be mutated — EventBus passes by reference. */\n\toptions: PrintOptions;\n\t/** Set to true to cancel the print. */\n\tcancelled: boolean;\n}\n\nexport interface AfterPrintEvent {\n\t/** The generated HTML (read-only). */\n\treadonly html: string;\n}\n","/**\n * PrintPlugin: provides print functionality for the notectl editor.\n * Registers a command, keymap, toolbar item, and exposes a PrintService.\n * Orchestrator only — delegates all logic to PrintServiceImpl, PrintStyleCollector,\n * and PrintContentPreparer.\n */\n\nimport { resolvePluginLocale } from '../../i18n/resolvePluginLocale.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\nimport { PRINT_LOCALES, type PrintLocale } from './PrintLocale.js';\nimport { createPrintService } from './PrintServiceImpl.js';\nimport type { PrintOptions, PrintPluginConfig, PrintService } from './PrintTypes.js';\nimport { PRINT_SERVICE_KEY } from './PrintTypes.js';\n\nconst PRINT_ICON: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\">' +\n\t'<path d=\"M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3' +\n\t' 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z\"/>' +\n\t'</svg>';\n\n/** No-op fallback service for environments without ShadowRoot. */\nconst NOOP_SERVICE: PrintService = {\n\tprint(): void {},\n\ttoHTML(): string {\n\t\treturn '';\n\t},\n};\n\nexport class PrintPlugin implements Plugin {\n\treadonly id = 'print';\n\treadonly name = 'Print';\n\n\tprivate readonly config: PrintPluginConfig;\n\tprivate service: PrintService | null = null;\n\tprivate locale!: PrintLocale;\n\n\tconstructor(config?: PrintPluginConfig) {\n\t\tthis.config = config ?? {};\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.locale = resolvePluginLocale(PRINT_LOCALES, context, this.config.locale);\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tconst rootNode: Node = container.getRootNode();\n\n\t\tif (rootNode instanceof ShadowRoot) {\n\t\t\tconst host: HTMLElement = rootNode.host as HTMLElement;\n\t\t\tconst eventBus = context.getEventBus();\n\t\t\tthis.service = createPrintService(rootNode, host, container, eventBus);\n\t\t} else {\n\t\t\tthis.service = NOOP_SERVICE;\n\t\t}\n\n\t\tcontext.registerService(PRINT_SERVICE_KEY, this.service);\n\n\t\tconst defaults: PrintOptions = this.config.defaults ?? {};\n\t\tconst service: PrintService = this.service;\n\n\t\tconst printLocale = this.locale;\n\t\tcontext.registerCommand('print', () => {\n\t\t\tcontext.announce(printLocale.printingAnnouncement);\n\t\t\tservice.print(defaults);\n\t\t\treturn true;\n\t\t});\n\n\t\tconst keyBinding: string = this.config.keyBinding ?? 'Mod-P';\n\t\tcontext.registerKeymap({\n\t\t\t[keyBinding]: () => {\n\t\t\t\tcontext.executeCommand('print');\n\t\t\t\treturn true;\n\t\t\t},\n\t\t});\n\n\t\tif (this.config.showToolbarItem !== false) {\n\t\t\tconst shortcut: string = formatShortcut(keyBinding);\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: 'print',\n\t\t\t\tgroup: 'actions',\n\t\t\t\tlabel: this.locale.label,\n\t\t\t\ttooltip: this.locale.tooltip(shortcut),\n\t\t\t\ticon: PRINT_ICON,\n\t\t\t\tcommand: 'print',\n\t\t\t\tpriority: 900,\n\t\t\t});\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.service = null;\n\t}\n}\n","/**\n * PrintService implementation.\n * Handles the synchronous print flow: event emission, style collection,\n * content preparation, iframe creation, and cleanup.\n */\n\nimport type { PluginEventBus } from '../Plugin.js';\nimport { prepare } from './PrintContentPreparer.js';\nimport { collectAll } from './PrintStyleCollector.js';\nimport {\n\tAFTER_PRINT,\n\ttype AfterPrintEvent,\n\tBEFORE_PRINT,\n\ttype BeforePrintEvent,\n\ttype PrintOptions,\n\ttype PrintService,\n} from './PrintTypes.js';\n\n/** Escapes HTML special characters in a plain-text string. */\nfunction escapeHTML(text: string): string {\n\treturn text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\n/** Builds a complete HTML document string from CSS, body content, and title. */\nexport function buildHTMLDocument(\n\tcss: string,\n\tcontent: string,\n\ttitle: string,\n\tlang = 'en',\n): string {\n\tconst safeTitle: string = escapeHTML(title);\n\treturn [\n\t\t'<!DOCTYPE html>',\n\t\t`<html lang=\"${lang}\">`,\n\t\t'<head>',\n\t\t`<meta charset=\"utf-8\">`,\n\t\t`<title>${safeTitle}</title>`,\n\t\t`<style>${css}</style>`,\n\t\t'</head>',\n\t\t`<body>${content}</body>`,\n\t\t'</html>',\n\t].join('\\n');\n}\n\n/** Creates and returns the PrintService implementation. */\nexport function createPrintService(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\tcontainer: HTMLElement,\n\teventBus: PluginEventBus,\n): PrintService {\n\tfunction mergeOptions(options?: PrintOptions): PrintOptions {\n\t\treturn options ?? {};\n\t}\n\n\tfunction executePrint(options: PrintOptions): string | null {\n\t\t// 1. Emit BEFORE_PRINT — listeners can mutate options or cancel\n\t\tconst beforeEvent: BeforePrintEvent = {\n\t\t\toptions,\n\t\t\tcancelled: false,\n\t\t};\n\t\teventBus.emit(BEFORE_PRINT, beforeEvent);\n\n\t\tif (beforeEvent.cancelled) return null;\n\n\t\tconst finalOptions: PrintOptions = beforeEvent.options;\n\n\t\t// 2. Collect styles\n\t\tconst css: string = collectAll(shadowRoot, host, finalOptions);\n\n\t\t// 3. Prepare content\n\t\tconst clone: HTMLElement = prepare(container, finalOptions);\n\t\tconst contentHTML: string = clone.outerHTML;\n\n\t\t// 4. Build HTML document\n\t\tconst title: string = finalOptions.title ?? '';\n\t\tconst lang: string =\n\t\t\thost.closest('[lang]')?.getAttribute('lang') ?? (document.documentElement.lang || 'en');\n\t\tconst html: string = buildHTMLDocument(css, contentHTML, title, lang);\n\n\t\t// 5. Emit AFTER_PRINT\n\t\tconst afterEvent: AfterPrintEvent = { html };\n\t\teventBus.emit(AFTER_PRINT, afterEvent);\n\n\t\treturn html;\n\t}\n\n\treturn {\n\t\tprint(options?: PrintOptions): void {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\tconst html: string | null = executePrint(resolved);\n\t\t\tif (!html) return;\n\n\t\t\t// Create hidden iframe\n\t\t\tconst iframe: HTMLIFrameElement = document.createElement('iframe');\n\t\t\tiframe.style.cssText = 'position:fixed;left:-9999px;width:0;height:0;border:none;';\n\t\t\tdocument.body.appendChild(iframe);\n\n\t\t\tconst iframeDoc: Document | null = iframe.contentDocument;\n\t\t\tif (!iframeDoc) {\n\t\t\t\tdocument.body.removeChild(iframe);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tiframeDoc.open();\n\t\t\tiframeDoc.write(html);\n\t\t\tiframeDoc.close();\n\n\t\t\tconst cleanup = (): void => {\n\t\t\t\tiframe.remove();\n\t\t\t};\n\n\t\t\t// Defer cleanup until print dialog closes\n\t\t\tif (iframe.contentWindow) {\n\t\t\t\tiframe.contentWindow.addEventListener('afterprint', cleanup, { once: true });\n\t\t\t\tiframe.contentWindow.print();\n\t\t\t} else {\n\t\t\t\tcleanup();\n\t\t\t}\n\t\t},\n\n\t\ttoHTML(options?: PrintOptions): string {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\treturn executePrint(resolved) ?? '';\n\t\t},\n\t};\n}\n","/**\n * Collects and aggregates CSS for print output.\n * Extracts adopted stylesheets, snapshots theme tokens, and generates print-specific CSS.\n */\n\nimport {\n\tPAPER_MARGIN_HORIZONTAL_PX,\n\tPAPER_MARGIN_TOP_PX,\n\tgetPaperCSSSize,\n} from '../../editor/PaperSize.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Extracts CSS text from all adopted stylesheets on a ShadowRoot. */\nexport function extractAdoptedStyles(shadowRoot: ShadowRoot): string {\n\tconst parts: string[] = [];\n\tfor (const sheet of shadowRoot.adoptedStyleSheets) {\n\t\tfor (const rule of sheet.cssRules) {\n\t\t\tparts.push(rule.cssText);\n\t\t}\n\t}\n\treturn parts.join('\\n');\n}\n\n/** Snapshots --notectl-* CSS custom properties from the host element into a :root block. */\nexport function snapshotThemeTokens(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst tokens: string[] = [];\n\n\tfor (let i = 0; i < computed.length; i++) {\n\t\tconst prop: string = computed[i] ?? '';\n\t\tif (prop.startsWith('--notectl-')) {\n\t\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\t\tif (value) {\n\t\t\t\ttokens.push(` ${prop}: ${value};`);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (tokens.length === 0) return '';\n\treturn `:root {\\n${tokens.join('\\n')}\\n}`;\n}\n\n/**\n * Snapshots computed typography from the host element into a `body` rule.\n * In the editor, typography is inherited from `:host` (shadow DOM).\n * The print iframe is a regular document where `:host` doesn't match,\n * so we must apply the same font/line-height explicitly.\n */\nexport function snapshotTypography(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst props: string[] = [\n\t\t'font-family',\n\t\t'font-size',\n\t\t'font-weight',\n\t\t'line-height',\n\t\t'letter-spacing',\n\t\t'word-spacing',\n\t\t'color',\n\t];\n\tconst rules: string[] = [' margin: 0;'];\n\tfor (const prop of props) {\n\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\tif (value) {\n\t\t\trules.push(` ${prop}: ${value};`);\n\t\t}\n\t}\n\treturn `body {\\n${rules.join('\\n')}\\n}`;\n}\n\n/** Generates print-specific CSS rules based on PrintOptions. */\nexport function generatePrintCSS(options: PrintOptions): string {\n\tconst parts: string[] = [];\n\n\t// @page rule\n\tconst pageProps: string[] = [];\n\tif (options.margin) {\n\t\tpageProps.push(` margin: ${options.margin};`);\n\t} else if (options.paperSize) {\n\t\t// WYSIWYG: zero @page margin so body = full paper width;\n\t\t// document margins are applied as content padding below.\n\t\tpageProps.push(' margin: 0;');\n\t}\n\tif (options.paperSize || options.orientation) {\n\t\tconst sizeKeyword: string = options.paperSize ? getPaperCSSSize(options.paperSize) : 'A4';\n\t\tconst sizeParts: string[] = [sizeKeyword];\n\t\tif (options.orientation) {\n\t\t\tsizeParts.push(options.orientation);\n\t\t}\n\t\tpageProps.push(` size: ${sizeParts.join(' ')};`);\n\t}\n\tif (pageProps.length > 0) {\n\t\tparts.push(`@page {\\n${pageProps.join('\\n')}\\n}`);\n\t}\n\n\t// WYSIWYG: apply paper-mode document margins to print content\n\tif (options.paperSize) {\n\t\tparts.push(\n\t\t\t`.notectl-content { padding: ${PAPER_MARGIN_TOP_PX}px ${PAPER_MARGIN_HORIZONTAL_PX}px !important; }`,\n\t\t);\n\t}\n\n\t// Print media rules\n\tconst printRules: string[] = [];\n\n\t// Hide non-printable elements\n\tprintRules.push('[data-notectl-no-print] { display: none !important; }');\n\n\t// Code blocks: preserve background, force wrapping\n\tprintRules.push(\n\t\t'.notectl-code-block { white-space: pre-wrap !important; ' +\n\t\t\t'word-break: break-all !important; page-break-inside: avoid; }',\n\t);\n\n\t// Images: avoid page breaks\n\tprintRules.push('img { page-break-inside: avoid; }');\n\n\t// Tables: avoid page breaks\n\tprintRules.push('.notectl-table { break-inside: avoid; }');\n\n\t// Preserve background colors and images in print output (WYSIWYG default).\n\t// Only omitted when the consumer explicitly opts out via printBackground: false.\n\tif (options.printBackground !== false) {\n\t\tprintRules.push(\n\t\t\t'* { -webkit-print-color-adjust: exact !important; ' +\n\t\t\t\t'print-color-adjust: exact !important; }',\n\t\t);\n\t}\n\n\tparts.push(`@media print {\\n ${printRules.join('\\n ')}\\n}`);\n\n\treturn parts.join('\\n\\n');\n}\n\n/** Collects all CSS needed for print: adopted styles, theme tokens, print CSS, and custom CSS. */\nexport function collectAll(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\toptions: PrintOptions,\n): string {\n\tconst parts: string[] = [];\n\n\tconst adopted: string = extractAdoptedStyles(shadowRoot);\n\tif (adopted) parts.push(adopted);\n\n\tconst theme: string = snapshotThemeTokens(host);\n\tif (theme) parts.push(theme);\n\n\t// WYSIWYG: snapshot host typography so the print iframe matches the editor.\n\t// In the editor, .notectl-content inherits font from :host (shadow DOM).\n\t// The print iframe is a regular document where :host doesn't apply.\n\tif (options.paperSize) {\n\t\tparts.push(snapshotTypography(host));\n\t}\n\n\tconst printCSS: string = generatePrintCSS(options);\n\tif (printCSS) parts.push(printCSS);\n\n\tif (options.customCSS) {\n\t\tparts.push(options.customCSS);\n\t}\n\n\treturn parts.join('\\n\\n');\n}\n","/**\n * Theme token types, built-in themes, and theme creation helpers.\n */\n\n/** Primitive color palette a theme defines. */\nexport interface ThemePrimitives {\n\treadonly background: string;\n\treadonly foreground: string;\n\treadonly mutedForeground: string;\n\treadonly border: string;\n\treadonly borderFocus: string;\n\treadonly primary: string;\n\treadonly primaryForeground: string;\n\treadonly primaryMuted: string;\n\treadonly surfaceRaised: string;\n\treadonly surfaceOverlay: string;\n\treadonly hoverBackground: string;\n\treadonly activeBackground: string;\n\treadonly danger: string;\n\treadonly dangerMuted: string;\n\treadonly success: string;\n\treadonly shadow: string;\n\treadonly focusRing: string;\n}\n\n/** Component-level toolbar overrides. */\nexport interface ThemeToolbar {\n\treadonly background: string;\n\treadonly borderColor: string;\n}\n\n/** Component-level code block overrides. */\nexport interface ThemeCodeBlock {\n\treadonly background: string;\n\treadonly foreground: string;\n\treadonly headerBackground: string;\n\treadonly headerForeground: string;\n\treadonly headerBorder: string;\n}\n\n/** Component-level tooltip overrides. */\nexport interface ThemeTooltip {\n\treadonly background: string;\n\treadonly foreground: string;\n}\n\n/** Full theme definition. */\nexport interface Theme {\n\treadonly name: string;\n\treadonly primitives: ThemePrimitives;\n\treadonly toolbar?: Partial<ThemeToolbar>;\n\treadonly codeBlock?: Partial<ThemeCodeBlock>;\n\treadonly tooltip?: Partial<ThemeTooltip>;\n}\n\n/** Partial custom theme — deeply partial for creating overrides. */\nexport interface PartialTheme {\n\treadonly name: string;\n\treadonly primitives?: Partial<ThemePrimitives>;\n\treadonly toolbar?: Partial<ThemeToolbar>;\n\treadonly codeBlock?: Partial<ThemeCodeBlock>;\n\treadonly tooltip?: Partial<ThemeTooltip>;\n}\n\n/** Built-in theme presets. */\nexport const ThemePreset = {\n\tLight: 'light',\n\tDark: 'dark',\n\tSystem: 'system',\n} as const;\nexport type ThemePreset = (typeof ThemePreset)[keyof typeof ThemePreset];\n\n/** Built-in light theme. */\nexport const LIGHT_THEME: Theme = {\n\tname: 'light',\n\tprimitives: {\n\t\tbackground: '#ffffff',\n\t\tforeground: '#1a1a1a',\n\t\tmutedForeground: '#666666',\n\t\tborder: '#d0d0d0',\n\t\tborderFocus: '#4a90d9',\n\t\tprimary: '#4a90d9',\n\t\tprimaryForeground: '#1a5fa0',\n\t\tprimaryMuted: '#d0e0f0',\n\t\tsurfaceRaised: '#f8f8f8',\n\t\tsurfaceOverlay: '#ffffff',\n\t\thoverBackground: '#e8e8e8',\n\t\tactiveBackground: '#d0e0f0',\n\t\tdanger: '#dc2626',\n\t\tdangerMuted: '#fee2e2',\n\t\tsuccess: '#1a8c1a',\n\t\tshadow: 'rgba(0, 0, 0, 0.15)',\n\t\tfocusRing: 'rgba(74, 144, 217, 0.2)',\n\t},\n\tcodeBlock: {\n\t\tbackground: '#f8fafc',\n\t\tforeground: '#334155',\n\t\theaderBackground: '#f1f5f9',\n\t\theaderForeground: '#64748b',\n\t\theaderBorder: '#e2e8f0',\n\t},\n\ttooltip: {\n\t\tbackground: '#1a1a1a',\n\t\tforeground: '#ffffff',\n\t},\n};\n\n/** Built-in dark theme. */\nexport const DARK_THEME: Theme = {\n\tname: 'dark',\n\tprimitives: {\n\t\tbackground: '#1e1e2e',\n\t\tforeground: '#cdd6f4',\n\t\tmutedForeground: '#7f849c',\n\t\tborder: '#45475a',\n\t\tborderFocus: '#89b4fa',\n\t\tprimary: '#89b4fa',\n\t\tprimaryForeground: '#89b4fa',\n\t\tprimaryMuted: 'rgba(137, 180, 250, 0.15)',\n\t\tsurfaceRaised: '#313244',\n\t\tsurfaceOverlay: '#313244',\n\t\thoverBackground: '#45475a',\n\t\tactiveBackground: 'rgba(137, 180, 250, 0.15)',\n\t\tdanger: '#f38ba8',\n\t\tdangerMuted: 'rgba(243, 139, 168, 0.15)',\n\t\tsuccess: '#a6e3a1',\n\t\tshadow: 'rgba(0, 0, 0, 0.4)',\n\t\tfocusRing: 'rgba(137, 180, 250, 0.25)',\n\t},\n\tcodeBlock: {\n\t\tbackground: '#11111b',\n\t\tforeground: '#cdd6f4',\n\t\theaderBackground: '#181825',\n\t\theaderForeground: '#7f849c',\n\t\theaderBorder: 'rgba(205, 214, 244, 0.08)',\n\t},\n\ttooltip: {\n\t\tbackground: '#585b70',\n\t\tforeground: '#cdd6f4',\n\t},\n};\n\n/** Creates a custom theme by extending a base theme with partial overrides. */\nexport function createTheme(base: Theme, overrides: PartialTheme): Theme {\n\treturn {\n\t\tname: overrides.name,\n\t\tprimitives: { ...base.primitives, ...overrides.primitives },\n\t\ttoolbar: overrides.toolbar ? { ...base.toolbar, ...overrides.toolbar } : base.toolbar,\n\t\tcodeBlock: overrides.codeBlock ? { ...base.codeBlock, ...overrides.codeBlock } : base.codeBlock,\n\t\ttooltip: overrides.tooltip ? { ...base.tooltip, ...overrides.tooltip } : base.tooltip,\n\t};\n}\n\n/** Resolves a ThemePreset string or Theme object to a full Theme. */\nexport function resolveTheme(theme: ThemePreset | Theme): Theme {\n\tif (typeof theme === 'object') return theme;\n\tswitch (theme) {\n\t\tcase ThemePreset.Light:\n\t\t\treturn LIGHT_THEME;\n\t\tcase ThemePreset.Dark:\n\t\t\treturn DARK_THEME;\n\t\tcase ThemePreset.System:\n\t\t\t// System is resolved externally via matchMedia; default to light.\n\t\t\treturn LIGHT_THEME;\n\t\tdefault:\n\t\t\treturn LIGHT_THEME;\n\t}\n}\n","/**\n * Theme engine — converts a Theme object into CSS custom properties.\n */\n\nimport type { Theme } from './ThemeTokens.js';\n\n/** Maps Theme fields to CSS custom property names. */\nconst VARIABLE_MAP: ReadonlyArray<readonly [string, string]> = [\n\t// Primitives\n\t['primitives.background', '--notectl-bg'],\n\t['primitives.foreground', '--notectl-fg'],\n\t['primitives.mutedForeground', '--notectl-fg-muted'],\n\t['primitives.border', '--notectl-border'],\n\t['primitives.borderFocus', '--notectl-border-focus'],\n\t['primitives.primary', '--notectl-primary'],\n\t['primitives.primaryForeground', '--notectl-primary-fg'],\n\t['primitives.primaryMuted', '--notectl-primary-muted'],\n\t['primitives.surfaceRaised', '--notectl-surface-raised'],\n\t['primitives.surfaceOverlay', '--notectl-surface-overlay'],\n\t['primitives.hoverBackground', '--notectl-hover-bg'],\n\t['primitives.activeBackground', '--notectl-active-bg'],\n\t['primitives.danger', '--notectl-danger'],\n\t['primitives.dangerMuted', '--notectl-danger-muted'],\n\t['primitives.success', '--notectl-success'],\n\t['primitives.shadow', '--notectl-shadow'],\n\t['primitives.focusRing', '--notectl-focus-ring'],\n\t// Component: toolbar\n\t['toolbar.background', '--notectl-toolbar-bg'],\n\t['toolbar.borderColor', '--notectl-toolbar-border'],\n\t// Component: codeBlock\n\t['codeBlock.background', '--notectl-code-block-bg'],\n\t['codeBlock.foreground', '--notectl-code-block-color'],\n\t['codeBlock.headerBackground', '--notectl-code-block-header-bg'],\n\t['codeBlock.headerForeground', '--notectl-code-block-header-color'],\n\t['codeBlock.headerBorder', '--notectl-code-block-header-border'],\n\t// Component: tooltip\n\t['tooltip.background', '--notectl-tooltip-bg'],\n\t['tooltip.foreground', '--notectl-tooltip-fg'],\n];\n\n/** Fallbacks for component tokens when not explicitly set. */\nconst COMPONENT_FALLBACKS: ReadonlyMap<string, string> = new Map([\n\t['--notectl-toolbar-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-toolbar-border', 'var(--notectl-border)'],\n\t['--notectl-code-block-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-code-block-color', 'var(--notectl-fg)'],\n\t['--notectl-code-block-header-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-code-block-header-color', 'var(--notectl-fg-muted)'],\n\t['--notectl-code-block-header-border', 'var(--notectl-border)'],\n\t['--notectl-tooltip-bg', 'var(--notectl-fg)'],\n\t['--notectl-tooltip-fg', 'var(--notectl-bg)'],\n]);\n\n/** Resolves a dotted path like 'primitives.background' from a Theme. */\nfunction resolvePath(theme: Theme, path: string): string | undefined {\n\tconst parts: string[] = path.split('.');\n\tlet current: unknown = theme;\n\tfor (const part of parts) {\n\t\tif (current === undefined || current === null) return undefined;\n\t\tif (typeof current !== 'object') return undefined;\n\t\tcurrent = (current as Record<string, unknown>)[part];\n\t}\n\treturn typeof current === 'string' ? current : undefined;\n}\n\n/** Generates CSS text with all theme custom properties on :host. */\nexport function generateThemeCSS(theme: Theme): string {\n\tconst lines: string[] = [':host {'];\n\n\tfor (const [path, cssVar] of VARIABLE_MAP) {\n\t\tconst value: string | undefined = resolvePath(theme, path);\n\t\tif (value !== undefined) {\n\t\t\tlines.push(`\\t${cssVar}: ${value};`);\n\t\t} else {\n\t\t\tconst fallback: string | undefined = COMPONENT_FALLBACKS.get(cssVar);\n\t\t\tif (fallback) {\n\t\t\t\tlines.push(`\\t${cssVar}: ${fallback};`);\n\t\t\t}\n\t\t}\n\t}\n\n\tlines.push('}');\n\treturn lines.join('\\n');\n}\n\n/** Creates a CSSStyleSheet populated with theme CSS variables. */\nexport function createThemeStyleSheet(theme: Theme): CSSStyleSheet {\n\tconst sheet: CSSStyleSheet = new CSSStyleSheet();\n\tsheet.replaceSync(generateThemeCSS(theme));\n\treturn sheet;\n}\n","/**\n * Supported locale identifiers for the notectl editor.\n * Use `Locale.BROWSER` to auto-detect from navigator.language.\n */\nexport const Locale = {\n\tEN: 'en',\n\tDE: 'de',\n\tES: 'es',\n\tFR: 'fr',\n\tZH: 'zh',\n\tRU: 'ru',\n\tAR: 'ar',\n\tHI: 'hi',\n\tBROWSER: 'browser',\n} as const;\n\nexport type Locale = (typeof Locale)[keyof typeof Locale];\n","/**\n * DocumentSerializer: converts an immutable Document into sanitized HTML.\n * Pure functions — operates on Document/SchemaRegistry, no class state.\n */\n\nimport DOMPurify from 'dompurify';\nimport { isNodeOfType } from '../model/AttrRegistry.js';\nimport type { BlockNode, Document, InlineNode, TextNode } from '../model/Document.js';\nimport {\n\tgetBlockChildren,\n\tgetInlineChildren,\n\tisInlineNode,\n\tisLeafBlock,\n\tisTextNode,\n\tmarkSetsEqual,\n} from '../model/Document.js';\nimport { escapeHTML } from '../model/HTMLUtils.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { buildMarkOrder, serializeMarksToHTML } from './MarkSerializer.js';\n\n/** Known-safe alignment values accepted by the serializer (defense-in-depth). */\nexport const VALID_ALIGNMENTS: ReadonlySet<string> = new Set([\n\t'left',\n\t'center',\n\t'right',\n\t'justify',\n]);\n\n/** Serializes a full document to sanitized HTML, wrapping list items in `<ul>`/`<ol>`. */\nexport function serializeDocumentToHTML(doc: Document, registry?: SchemaRegistry): string {\n\tconst html: string = serializeBlocks(doc.children, registry);\n\n\tconst allowedTags: string[] = registry ? registry.getAllowedTags() : ['p', 'br', 'div', 'span'];\n\tconst allowedAttrs: string[] = registry ? registry.getAllowedAttrs() : ['style'];\n\n\treturn DOMPurify.sanitize(html, {\n\t\tALLOWED_TAGS: allowedTags,\n\t\tALLOWED_ATTR: allowedAttrs,\n\t});\n}\n\n/** Serializes a sequence of blocks to HTML, grouping consecutive list items into wrappers. */\nfunction serializeBlocks(blocks: readonly BlockNode[], registry?: SchemaRegistry): string {\n\tconst parts: string[] = [];\n\tlet i = 0;\n\n\twhile (i < blocks.length) {\n\t\tconst block: BlockNode | undefined = blocks[i];\n\t\tif (!block) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isNodeOfType(block, 'list_item')) {\n\t\t\t// Collect consecutive list items\n\t\t\tconst listItems: BlockNode[] = [];\n\t\t\twhile (i < blocks.length) {\n\t\t\t\tconst item: BlockNode | undefined = blocks[i];\n\t\t\t\tif (!item || !isNodeOfType(item, 'list_item')) break;\n\t\t\t\tlistItems.push(item);\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tparts.push(serializeListGroup(listItems, registry));\n\t\t} else {\n\t\t\tparts.push(serializeBlock(block, registry));\n\t\t\ti++;\n\t\t}\n\t}\n\n\treturn parts.join('');\n}\n\n/**\n * Serializes a group of consecutive list items into properly nested `<ul>`/`<ol>` wrappers.\n * Uses a stack-based algorithm to handle indent-based nesting.\n * Produces valid HTML5: nested lists open *inside* the parent `<li>`.\n */\nfunction serializeListGroup(items: readonly BlockNode[], registry?: SchemaRegistry): string {\n\tconst parts: string[] = [];\n\tconst stack: { tag: string; indent: number }[] = [];\n\n\tfor (let idx = 0; idx < items.length; idx++) {\n\t\tconst item: BlockNode | undefined = items[idx];\n\t\tif (!item) continue;\n\n\t\tconst listType: string = (item.attrs?.listType as string) ?? 'bullet';\n\t\tconst indent: number = (item.attrs?.indent as number) ?? 0;\n\t\tconst tag: string = listType === 'ordered' ? 'ol' : 'ul';\n\n\t\t// Pop wrapper levels that are deeper than current indent,\n\t\t// or at the same level when the tag type changes\n\t\twhile (stack.length > 0) {\n\t\t\tconst top: { tag: string; indent: number } | undefined = stack[stack.length - 1];\n\t\t\tif (!top) break;\n\n\t\t\tif (top.indent > indent) {\n\t\t\t\tparts.push(`</${top.tag}></li>`);\n\t\t\t\tstack.pop();\n\t\t\t} else if (top.indent === indent && top.tag !== tag) {\n\t\t\t\tparts.push(`</${top.tag}></li>`);\n\t\t\t\tstack.pop();\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (stack.length === 0) {\n\t\t\tparts.push(`<${tag}>`);\n\t\t\tstack.push({ tag, indent });\n\t\t} else {\n\t\t\tconst top: { tag: string; indent: number } | undefined = stack[stack.length - 1];\n\t\t\tif (top && indent > top.indent) {\n\t\t\t\tparts.push(`<${tag}>`);\n\t\t\t\tstack.push({ tag, indent });\n\t\t\t}\n\t\t}\n\n\t\tconst content: string = serializeBlock(item, registry);\n\n\t\t// Look ahead: if the next item is deeper, strip </li> so the nested\n\t\t// list opens inside this <li> (valid HTML5 nesting).\n\t\tconst nextItem: BlockNode | undefined = items[idx + 1];\n\t\tconst nextIndent: number | undefined = nextItem\n\t\t\t? ((nextItem.attrs?.indent as number) ?? 0)\n\t\t\t: undefined;\n\n\t\tif (nextIndent !== undefined && nextIndent > indent) {\n\t\t\tparts.push(stripTrailingLiClose(content));\n\t\t} else {\n\t\t\tparts.push(content);\n\t\t}\n\t}\n\n\t// Close all remaining open wrappers\n\twhile (stack.length > 0) {\n\t\tconst top: { tag: string; indent: number } | undefined = stack.pop();\n\t\tif (!top) break;\n\t\tparts.push(`</${top.tag}>`);\n\t\tif (stack.length > 0) {\n\t\t\tparts.push('</li>');\n\t\t}\n\t}\n\n\treturn parts.join('');\n}\n\n/** Removes the trailing `</li>` from serialized list item HTML. */\nfunction stripTrailingLiClose(html: string): string {\n\tconst suffix = '</li>';\n\tif (html.endsWith(suffix)) {\n\t\treturn html.slice(0, -suffix.length);\n\t}\n\treturn html;\n}\n\n/** Serializes a single block to HTML using its NodeSpec. */\nfunction serializeBlock(block: BlockNode, registry?: SchemaRegistry): string {\n\tconst content: string = isLeafBlock(block)\n\t\t? serializeInlineContent(block, registry)\n\t\t: serializeBlocks(getBlockChildren(block), registry);\n\tconst spec = registry?.getNodeSpec(block.type);\n\n\tlet html: string;\n\tif (spec?.toHTML) {\n\t\thtml = spec.toHTML(block, content);\n\t} else {\n\t\thtml = `<p>${content || '<br>'}</p>`;\n\t}\n\n\t// Inject align style into the first opening tag (validated against allowlist).\n\t// Skip if the spec's toHTML already emitted a text-align style.\n\tconst align: string | undefined = (block.attrs as Record<string, unknown>)?.align as\n\t\t| string\n\t\t| undefined;\n\tconst alreadyHasAlign: boolean = /style=\"[^\"]*text-align:/.test(html);\n\tif (align && align !== 'left' && VALID_ALIGNMENTS.has(align) && !alreadyHasAlign) {\n\t\thtml = html.replace(/>/, ` style=\"text-align: ${align}\">`);\n\t}\n\n\treturn html;\n}\n\n/** Serializes inline children (TextNode + InlineNode) of a block. */\nfunction serializeInlineContent(block: BlockNode, registry?: SchemaRegistry): string {\n\tconst children: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tconst merged: readonly (TextNode | InlineNode)[] = mergeAdjacentTextNodes(children);\n\tconst parts: string[] = [];\n\tconst markOrder: Map<string, number> | undefined = registry\n\t\t? buildMarkOrder(registry)\n\t\t: undefined;\n\n\tfor (const child of merged) {\n\t\tif (isInlineNode(child)) {\n\t\t\tconst inlineSpec = registry?.getInlineNodeSpec(child.inlineType);\n\t\t\tif (inlineSpec?.toHTMLString) {\n\t\t\t\tparts.push(inlineSpec.toHTMLString(child));\n\t\t\t}\n\t\t} else if (registry) {\n\t\t\tparts.push(serializeMarksToHTML(child.text, child.marks, registry, markOrder));\n\t\t} else if (child.text !== '') {\n\t\t\tparts.push(escapeHTML(child.text));\n\t\t}\n\t}\n\n\treturn parts.join('');\n}\n\n/**\n * Merges adjacent TextNodes that share identical mark sets.\n * InlineNodes act as merge boundaries.\n */\nfunction mergeAdjacentTextNodes(\n\tchildren: readonly (TextNode | InlineNode)[],\n): readonly (TextNode | InlineNode)[] {\n\tif (children.length <= 1) return children;\n\n\tconst result: (TextNode | InlineNode)[] = [];\n\n\tfor (const child of children) {\n\t\tif (isInlineNode(child)) {\n\t\t\tresult.push(child);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst prev: TextNode | InlineNode | undefined = result[result.length - 1];\n\t\tif (prev && isTextNode(prev) && markSetsEqual(prev.marks, child.marks)) {\n\t\t\tresult[result.length - 1] = {\n\t\t\t\ttype: 'text',\n\t\t\t\ttext: prev.text + child.text,\n\t\t\t\tmarks: prev.marks,\n\t\t\t};\n\t\t} else {\n\t\t\tresult.push(child);\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * DocumentParser: converts sanitized HTML strings into immutable Document instances.\n * Pure functions — no class state, no DOM mutation beyond a temporary `<template>`.\n */\n\nimport DOMPurify from 'dompurify';\nimport type { BlockNode, Document, InlineNode, Mark, TextNode } from '../model/Document.js';\nimport {\n\tcreateBlockNode,\n\tcreateDocument,\n\tcreateInlineNode,\n\tcreateTextNode,\n} from '../model/Document.js';\nimport type { ParseRule } from '../model/ParseRule.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { type InlineTypeName, inlineType, markType, nodeType } from '../model/TypeBrands.js';\nimport { VALID_ALIGNMENTS } from './DocumentSerializer.js';\n\n/** Parses an HTML string into a Document, applying sanitization and schema parse rules. */\nexport function parseHTMLToDocument(html: string, registry?: SchemaRegistry): Document {\n\tconst allowedTags: string[] = registry ? registry.getAllowedTags() : ['p', 'br', 'div', 'span'];\n\tconst allowedAttrs: string[] = registry ? registry.getAllowedAttrs() : ['style'];\n\n\tconst template = document.createElement('template');\n\ttemplate.innerHTML = DOMPurify.sanitize(html, {\n\t\tALLOWED_TAGS: allowedTags,\n\t\tALLOWED_ATTR: allowedAttrs,\n\t});\n\tconst root: DocumentFragment = template.content;\n\n\tconst blockRules = registry?.getBlockParseRules() ?? [];\n\tconst blocks: BlockNode[] = [];\n\n\tfor (const child of Array.from(root.childNodes)) {\n\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\tconst el = child as HTMLElement;\n\t\t\tconst tag: string = el.tagName.toLowerCase();\n\n\t\t\t// Lists need cross-element logic — handle before parse rules\n\t\t\tif (tag === 'ul' || tag === 'ol') {\n\t\t\t\tconst listType: string = tag === 'ol' ? 'ordered' : 'bullet';\n\t\t\t\tparseListElement(el, listType, 0, blocks, registry);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Try block parse rules\n\t\t\tconst match = matchBlockParseRule(el, blockRules);\n\t\t\tif (match) {\n\t\t\t\tconst inlineContent = parseElementToInlineContent(el, registry);\n\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t...(match.attrs as Record<string, string | number | boolean> | undefined),\n\t\t\t\t};\n\t\t\t\textractAlignment(el, attrs);\n\t\t\t\tblocks.push(\n\t\t\t\t\tcreateBlockNode(\n\t\t\t\t\t\tnodeType(match.type),\n\t\t\t\t\t\tinlineContent,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tObject.keys(attrs).length > 0 ? attrs : undefined,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Fallback to paragraph\n\t\t\tconst inlineContent = parseElementToInlineContent(el, registry);\n\t\t\tconst attrs: Record<string, string | number | boolean> = {};\n\t\t\textractAlignment(el, attrs);\n\t\t\tblocks.push(\n\t\t\t\tcreateBlockNode(\n\t\t\t\t\tnodeType('paragraph'),\n\t\t\t\t\tinlineContent,\n\t\t\t\t\tundefined,\n\t\t\t\t\tObject.keys(attrs).length > 0 ? attrs : undefined,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (child.nodeType === Node.TEXT_NODE && child.textContent?.trim()) {\n\t\t\tblocks.push(\n\t\t\t\tcreateBlockNode(nodeType('paragraph'), [createTextNode(child.textContent.trim())]),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (blocks.length === 0) return createDocument();\n\treturn createDocument(blocks);\n}\n\n/**\n * Recursively parses a list element (`<ul>` or `<ol>`), creating list_item blocks\n * with correct indent depth. Handles nested lists inside `<li>` elements.\n */\nfunction parseListElement(\n\tlistEl: Element,\n\tlistType: string,\n\tdepth: number,\n\tblocks: BlockNode[],\n\tregistry?: SchemaRegistry,\n): void {\n\tfor (const child of Array.from(listEl.children)) {\n\t\tconst tag: string = child.tagName.toLowerCase();\n\n\t\tif (tag === 'li') {\n\t\t\tconst li: HTMLElement = child as HTMLElement;\n\n\t\t\t// Check for checklist: <input type=\"checkbox\">\n\t\t\tconst checkbox: HTMLInputElement | null = li.querySelector(':scope > input[type=\"checkbox\"]');\n\t\t\tconst isChecklist: boolean = checkbox !== null;\n\t\t\tconst checked: boolean = checkbox?.hasAttribute('checked') ?? false;\n\n\t\t\tconst resolvedType: string = isChecklist ? 'checklist' : listType;\n\n\t\t\tconst inlineContent = parseElementToInlineContent(li, registry, true);\n\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\tlistType: resolvedType,\n\t\t\t\tindent: depth,\n\t\t\t\tchecked,\n\t\t\t};\n\n\t\t\tblocks.push(createBlockNode(nodeType('list_item'), inlineContent, undefined, attrs));\n\n\t\t\t// Check for nested lists inside this <li>\n\t\t\tfor (const liChild of Array.from(li.children)) {\n\t\t\t\tconst liChildTag: string = liChild.tagName.toLowerCase();\n\t\t\t\tif (liChildTag === 'ul' || liChildTag === 'ol') {\n\t\t\t\t\tconst nestedType: string = liChildTag === 'ol' ? 'ordered' : 'bullet';\n\t\t\t\t\tparseListElement(liChild, nestedType, depth + 1, blocks, registry);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (tag === 'ul' || tag === 'ol') {\n\t\t\t// Direct nested list without wrapping <li> — increment depth\n\t\t\tconst nestedType: string = tag === 'ol' ? 'ordered' : 'bullet';\n\t\t\tparseListElement(child, nestedType, depth + 1, blocks, registry);\n\t\t}\n\t}\n}\n\n/**\n * Parses an HTML element's inline children into (TextNode | InlineNode)[].\n * Applies mark parse rules and inline node parse rules.\n */\nfunction parseElementToInlineContent(\n\tel: HTMLElement,\n\tregistry?: SchemaRegistry,\n\tskipNestedLists?: boolean,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tconst markRules = registry?.getMarkParseRules() ?? [];\n\tconst inlineRules = registry?.getInlineParseRules() ?? [];\n\twalkElement(el, [], result, markRules, inlineRules, skipNestedLists);\n\treturn result.length > 0 ? result : [createTextNode('')];\n}\n\n/**\n * Recursively walks DOM nodes, collecting marks from parse rules,\n * matching inline node parse rules, and producing TextNodes/InlineNodes.\n */\nfunction walkElement(\n\tnode: Node,\n\tcurrentMarks: Mark[],\n\tresult: (TextNode | InlineNode)[],\n\tmarkRules: readonly { readonly rule: ParseRule; readonly type: string }[],\n\tinlineRules: readonly { readonly rule: ParseRule; readonly type: string }[],\n\tskipNestedLists?: boolean,\n): void {\n\tif (node.nodeType === Node.TEXT_NODE) {\n\t\tconst text: string = node.textContent ?? '';\n\t\tif (text) {\n\t\t\tresult.push(createTextNode(text, [...currentMarks]));\n\t\t}\n\t\treturn;\n\t}\n\n\tif (node.nodeType !== Node.ELEMENT_NODE) return;\n\n\tconst el = node as HTMLElement;\n\tconst tag: string = el.tagName.toLowerCase();\n\n\t// Skip nested lists inside <li> (handled by parseListElement)\n\tif (skipNestedLists && (tag === 'ul' || tag === 'ol')) return;\n\n\t// Skip checkbox inputs inside list items (already handled by parseListElement)\n\tif (skipNestedLists && tag === 'input' && el.getAttribute('type') === 'checkbox') return;\n\n\t// Try inline node parse rules first (atomic — no recursion)\n\tfor (const entry of inlineRules) {\n\t\tif (entry.rule.tag !== tag) continue;\n\n\t\tif (entry.rule.getAttrs) {\n\t\t\tconst attrs = entry.rule.getAttrs(el);\n\t\t\tif (attrs === false) continue;\n\t\t\tresult.push(\n\t\t\t\tcreateInlineNode(\n\t\t\t\t\tinlineType(entry.type) as InlineTypeName,\n\t\t\t\t\tattrs as Readonly<Record<string, string | number | boolean>>,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tresult.push(createInlineNode(inlineType(entry.type) as InlineTypeName));\n\t\treturn;\n\t}\n\n\tconst marks: Mark[] = [...currentMarks];\n\n\t// Try mark parse rules — collect all matching marks for this element\n\tconst matchedTypes = new Set<string>();\n\tfor (const entry of markRules) {\n\t\tif (entry.rule.tag !== tag) continue;\n\t\tif (matchedTypes.has(entry.type)) continue;\n\n\t\tif (entry.rule.getAttrs) {\n\t\t\tconst attrs = entry.rule.getAttrs(el);\n\t\t\tif (attrs === false) continue;\n\t\t\tif (!marks.some((m) => m.type === entry.type)) {\n\t\t\t\tmarks.push({\n\t\t\t\t\ttype: markType(entry.type),\n\t\t\t\t\t...(Object.keys(attrs).length > 0 ? { attrs } : {}),\n\t\t\t\t} as Mark);\n\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t}\n\t\t} else {\n\t\t\tif (!marks.some((m) => m.type === entry.type)) {\n\t\t\t\tmarks.push({ type: markType(entry.type) });\n\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const child of Array.from(el.childNodes)) {\n\t\twalkElement(child, marks, result, markRules, inlineRules, skipNestedLists);\n\t}\n}\n\n/** Extracts validated `text-align` from an element's style and adds it to attrs. */\nfunction extractAlignment(el: HTMLElement, attrs: Record<string, string | number | boolean>): void {\n\tconst align: string = el.style?.textAlign ?? '';\n\tif (align && VALID_ALIGNMENTS.has(align)) {\n\t\tattrs.align = align;\n\t}\n}\n\n/** Matches an element against block parse rules. Returns matched type and attrs. */\nfunction matchBlockParseRule(\n\tel: HTMLElement,\n\trules: readonly { readonly rule: ParseRule; readonly type: string }[],\n): { readonly type: string; readonly attrs?: Record<string, unknown> } | null {\n\tconst tag: string = el.tagName.toLowerCase();\n\tfor (const entry of rules) {\n\t\tif (entry.rule.tag !== tag) continue;\n\t\tif (entry.rule.getAttrs) {\n\t\t\tconst attrs = entry.rule.getAttrs(el);\n\t\t\tif (attrs === false) continue;\n\t\t\treturn { type: entry.type, attrs };\n\t\t}\n\t\treturn { type: entry.type };\n\t}\n\treturn null;\n}\n","/**\n * Input handler: intercepts all beforeinput events, maps them to transactions.\n * After text insertion, checks registered InputRules for pattern matches.\n */\n\nimport {\n\tdeleteBackward,\n\tdeleteForward,\n\tdeleteSoftLineBackward,\n\tdeleteSoftLineForward,\n\tdeleteWordBackward,\n\tdeleteWordForward,\n\tinsertHardBreakCommand,\n\tinsertTextCommand,\n\tsplitBlockCommand,\n} from '../commands/Commands.js';\nimport { getBlockText } from '../model/Document.js';\nimport { isGapCursor, isNodeSelection } from '../model/Selection.js';\nimport type { Transaction } from '../state/Transaction.js';\n\nimport type { EditorState } from '../state/EditorState.js';\nimport { CompositionTracker } from './CompositionTracker.js';\nimport type { InputRuleRegistry } from './InputRuleRegistry.js';\n\nexport type DispatchFn = (tr: Transaction) => void;\nexport type GetStateFn = () => EditorState;\nexport type UndoFn = () => void;\nexport type RedoFn = () => void;\n\nexport type SyncSelectionFn = () => void;\n\nexport interface InputHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tsyncSelection: SyncSelectionFn;\n\tinputRuleRegistry?: InputRuleRegistry;\n\tisReadOnly?: () => boolean;\n\tcompositionTracker?: CompositionTracker;\n}\n\nexport class InputHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly syncSelection: SyncSelectionFn;\n\tprivate readonly inputRuleRegistry?: InputRuleRegistry;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate readonly compositionTracker: CompositionTracker;\n\n\tprivate readonly handleBeforeInput: (e: InputEvent) => void;\n\tprivate readonly handleCompositionStart: (e: CompositionEvent) => void;\n\tprivate readonly handleCompositionEnd: (e: CompositionEvent) => void;\n\n\tconstructor(\n\t\tprivate readonly element: HTMLElement,\n\t\toptions: InputHandlerOptions,\n\t) {\n\t\tthis.getState = options.getState;\n\t\tthis.dispatch = options.dispatch;\n\t\tthis.syncSelection = options.syncSelection;\n\t\tthis.inputRuleRegistry = options.inputRuleRegistry;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\t\tthis.compositionTracker = options.compositionTracker ?? new CompositionTracker();\n\n\t\tthis.handleBeforeInput = this.onBeforeInput.bind(this);\n\t\tthis.handleCompositionStart = this.onCompositionStart.bind(this);\n\t\tthis.handleCompositionEnd = this.onCompositionEnd.bind(this);\n\n\t\telement.addEventListener('beforeinput', this.handleBeforeInput);\n\t\telement.addEventListener('compositionstart', this.handleCompositionStart);\n\t\telement.addEventListener('compositionend', this.handleCompositionEnd);\n\t}\n\n\tprivate onBeforeInput(e: InputEvent): void {\n\t\tif (this.isReadOnly()) return;\n\n\t\t// During composition, let the browser handle it\n\t\tif (this.compositionTracker.isComposing && e.inputType === 'insertCompositionText') {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\t// Sync selection from DOM before processing non-insert operations\n\t\t// (handles arrow key / mouse navigation that doesn't go through our state)\n\t\tconst needsSelectionSync =\n\t\t\te.inputType !== 'insertText' && e.inputType !== 'insertCompositionText';\n\t\tif (needsSelectionSync) {\n\t\t\tthis.syncSelection();\n\t\t}\n\n\t\tconst state = this.getState();\n\t\tlet tr: Transaction | null = null;\n\n\t\tswitch (e.inputType) {\n\t\t\tcase 'insertText':\n\t\t\t\tif (e.data) {\n\t\t\t\t\ttr = insertTextCommand(state, e.data, 'input');\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'insertParagraph':\n\t\t\t\ttr = splitBlockCommand(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'insertLineBreak':\n\t\t\t\ttr = insertHardBreakCommand(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteContentBackward':\n\t\t\t\ttr = deleteBackward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteContentForward':\n\t\t\t\ttr = deleteForward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteWordBackward':\n\t\t\t\ttr = deleteWordBackward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteWordForward':\n\t\t\t\ttr = deleteWordForward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteSoftLineBackward':\n\t\t\t\ttr = deleteSoftLineBackward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteSoftLineForward':\n\t\t\t\ttr = deleteSoftLineForward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteByCut':\n\t\t\t\ttr = deleteBackward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'insertFromPaste':\n\t\t\t\t// Handled by PasteHandler\n\t\t\t\tbreak;\n\n\t\t\tcase 'insertFromDrop':\n\t\t\t\t// Handled by PasteHandler\n\t\t\t\tbreak;\n\n\t\t\tcase 'formatBold':\n\t\t\tcase 'formatItalic':\n\t\t\tcase 'formatUnderline':\n\t\t\tcase 'historyUndo':\n\t\t\tcase 'historyRedo':\n\t\t\t\t// Handled by KeyboardHandler — just prevent default\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (tr) {\n\t\t\tthis.dispatch(tr);\n\n\t\t\t// Check input rules after text insertion\n\t\t\tif (e.inputType === 'insertText') {\n\t\t\t\tthis.checkInputRules();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onCompositionStart(_e: CompositionEvent): void {\n\t\tconst state = this.getState();\n\t\tif (isNodeSelection(state.selection) || isGapCursor(state.selection)) return;\n\t\tthis.compositionTracker.start(state.selection.anchor.blockId);\n\t}\n\n\tprivate onCompositionEnd(e: CompositionEvent): void {\n\t\tthis.compositionTracker.end();\n\t\tif (this.isReadOnly()) return;\n\t\tconst composedText = e.data;\n\t\tif (!composedText) return;\n\n\t\tconst state = this.getState();\n\t\tconst tr = insertTextCommand(state, composedText, 'input');\n\t\tthis.dispatch(tr);\n\t}\n\n\tprivate checkInputRules(): void {\n\t\tif (!this.inputRuleRegistry) return;\n\t\tconst rules = this.inputRuleRegistry.getInputRules();\n\t\tif (rules.length === 0) return;\n\n\t\tconst state = this.getState();\n\t\tif (isNodeSelection(state.selection) || isGapCursor(state.selection)) return;\n\t\tconst { anchor } = state.selection;\n\t\tconst block = state.getBlock(anchor.blockId);\n\t\tif (!block) return;\n\n\t\tconst text = getBlockText(block);\n\t\tconst textBefore = text.slice(0, anchor.offset);\n\n\t\tfor (const rule of rules) {\n\t\t\tconst match = rule.pattern.exec(textBefore);\n\t\t\tif (match) {\n\t\t\t\tconst start = match.index;\n\t\t\t\tconst end = start + match[0].length;\n\t\t\t\tconst tr = rule.handler(state, match, start, end);\n\t\t\t\tif (tr) {\n\t\t\t\t\tthis.dispatch(tr);\n\t\t\t\t\treturn; // Only first matching rule fires\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.element.removeEventListener('beforeinput', this.handleBeforeInput);\n\t\tthis.element.removeEventListener('compositionstart', this.handleCompositionStart);\n\t\tthis.element.removeEventListener('compositionend', this.handleCompositionEnd);\n\t}\n}\n","/**\n * ContentSlice: an immutable fragment of document content for paste operations.\n * Represents \"what to insert\" independent of where it will be inserted.\n */\n\nimport type { BlockAttrs, TextSegment } from './Document.js';\nimport type { NodeTypeName } from './TypeBrands.js';\nimport { nodeType } from './TypeBrands.js';\n\nexport interface SliceBlock {\n\treadonly type: NodeTypeName;\n\treadonly attrs?: BlockAttrs;\n\treadonly segments: readonly TextSegment[];\n}\n\nexport interface ContentSlice {\n\treadonly blocks: readonly SliceBlock[];\n}\n\n/** Concatenates all segment texts within a slice block. */\nexport function segmentsToText(segments: readonly TextSegment[]): string {\n\treturn segments.reduce((acc: string, s: TextSegment) => acc + s.text, '');\n}\n\n/** Returns the total text length of a slice block's segments. */\nexport function segmentsLength(segments: readonly TextSegment[]): number {\n\treturn segments.reduce((acc: number, s: TextSegment) => acc + s.text.length, 0);\n}\n\n/** Creates a single-paragraph content slice from plain text. */\nexport function plainTextSlice(text: string): ContentSlice {\n\tconst lines: readonly string[] = text.split(/\\r?\\n/);\n\tconst blocks: readonly SliceBlock[] = lines.map(\n\t\t(line: string): SliceBlock => ({\n\t\t\ttype: nodeType('paragraph'),\n\t\t\tsegments: [{ text: line, marks: [] }],\n\t\t}),\n\t);\n\treturn {\n\t\tblocks:\n\t\t\tblocks.length > 0\n\t\t\t\t? blocks\n\t\t\t\t: [{ type: nodeType('paragraph'), segments: [{ text: '', marks: [] }] }],\n\t};\n}\n","/**\n * PasteCommand: builds transactions from a ContentSlice and EditorState.\n * Handles three strategies: inline paste, single-block paste, multi-block paste.\n */\n\nimport type { ContentSlice, SliceBlock } from '../model/ContentSlice.js';\nimport { segmentsLength, segmentsToText } from '../model/ContentSlice.js';\nimport {\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgenerateBlockId,\n\tisBlockNode,\n} from '../model/Document.js';\nimport type { TextSegment } from '../model/Document.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { GapCursorSelection } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport { nodeType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction, TransactionBuilder } from '../state/Transaction.js';\nimport { resolveInsertPoint } from './CommandHelpers.js';\nimport { addDeleteSelectionSteps } from './Commands.js';\n\n/**\n * Builds a transaction that pastes the given ContentSlice into the editor state.\n * Selects the appropriate strategy based on the slice structure.\n */\nexport function pasteSlice(state: EditorState, slice: ContentSlice): Transaction {\n\tif (slice.blocks.length === 0) {\n\t\treturn state.transaction('paste').setSelection(state.selection).build();\n\t}\n\n\tconst firstBlock: SliceBlock | undefined = slice.blocks[0];\n\tif (!firstBlock) {\n\t\treturn state.transaction('paste').setSelection(state.selection).build();\n\t}\n\n\tif (slice.blocks.length === 1 && firstBlock.type === nodeType('paragraph')) {\n\t\treturn pasteInline(state, firstBlock.segments);\n\t}\n\tif (slice.blocks.length === 1) {\n\t\treturn pasteSingleBlock(state, firstBlock);\n\t}\n\treturn pasteMultiBlock(state, slice);\n}\n\n/** Case 1: single paragraph — insert segments into current block. */\nfunction pasteInline(state: EditorState, segments: readonly TextSegment[]): Transaction {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\tif (isGapCursor(sel)) {\n\t\treturn pasteInlineAtGap(state, sel, segments);\n\t}\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst { blockId: insertBlockId, offset: insertOffset } = resolveInsertPoint(\n\t\tsel,\n\t\tstate.getBlockOrder(),\n\t);\n\tconst totalLength: number = segmentsLength(segments);\n\tconst text: string = segmentsToText(segments);\n\n\tbuilder.insertText(insertBlockId, insertOffset, text, [], segments);\n\tbuilder.setSelection(createCollapsedSelection(insertBlockId, insertOffset + totalLength));\n\n\treturn builder.build();\n}\n\n/** Case 2: single non-paragraph block — change block type and insert segments. */\nfunction pasteSingleBlock(state: EditorState, block: SliceBlock): Transaction {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\tif (isGapCursor(sel)) {\n\t\treturn pasteBlocksAtGap(state, sel, [block]);\n\t}\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst { blockId: insertBlockId, offset: insertOffset } = resolveInsertPoint(\n\t\tsel,\n\t\tstate.getBlockOrder(),\n\t);\n\tconst totalLength: number = segmentsLength(block.segments);\n\tconst text: string = segmentsToText(block.segments);\n\n\tbuilder.setBlockType(insertBlockId, block.type, block.attrs);\n\tbuilder.insertText(insertBlockId, insertOffset, text, [], block.segments);\n\tbuilder.setSelection(createCollapsedSelection(insertBlockId, insertOffset + totalLength));\n\n\treturn builder.build();\n}\n\n/** Case 3: multiple blocks — split-insert-merge strategy. */\nfunction pasteMultiBlock(state: EditorState, slice: ContentSlice): Transaction {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\tif (isGapCursor(sel)) {\n\t\treturn pasteBlocksAtGap(state, sel, slice.blocks);\n\t}\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst blockOrder = state.getBlockOrder();\n\tconst { blockId, offset } = resolveInsertPoint(sel, blockOrder);\n\tconst blockIdx: number = blockOrder.indexOf(blockId);\n\n\tconst firstSlice: SliceBlock | undefined = slice.blocks[0];\n\tconst lastSlice: SliceBlock | undefined = slice.blocks[slice.blocks.length - 1];\n\tif (!firstSlice || !lastSlice) {\n\t\treturn builder.build();\n\t}\n\tconst middleSlices: readonly SliceBlock[] = slice.blocks.slice(1, -1);\n\n\t// 1. Insert first slice's segments into current block\n\tconst firstLen: number = segmentsLength(firstSlice.segments);\n\tif (firstSlice.segments.length > 0 && firstLen > 0) {\n\t\tbuilder.insertText(\n\t\t\tblockId,\n\t\t\toffset,\n\t\t\tsegmentsToText(firstSlice.segments),\n\t\t\t[],\n\t\t\tfirstSlice.segments,\n\t\t);\n\t}\n\n\t// 2. Change block type if first slice is not a paragraph\n\tif (firstSlice.type !== nodeType('paragraph')) {\n\t\tbuilder.setBlockType(blockId, firstSlice.type, firstSlice.attrs);\n\t}\n\n\t// 3. Split current block after inserted text\n\tconst splitOffset: number = offset + firstLen;\n\tconst tailBlockId = generateBlockId();\n\tbuilder.splitBlock(blockId, splitOffset, tailBlockId);\n\n\t// 4. Insert middle blocks between first and tail\n\tlet insertAt: number = blockIdx + 1;\n\tfor (const mid of middleSlices) {\n\t\tconst textNodes = mid.segments.map((s: TextSegment) => createTextNode(s.text, [...s.marks]));\n\t\tconst newBlock = createBlockNode(\n\t\t\tmid.type,\n\t\t\ttextNodes.length > 0 ? textNodes : undefined,\n\t\t\tgenerateBlockId(),\n\t\t\tmid.attrs,\n\t\t);\n\t\tbuilder.insertNode([], insertAt, newBlock);\n\t\tinsertAt++;\n\t}\n\n\t// 5. Insert last slice's segments at start of tail block\n\tconst lastLen: number = segmentsLength(lastSlice.segments);\n\tif (lastSlice.segments.length > 0 && lastLen > 0) {\n\t\tbuilder.insertText(tailBlockId, 0, segmentsToText(lastSlice.segments), [], lastSlice.segments);\n\t}\n\n\t// 6. Change tail block type if needed\n\tif (lastSlice.type !== nodeType('paragraph')) {\n\t\tbuilder.setBlockType(tailBlockId, lastSlice.type, lastSlice.attrs);\n\t}\n\n\t// 7. Set cursor to end of inserted content\n\tbuilder.setSelection(createCollapsedSelection(tailBlockId, lastLen));\n\n\treturn builder.build();\n}\n\n// --- GapCursor Paste Helpers ---\n\n/**\n * Resolves the insert position for a GapCursor: parent path and index\n * within siblings where new blocks should be inserted.\n */\nfunction gapInsertIndex(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n): { parentPath: BlockId[]; insertIndex: number } | null {\n\tconst path = findNodePath(state.doc, sel.blockId);\n\tif (!path) return null;\n\n\tconst parentPath: BlockId[] = path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\n\tconst siblings =\n\t\tparentPath.length === 0\n\t\t\t? state.doc.children\n\t\t\t: (() => {\n\t\t\t\t\tconst parent = state.getBlock(parentPath[parentPath.length - 1] as BlockId);\n\t\t\t\t\treturn parent ? parent.children : [];\n\t\t\t\t})();\n\n\tconst index: number = siblings.findIndex((c) => isBlockNode(c) && c.id === sel.blockId);\n\tif (index < 0) return null;\n\n\tconst insertIndex: number = sel.side === 'before' ? index : index + 1;\n\treturn { parentPath, insertIndex };\n}\n\n/** Pastes inline segments (single paragraph) at a GapCursor position. */\nfunction pasteInlineAtGap(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n\tsegments: readonly TextSegment[],\n): Transaction {\n\tconst gap = gapInsertIndex(state, sel);\n\tif (!gap) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\n\tconst newId: BlockId = generateBlockId();\n\tconst text: string = segmentsToText(segments);\n\tconst totalLength: number = segmentsLength(segments);\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tbuilder.insertNode(\n\t\tgap.parentPath,\n\t\tgap.insertIndex,\n\t\tcreateBlockNode(nodeType('paragraph') as NodeTypeName, [createTextNode('')], newId),\n\t);\n\tif (text.length > 0) {\n\t\tbuilder.insertText(newId, 0, text, [], segments);\n\t}\n\tbuilder.setSelection(createCollapsedSelection(newId, totalLength));\n\n\treturn builder.build();\n}\n\n/** Pastes one or more blocks at a GapCursor position. */\nfunction pasteBlocksAtGap(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n\tblocks: readonly SliceBlock[],\n): Transaction {\n\tconst gap = gapInsertIndex(state, sel);\n\tif (!gap) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\tlet insertAt: number = gap.insertIndex;\n\tlet lastBlockId: BlockId | undefined;\n\tlet lastTextLen = 0;\n\n\tfor (const block of blocks) {\n\t\tconst newId: BlockId = generateBlockId();\n\t\tconst text: string = segmentsToText(block.segments);\n\t\tconst textNodes = block.segments.map((s: TextSegment) => createTextNode(s.text, [...s.marks]));\n\t\tconst newBlock = createBlockNode(\n\t\t\tblock.type,\n\t\t\ttextNodes.length > 0 ? textNodes : [createTextNode('')],\n\t\t\tnewId,\n\t\t\tblock.attrs,\n\t\t);\n\t\tbuilder.insertNode(gap.parentPath, insertAt, newBlock);\n\t\tinsertAt++;\n\t\tlastBlockId = newId;\n\t\tlastTextLen = text.length;\n\t}\n\n\tif (lastBlockId) {\n\t\tbuilder.setSelection(createCollapsedSelection(lastBlockId, lastTextLen));\n\t}\n\n\treturn builder.build();\n}\n","/**\n * HTMLParser: converts sanitized HTML DOM into a ContentSlice.\n * Works on DOM nodes (not strings), is schema-aware, and produces immutable output.\n */\n\nimport type { ContentSlice, SliceBlock } from './ContentSlice.js';\nimport type { Mark, TextSegment } from './Document.js';\nimport { markSetsEqual } from './Document.js';\nimport type { ParseRule } from './ParseRule.js';\nimport type { Schema } from './Schema.js';\nimport { isMarkAllowed, isNodeTypeAllowed } from './Schema.js';\nimport type { SchemaRegistry } from './SchemaRegistry.js';\nimport type { NodeTypeName } from './TypeBrands.js';\nimport { markType, nodeType } from './TypeBrands.js';\n\nexport interface HTMLParserOptions {\n\treadonly schema: Schema;\n\treadonly schemaRegistry?: SchemaRegistry;\n}\n\nconst BLOCK_ELEMENTS: ReadonlySet<string> = new Set([\n\t'P',\n\t'DIV',\n\t'H1',\n\t'H2',\n\t'H3',\n\t'H4',\n\t'H5',\n\t'H6',\n\t'BLOCKQUOTE',\n\t'UL',\n\t'OL',\n\t'LI',\n\t'HR',\n\t'PRE',\n\t'TABLE',\n\t'THEAD',\n\t'TBODY',\n\t'TR',\n]);\n\nconst INLINE_ELEMENTS: ReadonlySet<string> = new Set([\n\t'STRONG',\n\t'B',\n\t'EM',\n\t'I',\n\t'U',\n\t'S',\n\t'STRIKE',\n\t'DEL',\n\t'A',\n\t'SPAN',\n\t'BR',\n\t'SUB',\n\t'SUP',\n\t'CODE',\n]);\n\nexport class HTMLParser {\n\tprivate readonly schema: Schema;\n\tprivate readonly blockParseRules: readonly {\n\t\treadonly rule: ParseRule;\n\t\treadonly type: string;\n\t}[];\n\tprivate readonly markParseRules: readonly {\n\t\treadonly rule: ParseRule;\n\t\treadonly type: string;\n\t}[];\n\n\tconstructor(options: HTMLParserOptions) {\n\t\tthis.schema = options.schema;\n\t\tthis.blockParseRules = options.schemaRegistry?.getBlockParseRules() ?? [];\n\t\tthis.markParseRules = options.schemaRegistry?.getMarkParseRules() ?? [];\n\t}\n\n\t/** Parses an HTML fragment and returns a ContentSlice. */\n\tparse(container: DocumentFragment | HTMLElement): ContentSlice {\n\t\tconst blocks: SliceBlock[] = this.parseContainer(container);\n\n\t\tif (blocks.length === 0) {\n\t\t\treturn {\n\t\t\t\tblocks: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\t\t\t\tsegments: [{ text: '', marks: [] }],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\treturn { blocks };\n\t}\n\n\tprivate parseContainer(container: DocumentFragment | HTMLElement): SliceBlock[] {\n\t\tconst blocks: SliceBlock[] = [];\n\t\tlet pendingSegments: TextSegment[] = [];\n\n\t\tfor (const child of Array.from(container.childNodes)) {\n\t\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst el = child as HTMLElement;\n\n\t\t\t\tif (this.isBlockElement(el)) {\n\t\t\t\t\tthis.flushPendingSegments(blocks, pendingSegments);\n\t\t\t\t\tpendingSegments = [];\n\t\t\t\t\tblocks.push(...this.parseBlockElement(el));\n\t\t\t\t} else if (el.children.length > 0 && this.containsBlockDescendants(el)) {\n\t\t\t\t\tthis.flushPendingSegments(blocks, pendingSegments);\n\t\t\t\t\tpendingSegments = [];\n\t\t\t\t\tblocks.push(...this.parseContainerWithMarks(el, this.marksFromElement(el)));\n\t\t\t\t} else {\n\t\t\t\t\tpendingSegments.push(...this.parseInlineNode(child, []));\n\t\t\t\t}\n\t\t\t} else if (child.nodeType === Node.TEXT_NODE) {\n\t\t\t\tconst text: string = child.textContent ?? '';\n\t\t\t\tif (text) {\n\t\t\t\t\tpendingSegments.push({ text, marks: [] });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.flushPendingSegments(blocks, pendingSegments);\n\t\treturn blocks;\n\t}\n\n\tprivate parseBlockElement(element: HTMLElement): SliceBlock[] {\n\t\tconst tag: string = element.tagName;\n\n\t\tconst headingMatch: RegExpExecArray | null = /^H([1-6])$/.exec(tag);\n\t\tif (headingMatch) {\n\t\t\tconst level: number = Number(headingMatch[1]);\n\t\t\tconst blockType: NodeTypeName = this.resolveBlockType(nodeType('heading'));\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\ttype: blockType,\n\t\t\t\t\t...(blockType === nodeType('heading') ? { attrs: { level } } : {}),\n\t\t\t\t\tsegments: this.ensureSegments(this.parseInlineChildren(element, [])),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\n\t\tswitch (tag) {\n\t\t\tcase 'P':\n\t\t\tcase 'DIV':\n\t\t\t\treturn this.parseBlockWithLineBreaks(element, this.resolveBlockType(nodeType('paragraph')));\n\n\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\treturn this.parseBlockquote(element);\n\n\t\t\tcase 'UL':\n\t\t\t\treturn this.parseList(element, 'bullet', 0);\n\n\t\t\tcase 'OL':\n\t\t\t\treturn this.parseList(element, 'ordered', 0);\n\n\t\t\tcase 'LI':\n\t\t\t\treturn this.parseListItem(element, 'bullet', 0);\n\n\t\t\tcase 'HR':\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: this.resolveBlockType(nodeType('horizontal_rule')),\n\t\t\t\t\t\tsegments: [],\n\t\t\t\t\t},\n\t\t\t\t];\n\n\t\t\tcase 'PRE':\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\t\t\t\tsegments: this.ensureSegments(this.parsePreContent(element)),\n\t\t\t\t\t},\n\t\t\t\t];\n\n\t\t\tcase 'TABLE':\n\t\t\tcase 'THEAD':\n\t\t\tcase 'TBODY':\n\t\t\tcase 'TR':\n\t\t\t\treturn this.parseTableAsParagraphs(element);\n\n\t\t\tdefault: {\n\t\t\t\t// Try block parse rules before falling back to paragraph\n\t\t\t\tconst blockMatch = this.matchBlockRule(element);\n\t\t\t\tif (blockMatch) {\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: blockMatch.type,\n\t\t\t\t\t\t\t...(blockMatch.attrs ? { attrs: blockMatch.attrs } : {}),\n\t\t\t\t\t\t\tsegments: this.ensureSegments(this.parseInlineChildren(element, [])),\n\t\t\t\t\t\t},\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\t\t\t\tsegments: this.ensureSegments(this.parseInlineChildren(element, [])),\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate parseBlockquote(element: HTMLElement): SliceBlock[] {\n\t\tconst blockType: NodeTypeName = this.resolveBlockType(nodeType('blockquote'));\n\t\tconst children: Node[] = Array.from(element.childNodes);\n\t\tconst hasBlockChildren: boolean = children.some(\n\t\t\t(c: Node) => c.nodeType === Node.ELEMENT_NODE && this.isBlockElement(c as HTMLElement),\n\t\t);\n\n\t\tif (hasBlockChildren) {\n\t\t\tconst innerBlocks: SliceBlock[] = this.parseContainer(element as HTMLElement);\n\t\t\treturn innerBlocks.map(\n\t\t\t\t(b: SliceBlock): SliceBlock => ({\n\t\t\t\t\ttype: blockType,\n\t\t\t\t\tsegments: b.segments,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\treturn [\n\t\t\t{\n\t\t\t\ttype: blockType,\n\t\t\t\tsegments: this.ensureSegments(this.parseInlineChildren(element, [])),\n\t\t\t},\n\t\t];\n\t}\n\n\tprivate parseList(element: HTMLElement, listType: string, depth: number): SliceBlock[] {\n\t\tconst blocks: SliceBlock[] = [];\n\n\t\tfor (const child of Array.from(element.children)) {\n\t\t\tconst el: HTMLElement = child as HTMLElement;\n\t\t\tif (el.tagName === 'LI') {\n\t\t\t\tblocks.push(...this.parseListItem(el, listType, depth));\n\t\t\t} else if (el.tagName === 'UL') {\n\t\t\t\tblocks.push(...this.parseList(el, 'bullet', depth + 1));\n\t\t\t} else if (el.tagName === 'OL') {\n\t\t\t\tblocks.push(...this.parseList(el, 'ordered', depth + 1));\n\t\t\t}\n\t\t}\n\n\t\treturn blocks;\n\t}\n\n\tprivate parseListItem(element: HTMLElement, listType: string, depth: number): SliceBlock[] {\n\t\tconst blocks: SliceBlock[] = [];\n\t\tconst blockType: NodeTypeName = this.resolveBlockType(nodeType('list_item'));\n\n\t\tconst isChecklist: boolean = this.hasCheckbox(element);\n\t\tconst resolvedListType: string = isChecklist ? 'checklist' : listType;\n\t\tconst checked: boolean = isChecklist ? this.isCheckboxChecked(element) : false;\n\n\t\tconst inlineSegments: TextSegment[] = [];\n\t\tconst nestedLists: HTMLElement[] = [];\n\n\t\tfor (const child of Array.from(element.childNodes)) {\n\t\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst el: HTMLElement = child as HTMLElement;\n\t\t\t\tif (el.tagName === 'UL' || el.tagName === 'OL') {\n\t\t\t\t\tnestedLists.push(el);\n\t\t\t\t} else if (el.tagName === 'INPUT' && el.getAttribute('type') === 'checkbox') {\n\t\t\t\t\t// skip checkbox inputs — handled via block attributes\n\t\t\t\t} else if (this.isBlockElement(el)) {\n\t\t\t\t\tinlineSegments.push(...this.parseInlineChildren(el, []));\n\t\t\t\t} else {\n\t\t\t\t\tinlineSegments.push(...this.parseInlineNode(child, []));\n\t\t\t\t}\n\t\t\t} else if (child.nodeType === Node.TEXT_NODE) {\n\t\t\t\tconst text: string = child.textContent ?? '';\n\t\t\t\tif (text) {\n\t\t\t\t\tinlineSegments.push({ text, marks: [] });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tblocks.push({\n\t\t\ttype: blockType,\n\t\t\tattrs: {\n\t\t\t\tlistType: resolvedListType,\n\t\t\t\tindent: depth,\n\t\t\t\t...(resolvedListType === 'checklist' ? { checked } : {}),\n\t\t\t},\n\t\t\tsegments: this.ensureSegments(this.normalizeSegments(inlineSegments)),\n\t\t});\n\n\t\tfor (const nested of nestedLists) {\n\t\t\tconst nestedType: string = nested.tagName === 'OL' ? 'ordered' : 'bullet';\n\t\t\tblocks.push(...this.parseList(nested, nestedType, depth + 1));\n\t\t}\n\n\t\treturn blocks;\n\t}\n\n\tprivate parseInlineChildren(element: HTMLElement, parentMarks: readonly Mark[]): TextSegment[] {\n\t\tconst segments: TextSegment[] = [];\n\n\t\tfor (const child of Array.from(element.childNodes)) {\n\t\t\tsegments.push(...this.parseInlineNode(child, parentMarks));\n\t\t}\n\n\t\treturn this.normalizeSegments(segments);\n\t}\n\n\tprivate parseInlineNode(node: Node, parentMarks: readonly Mark[]): TextSegment[] {\n\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\tconst text: string = node.textContent ?? '';\n\t\t\tif (text) {\n\t\t\t\treturn [{ text, marks: this.resolveMarks(parentMarks) }];\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\n\t\tif (node.nodeType !== Node.ELEMENT_NODE) return [];\n\n\t\tconst el: HTMLElement = node as HTMLElement;\n\t\tconst tag: string = el.tagName;\n\n\t\tif (tag === 'BR') {\n\t\t\treturn [{ text: '\\n', marks: this.resolveMarks(parentMarks) }];\n\t\t}\n\n\t\tif (this.isBlockElement(el) && !INLINE_ELEMENTS.has(tag)) {\n\t\t\treturn this.parseInlineChildren(el, parentMarks);\n\t\t}\n\n\t\tconst childMarks: readonly Mark[] = this.mergeMarks(parentMarks, this.marksFromElement(el));\n\t\treturn this.parseInlineChildren(el, childMarks);\n\t}\n\n\tprivate parsePreContent(element: HTMLElement): TextSegment[] {\n\t\tconst text: string = element.textContent ?? '';\n\t\tif (!text) return [];\n\t\treturn [{ text, marks: [] }];\n\t}\n\n\tprivate parseTableAsParagraphs(element: HTMLElement): SliceBlock[] {\n\t\tconst blocks: SliceBlock[] = [];\n\t\tconst cells: NodeListOf<HTMLTableCellElement> = element.querySelectorAll('td, th');\n\n\t\tfor (const cell of Array.from(cells)) {\n\t\t\tconst segments: TextSegment[] = this.parseInlineChildren(cell, []);\n\t\t\tif (segments.length > 0 && segments.some((s: TextSegment) => s.text.length > 0)) {\n\t\t\t\tblocks.push({\n\t\t\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\t\t\tsegments: this.ensureSegments(segments),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn blocks;\n\t}\n\n\tprivate marksFromElement(element: HTMLElement): readonly Mark[] {\n\t\tconst marks: Mark[] = [];\n\t\tconst tag: string = element.tagName.toLowerCase();\n\n\t\t// Try mark parse rules first\n\t\tif (this.markParseRules.length > 0) {\n\t\t\tconst matchedTypes = new Set<string>();\n\t\t\tfor (const entry of this.markParseRules) {\n\t\t\t\tif (entry.rule.tag !== tag) continue;\n\t\t\t\tif (matchedTypes.has(entry.type)) continue;\n\n\t\t\t\tif (entry.rule.getAttrs) {\n\t\t\t\t\tconst attrs = entry.rule.getAttrs(element);\n\t\t\t\t\tif (attrs === false) continue;\n\t\t\t\t\tmarks.push({\n\t\t\t\t\t\ttype: markType(entry.type),\n\t\t\t\t\t\t...(Object.keys(attrs).length > 0 ? { attrs } : {}),\n\t\t\t\t\t} as Mark);\n\t\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t\t} else {\n\t\t\t\t\tmarks.push({ type: markType(entry.type) });\n\t\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (matchedTypes.size > 0) return marks;\n\t\t}\n\n\t\t// Fallback to hardcoded logic when no registry is provided\n\t\tconst upperTag: string = element.tagName;\n\t\tif (upperTag === 'STRONG' || upperTag === 'B') {\n\t\t\tconst fw: string = element.style.fontWeight;\n\t\t\tconst numeric: number = Number.parseInt(fw, 10);\n\t\t\tconst isExplicitlyNotBold: boolean =\n\t\t\t\tfw === 'normal' || (!Number.isNaN(numeric) && numeric < 700);\n\t\t\tif (!isExplicitlyNotBold) {\n\t\t\t\tmarks.push({ type: markType('bold') });\n\t\t\t}\n\t\t}\n\t\tif (upperTag === 'EM' || upperTag === 'I') {\n\t\t\tmarks.push({ type: markType('italic') });\n\t\t}\n\t\tif (upperTag === 'U') {\n\t\t\tmarks.push({ type: markType('underline') });\n\t\t}\n\t\tif (upperTag === 'S' || upperTag === 'STRIKE' || upperTag === 'DEL') {\n\t\t\tmarks.push({ type: markType('strikethrough') });\n\t\t}\n\t\tif (upperTag === 'A') {\n\t\t\tconst href: string = element.getAttribute('href') ?? '';\n\t\t\tmarks.push({ type: markType('link'), attrs: { href } });\n\t\t}\n\n\t\treturn marks;\n\t}\n\n\tprivate mergeMarks(existing: readonly Mark[], additional: readonly Mark[]): readonly Mark[] {\n\t\tconst result: Mark[] = [...existing];\n\t\tfor (const mark of additional) {\n\t\t\tif (!result.some((m: Mark) => m.type === mark.type)) {\n\t\t\t\tresult.push(mark);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate resolveMarks(rawMarks: readonly Mark[]): readonly Mark[] {\n\t\treturn rawMarks.filter((m: Mark) => isMarkAllowed(this.schema, m.type));\n\t}\n\n\tprivate resolveBlockType(type: NodeTypeName): NodeTypeName {\n\t\tif (isNodeTypeAllowed(this.schema, type)) return type;\n\t\treturn nodeType('paragraph');\n\t}\n\n\tprivate normalizeSegments(segments: readonly TextSegment[]): TextSegment[] {\n\t\tif (segments.length === 0) return [];\n\n\t\tconst result: TextSegment[] = [];\n\t\tfor (const segment of segments) {\n\t\t\tconst prev: TextSegment | undefined = result[result.length - 1];\n\t\t\tif (prev && markSetsEqual(prev.marks, segment.marks)) {\n\t\t\t\tresult[result.length - 1] = { text: prev.text + segment.text, marks: prev.marks };\n\t\t\t} else if (segment.text.length > 0) {\n\t\t\t\tresult.push(segment);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate ensureSegments(segments: readonly TextSegment[]): readonly TextSegment[] {\n\t\tif (segments.length === 0) return [{ text: '', marks: [] }];\n\t\treturn segments;\n\t}\n\n\tprivate matchBlockRule(el: HTMLElement): {\n\t\treadonly type: NodeTypeName;\n\t\treadonly attrs?: Record<string, string | number | boolean>;\n\t} | null {\n\t\tconst tag: string = el.tagName.toLowerCase();\n\t\tfor (const entry of this.blockParseRules) {\n\t\t\tif (entry.rule.tag !== tag) continue;\n\t\t\tif (entry.rule.getAttrs) {\n\t\t\t\tconst attrs = entry.rule.getAttrs(el);\n\t\t\t\tif (attrs === false) continue;\n\t\t\t\treturn {\n\t\t\t\t\ttype: nodeType(entry.type),\n\t\t\t\t\tattrs: attrs as Record<string, string | number | boolean>,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { type: nodeType(entry.type) };\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate isBlockElement(el: HTMLElement): boolean {\n\t\tif (BLOCK_ELEMENTS.has(el.tagName)) return true;\n\t\t// Check if any block parse rule matches this tag\n\t\tconst tag: string = el.tagName.toLowerCase();\n\t\treturn this.blockParseRules.some((entry) => entry.rule.tag === tag);\n\t}\n\n\tprivate hasCheckbox(element: HTMLElement): boolean {\n\t\tconst input: HTMLInputElement | null = element.querySelector('input[type=\"checkbox\"]');\n\t\treturn input !== null;\n\t}\n\n\tprivate isCheckboxChecked(element: HTMLElement): boolean {\n\t\tconst input: HTMLInputElement | null = element.querySelector('input[type=\"checkbox\"]');\n\t\treturn input?.hasAttribute('checked') ?? false;\n\t}\n\n\t/** Checks whether an element contains any block-level descendants. */\n\tprivate containsBlockDescendants(el: HTMLElement): boolean {\n\t\tfor (const child of Array.from(el.children)) {\n\t\t\tif (this.isBlockElement(child as HTMLElement)) return true;\n\t\t\tif (this.containsBlockDescendants(child as HTMLElement)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** Parses a container element, prepending inherited marks to all resulting blocks. */\n\tprivate parseContainerWithMarks(\n\t\tcontainer: HTMLElement,\n\t\tinheritedMarks: readonly Mark[],\n\t): SliceBlock[] {\n\t\tconst innerBlocks: SliceBlock[] = this.parseContainer(container);\n\t\tif (inheritedMarks.length === 0) return innerBlocks;\n\n\t\treturn innerBlocks.map(\n\t\t\t(block: SliceBlock): SliceBlock => ({\n\t\t\t\t...block,\n\t\t\t\tsegments: this.prependMarks(block.segments, inheritedMarks),\n\t\t\t}),\n\t\t);\n\t}\n\n\t/** Merges inherited marks into each segment's mark list. */\n\tprivate prependMarks(\n\t\tsegments: readonly TextSegment[],\n\t\tmarks: readonly Mark[],\n\t): readonly TextSegment[] {\n\t\treturn segments.map(\n\t\t\t(s: TextSegment): TextSegment => ({\n\t\t\t\ttext: s.text,\n\t\t\t\tmarks: this.mergeMarks(marks, s.marks),\n\t\t\t}),\n\t\t);\n\t}\n\n\t/**\n\t * Parses a block element, splitting into multiple blocks at `<br>` boundaries.\n\t * `<br>` may appear at any nesting depth (e.g. inside `<b>` or `<span>`),\n\t * so we parse inline content first, then split the resulting segments at\n\t * the `\\n` characters produced by `<br>`.\n\t */\n\tprivate parseBlockWithLineBreaks(element: HTMLElement, blockType: NodeTypeName): SliceBlock[] {\n\t\tconst segments: readonly TextSegment[] = this.parseInlineChildren(element, []);\n\t\tconst hasLineBreak: boolean = segments.some((s: TextSegment) => s.text.includes('\\n'));\n\n\t\tif (!hasLineBreak) {\n\t\t\treturn [{ type: blockType, segments: this.ensureSegments(segments) }];\n\t\t}\n\n\t\tconst blocks: SliceBlock[] = [];\n\t\tlet current: TextSegment[] = [];\n\n\t\tfor (const segment of segments) {\n\t\t\tconst parts: readonly string[] = segment.text.split('\\n');\n\t\t\tfor (let i = 0; i < parts.length; i++) {\n\t\t\t\tif (i > 0) {\n\t\t\t\t\tblocks.push({\n\t\t\t\t\t\ttype: blockType,\n\t\t\t\t\t\tsegments: this.ensureSegments(this.normalizeSegments(current)),\n\t\t\t\t\t});\n\t\t\t\t\tcurrent = [];\n\t\t\t\t}\n\t\t\t\tconst part: string = parts[i] ?? '';\n\t\t\t\tif (part) {\n\t\t\t\t\tcurrent.push({ text: part, marks: segment.marks });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tblocks.push({\n\t\t\ttype: blockType,\n\t\t\tsegments: this.ensureSegments(this.normalizeSegments(current)),\n\t\t});\n\n\t\treturn blocks;\n\t}\n\n\tprivate flushPendingSegments(blocks: SliceBlock[], segments: TextSegment[]): void {\n\t\tconst normalized: TextSegment[] = this.normalizeSegments(segments);\n\t\tif (normalized.length === 0) return;\n\t\tif (normalized.every((s: TextSegment) => s.text.trim() === '')) return;\n\n\t\tblocks.push({\n\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\tsegments: normalized,\n\t\t});\n\t}\n}\n","/**\n * Normalizes legacy HTML elements to their modern CSS equivalents.\n * Converts {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font | <font>}\n * `color/face/size` attributes to `<span style=\"color/font-family/font-size\">`\n * so that DOMPurify + existing plugin parse rules handle them transparently.\n *\n * Must be called BEFORE DOMPurify sanitization.\n */\n\n/** Maps HTML `<font size>` values (1–7) to CSS font-size keywords per the HTML 4 spec. */\nconst FONT_SIZE_MAP: Readonly<Record<string, string>> = {\n\t'1': 'x-small',\n\t'2': 'small',\n\t'3': 'medium',\n\t'4': 'large',\n\t'5': 'x-large',\n\t'6': 'xx-large',\n\t'7': 'xxx-large',\n};\n\n/**\n * Normalizes legacy `<font>` elements in-place, converting them to `<span style=\"...\">`.\n *\n * - `color` attribute → `style.color`\n * - `face` attribute → `style.fontFamily`\n * - `size` attribute → mapped to CSS `font-size` keyword (unless inline `font-size` already set)\n * - `<font>` with no meaningful attributes → unwrapped (children promoted to parent)\n */\nexport function normalizeLegacyHTML(container: DocumentFragment | HTMLElement): void {\n\tconst fonts: HTMLElement[] = Array.from(container.querySelectorAll('font'));\n\n\tfor (const font of fonts) {\n\t\tconst color: string | null = font.getAttribute('color');\n\t\tconst face: string | null = font.getAttribute('face');\n\t\tconst size: string | null = font.getAttribute('size');\n\t\tconst existingStyle: string = font.getAttribute('style') ?? '';\n\n\t\tconst hasFormatting: boolean =\n\t\t\tcolor !== null || face !== null || size !== null || existingStyle.length > 0;\n\n\t\tif (!hasFormatting) {\n\t\t\tunwrap(font);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst span: HTMLSpanElement = document.createElement('span');\n\t\tconst styles: string[] = [];\n\n\t\tif (existingStyle) {\n\t\t\tstyles.push(existingStyle.endsWith(';') ? existingStyle : `${existingStyle};`);\n\t\t}\n\n\t\tif (color) {\n\t\t\tstyles.push(`color: ${color};`);\n\t\t}\n\n\t\tif (face) {\n\t\t\tstyles.push(`font-family: ${face};`);\n\t\t}\n\n\t\tif (size && !hasFontSizeInStyle(existingStyle)) {\n\t\t\tconst mapped: string | undefined = FONT_SIZE_MAP[size];\n\t\t\tif (mapped) {\n\t\t\t\tstyles.push(`font-size: ${mapped};`);\n\t\t\t}\n\t\t}\n\n\t\tspan.setAttribute('style', styles.join(' '));\n\n\t\tmoveChildren(font, span);\n\t\tfont.parentNode?.replaceChild(span, font);\n\t}\n}\n\n/** Checks whether an inline style string already contains a `font-size` declaration. */\nfunction hasFontSizeInStyle(style: string): boolean {\n\treturn style.toLowerCase().includes('font-size');\n}\n\n/** Moves all child nodes from `source` to `target`. */\nfunction moveChildren(source: Node, target: Node): void {\n\twhile (source.firstChild) {\n\t\ttarget.appendChild(source.firstChild);\n\t}\n}\n\n/** Unwraps an element, promoting its children into its parent. */\nfunction unwrap(element: HTMLElement): void {\n\tconst parent: Node | null = element.parentNode;\n\tif (!parent) return;\n\n\twhile (element.firstChild) {\n\t\tparent.insertBefore(element.firstChild, element);\n\t}\n\tparent.removeChild(element);\n}\n","/**\n * Paste handler: intercepts paste events and converts clipboard content to transactions.\n * Supports file paste via registered FileHandlers, plain text, and HTML.\n */\n\nimport DOMPurify from 'dompurify';\nimport { insertTextCommand } from '../commands/Commands.js';\nimport { pasteSlice } from '../commands/PasteCommand.js';\nimport {\n\ttype BlockAttrs,\n\ttype BlockNode,\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgetBlockText,\n\tisBlockNode,\n} from '../model/Document.js';\nimport { generateBlockId } from '../model/Document.js';\nimport { HTMLParser } from '../model/HTMLParser.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { AttrSpec } from '../model/NodeSpec.js';\nimport { schemaFromRegistry } from '../model/Schema.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport { nodeType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { FileHandlerRegistry } from './FileHandlerRegistry.js';\nimport type { DispatchFn, GetStateFn } from './InputHandler.js';\nimport { type RichBlockData, consumeRichClipboard } from './InternalClipboard.js';\nimport { normalizeLegacyHTML } from './LegacyHTMLNormalizer.js';\n\n/**\n * Validates incoming attributes against the declared AttrSpec.\n * Only keys declared in the spec are kept; non-primitive values fall back to defaults.\n */\nfunction sanitizeAttrs(\n\tincoming: Record<string, unknown> | undefined,\n\tspecAttrs: Readonly<Record<string, AttrSpec>> | undefined,\n): Record<string, string | number | boolean> | undefined {\n\tif (!specAttrs) return undefined;\n\n\tconst result: Record<string, string | number | boolean> = {};\n\tlet hasKeys = false;\n\n\tfor (const key of Object.keys(specAttrs)) {\n\t\tconst spec: AttrSpec = specAttrs[key] as AttrSpec;\n\t\tconst raw: unknown = incoming?.[key];\n\n\t\tif (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {\n\t\t\tresult[key] = raw;\n\t\t} else if (spec.default !== undefined) {\n\t\t\tresult[key] = spec.default;\n\t\t}\n\t\tif (key in result) hasKeys = true;\n\t}\n\n\treturn hasKeys ? result : undefined;\n}\n\nexport interface PasteHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tschemaRegistry?: SchemaRegistry;\n\tfileHandlerRegistry?: FileHandlerRegistry;\n\tisReadOnly?: () => boolean;\n}\n\nexport class PasteHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate readonly fileHandlerRegistry?: FileHandlerRegistry;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate readonly handlePaste: (e: ClipboardEvent) => void;\n\n\tconstructor(\n\t\tprivate readonly element: HTMLElement,\n\t\toptions: PasteHandlerOptions,\n\t) {\n\t\tthis.getState = options.getState;\n\t\tthis.dispatch = options.dispatch;\n\t\tthis.schemaRegistry = options.schemaRegistry;\n\t\tthis.fileHandlerRegistry = options.fileHandlerRegistry;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\n\t\tthis.handlePaste = this.onPaste.bind(this);\n\t\telement.addEventListener('paste', this.handlePaste);\n\t}\n\n\tprivate onPaste(e: ClipboardEvent): void {\n\t\te.preventDefault();\n\t\tif (this.isReadOnly()) return;\n\n\t\tconst clipboardData = e.clipboardData;\n\t\tif (!clipboardData) return;\n\n\t\t// Check for internal block paste (from ClipboardHandler)\n\t\tconst blockJson: string = clipboardData.getData('application/x-notectl-block');\n\t\tif (blockJson) {\n\t\t\tthis.handleBlockPaste(blockJson);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for file paste first\n\t\tif (this.handleFilePaste(clipboardData)) return;\n\n\t\t// Check in-memory rich clipboard (block structure from our own copy)\n\t\tconst plainText: string = clipboardData.getData('text/plain');\n\t\tif (plainText) {\n\t\t\tconst richBlocks: readonly RichBlockData[] | undefined = consumeRichClipboard(plainText);\n\t\t\tif (richBlocks && this.handleRichPaste(richBlocks)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst state = this.getState();\n\n\t\t// Try HTML first, fall back to plain text\n\t\tconst html = clipboardData.getData('text/html');\n\t\tif (html) {\n\t\t\t// Check for embedded rich block data (from programmatic paste)\n\t\t\tconst richJson: string | undefined = this.extractRichData(html);\n\t\t\tif (richJson && this.handleRichPasteFromJson(richJson)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Normalize legacy elements (e.g. <font>) before sanitization\n\t\t\tconst preTemplate: HTMLTemplateElement = document.createElement('template');\n\t\t\tpreTemplate.innerHTML = html;\n\t\t\tnormalizeLegacyHTML(preTemplate.content);\n\t\t\tconst normalizedHTML: string = preTemplate.innerHTML;\n\n\t\t\tconst allowedTags: string[] = this.schemaRegistry\n\t\t\t\t? this.schemaRegistry.getAllowedTags()\n\t\t\t\t: ['strong', 'em', 'u', 'b', 'i', 'p', 'br', 'div', 'span'];\n\t\t\tconst allowedAttrs: string[] = this.schemaRegistry\n\t\t\t\t? this.schemaRegistry.getAllowedAttrs()\n\t\t\t\t: [];\n\t\t\tconst sanitized = DOMPurify.sanitize(normalizedHTML, {\n\t\t\t\tALLOWED_TAGS: allowedTags,\n\t\t\t\tALLOWED_ATTR: allowedAttrs,\n\t\t\t});\n\n\t\t\tif (this.schemaRegistry) {\n\t\t\t\tconst schema = schemaFromRegistry(this.schemaRegistry);\n\t\t\t\tconst parser = new HTMLParser({ schema, schemaRegistry: this.schemaRegistry });\n\t\t\t\tconst template = document.createElement('template');\n\t\t\t\ttemplate.innerHTML = sanitized;\n\t\t\t\tconst slice = parser.parse(template.content);\n\t\t\t\tconst tr = pasteSlice(state, slice);\n\t\t\t\tthis.dispatch(tr);\n\t\t\t} else {\n\t\t\t\tconst text = this.extractTextFromHTML(sanitized);\n\t\t\t\tif (text) {\n\t\t\t\t\tconst tr = insertTextCommand(state, text, 'paste');\n\t\t\t\t\tthis.dispatch(tr);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (plainText) {\n\t\t\tconst tr = insertTextCommand(this.getState(), plainText, 'paste');\n\t\t\tthis.dispatch(tr);\n\t\t}\n\t}\n\n\t/** Handles paste of an internal block node from ClipboardHandler. */\n\tprivate handleBlockPaste(json: string): void {\n\t\tlet parsed: { type?: string; attrs?: Record<string, unknown> };\n\t\ttry {\n\t\t\tparsed = JSON.parse(json) as { type?: string; attrs?: Record<string, unknown> };\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\n\t\tconst typeName: string | undefined = parsed.type;\n\t\tif (!typeName) return;\n\n\t\t// Validate that this type is known (if we have a registry)\n\t\tconst spec = this.schemaRegistry?.getNodeSpec(typeName);\n\t\tif (this.schemaRegistry && !spec) return;\n\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\n\t\t// Find anchor block to insert after\n\t\tconst anchorBlockId: BlockId = isNodeSelection(sel)\n\t\t\t? sel.nodeId\n\t\t\t: isGapCursor(sel)\n\t\t\t\t? sel.blockId\n\t\t\t\t: sel.anchor.blockId;\n\n\t\tconst newBlockId: BlockId = generateBlockId();\n\t\tconst attrs: BlockAttrs | undefined = sanitizeAttrs(parsed.attrs, spec?.attrs) as\n\t\t\t| BlockAttrs\n\t\t\t| undefined;\n\t\tconst newBlock: BlockNode = createBlockNode(\n\t\t\tnodeType(typeName) as NodeTypeName,\n\t\t\t[],\n\t\t\tnewBlockId,\n\t\t\tattrs,\n\t\t);\n\n\t\t// Check if we're inside a table cell — insert as child of cell\n\t\tconst cellId: BlockId | undefined = this.findTableCellAncestor(state, anchorBlockId);\n\t\tif (cellId) {\n\t\t\tconst cellPath: BlockId[] | undefined = findNodePath(state.doc, cellId) as\n\t\t\t\t| BlockId[]\n\t\t\t\t| undefined;\n\t\t\tif (!cellPath) return;\n\n\t\t\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\t\t\tif (!cell) return;\n\n\t\t\tconst builder = state.transaction('paste');\n\t\t\tbuilder.insertNode(cellPath, cell.children.length, newBlock);\n\t\t\tbuilder.setSelection(createNodeSelection(newBlockId, [...cellPath, newBlockId]));\n\t\t\tthis.dispatch(builder.build());\n\t\t\treturn;\n\t\t}\n\n\t\t// Default: insert after the anchor block at the same level\n\t\tconst path = findNodePath(state.doc, anchorBlockId);\n\t\tconst parentPath: BlockId[] = path && path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\n\t\tconst siblings: readonly (BlockNode | import('../model/Document.js').ChildNode)[] =\n\t\t\tparentPath.length === 0\n\t\t\t\t? state.doc.children\n\t\t\t\t: (() => {\n\t\t\t\t\t\tconst parent = state.getBlock(parentPath[parentPath.length - 1] as BlockId);\n\t\t\t\t\t\treturn parent ? parent.children : [];\n\t\t\t\t\t})();\n\n\t\tconst index: number = siblings.findIndex((c) => isBlockNode(c) && c.id === anchorBlockId);\n\t\tif (index < 0) return;\n\n\t\tconst insertOffset: number = isGapCursor(sel) && sel.side === 'before' ? 0 : 1;\n\t\tconst builder = state.transaction('paste');\n\t\tbuilder.insertNode(parentPath, index + insertOffset, newBlock);\n\t\tbuilder.setSelection(createNodeSelection(newBlockId, [...parentPath, newBlockId]));\n\n\t\tthis.dispatch(builder.build());\n\t}\n\n\t/** Parses JSON and delegates to handleRichPaste (for HTML-embedded data). */\n\tprivate handleRichPasteFromJson(json: string): boolean {\n\t\tlet blocks: RichBlockData[];\n\t\ttry {\n\t\t\tblocks = JSON.parse(json) as RichBlockData[];\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t\tif (!Array.isArray(blocks) || blocks.length === 0) return false;\n\t\treturn this.handleRichPaste(blocks);\n\t}\n\n\t/**\n\t * Handles paste of rich block data (text selections that carry block structure).\n\t * Returns true if the paste was handled, false to fall through to plain-text paste.\n\t */\n\tprivate handleRichPaste(blocks: readonly RichBlockData[]): boolean {\n\t\tif (blocks.length === 0) return false;\n\n\t\t// Only use rich paste for structured blocks (list_item, heading, etc.)\n\t\tconst hasStructured: boolean = blocks.some(\n\t\t\t(b) => b.type !== undefined && b.type !== 'paragraph',\n\t\t);\n\t\tif (!hasStructured) return false;\n\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\t\tconst anchorBlockId: BlockId = isNodeSelection(sel)\n\t\t\t? sel.nodeId\n\t\t\t: isGapCursor(sel)\n\t\t\t\t? sel.blockId\n\t\t\t\t: sel.anchor.blockId;\n\n\t\tconst cellId: BlockId | undefined = this.findTableCellAncestor(state, anchorBlockId);\n\n\t\tif (cellId) {\n\t\t\treturn this.insertRichBlocksIntoCell(blocks, state, anchorBlockId, cellId);\n\t\t}\n\t\treturn this.insertRichBlocksAtRoot(blocks, state, anchorBlockId);\n\t}\n\n\t/** Inserts rich blocks as children of a table cell. */\n\tprivate insertRichBlocksIntoCell(\n\t\tblocks: readonly RichBlockData[],\n\t\tstate: EditorState,\n\t\tanchorBlockId: BlockId,\n\t\tcellId: BlockId,\n\t): boolean {\n\t\tconst cellPath: BlockId[] | undefined = findNodePath(state.doc, cellId) as\n\t\t\t| BlockId[]\n\t\t\t| undefined;\n\t\tif (!cellPath) return false;\n\n\t\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\t\tif (!cell) return false;\n\n\t\tconst anchorBlock: BlockNode | undefined = state.getBlock(anchorBlockId);\n\t\tconst anchorIndex: number = cell.children.findIndex(\n\t\t\t(c) => isBlockNode(c) && c.id === anchorBlockId,\n\t\t);\n\t\tconst isAnchorEmpty: boolean =\n\t\t\tanchorBlock !== undefined &&\n\t\t\tanchorBlock.type === 'paragraph' &&\n\t\t\tgetBlockText(anchorBlock) === '';\n\n\t\tlet insertIndex: number = anchorIndex >= 0 ? anchorIndex + 1 : cell.children.length;\n\t\tconst builder = state.transaction('paste');\n\t\tlet lastBlockId: BlockId | undefined;\n\t\tlet lastTextLen = 0;\n\n\t\tfor (const raw of blocks) {\n\t\t\tconst blockData: RichBlockData | undefined = this.validateRichBlockData(raw);\n\t\t\tif (!blockData) continue;\n\n\t\t\tconst newId: BlockId = generateBlockId();\n\t\t\tconst text: string = blockData.text ?? '';\n\t\t\tconst children = text ? [createTextNode(text)] : undefined;\n\t\t\tconst attrs: BlockAttrs | undefined = blockData.attrs\n\t\t\t\t? (blockData.attrs as BlockAttrs)\n\t\t\t\t: undefined;\n\n\t\t\tconst newBlock: BlockNode = createBlockNode(\n\t\t\t\tnodeType(blockData.type) as NodeTypeName,\n\t\t\t\tchildren,\n\t\t\t\tnewId,\n\t\t\t\tattrs,\n\t\t\t);\n\n\t\t\tbuilder.insertNode(cellPath, insertIndex, newBlock);\n\t\t\tinsertIndex++;\n\t\t\tlastBlockId = newId;\n\t\t\tlastTextLen = text.length;\n\t\t}\n\n\t\t// Remove the empty anchor paragraph (it is still at anchorIndex in the working doc)\n\t\tif (isAnchorEmpty && anchorIndex >= 0) {\n\t\t\tbuilder.removeNode(cellPath, anchorIndex);\n\t\t}\n\n\t\tif (lastBlockId) {\n\t\t\tbuilder.setSelection(createCollapsedSelection(lastBlockId, lastTextLen));\n\t\t}\n\n\t\tthis.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\t/** Inserts rich blocks after the anchor block at the root/parent level. */\n\tprivate insertRichBlocksAtRoot(\n\t\tblocks: readonly RichBlockData[],\n\t\tstate: EditorState,\n\t\tanchorBlockId: BlockId,\n\t): boolean {\n\t\tconst path = findNodePath(state.doc, anchorBlockId);\n\t\tconst parentPath: BlockId[] = path && path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\n\t\tconst siblings: readonly (BlockNode | import('../model/Document.js').ChildNode)[] =\n\t\t\tparentPath.length === 0\n\t\t\t\t? state.doc.children\n\t\t\t\t: (() => {\n\t\t\t\t\t\tconst parent = state.getBlock(parentPath[parentPath.length - 1] as BlockId);\n\t\t\t\t\t\treturn parent ? parent.children : [];\n\t\t\t\t\t})();\n\n\t\tconst anchorIndex: number = siblings.findIndex((c) => isBlockNode(c) && c.id === anchorBlockId);\n\t\tif (anchorIndex < 0) return false;\n\n\t\tconst anchorBlock: BlockNode | undefined = state.getBlock(anchorBlockId);\n\t\tconst isAnchorEmpty: boolean =\n\t\t\tanchorBlock !== undefined &&\n\t\t\tanchorBlock.type === 'paragraph' &&\n\t\t\tgetBlockText(anchorBlock) === '';\n\n\t\tconst sel = state.selection;\n\t\tconst insertOffset: number = isGapCursor(sel) && sel.side === 'before' ? 0 : 1;\n\t\tlet insertIndex: number = anchorIndex + insertOffset;\n\t\tconst builder = state.transaction('paste');\n\t\tlet lastBlockId: BlockId | undefined;\n\t\tlet lastTextLen = 0;\n\n\t\tfor (const raw of blocks) {\n\t\t\tconst blockData: RichBlockData | undefined = this.validateRichBlockData(raw);\n\t\t\tif (!blockData) continue;\n\n\t\t\tconst newId: BlockId = generateBlockId();\n\t\t\tconst text: string = blockData.text ?? '';\n\t\t\tconst children = text ? [createTextNode(text)] : undefined;\n\t\t\tconst attrs: BlockAttrs | undefined = blockData.attrs\n\t\t\t\t? (blockData.attrs as BlockAttrs)\n\t\t\t\t: undefined;\n\n\t\t\tconst newBlock: BlockNode = createBlockNode(\n\t\t\t\tnodeType(blockData.type) as NodeTypeName,\n\t\t\t\tchildren,\n\t\t\t\tnewId,\n\t\t\t\tattrs,\n\t\t\t);\n\n\t\t\tbuilder.insertNode(parentPath, insertIndex, newBlock);\n\t\t\tinsertIndex++;\n\t\t\tlastBlockId = newId;\n\t\t\tlastTextLen = text.length;\n\t\t}\n\n\t\t// Remove the empty anchor paragraph (don't remove void blocks at gap cursor)\n\t\tif (isAnchorEmpty && !isGapCursor(sel)) {\n\t\t\tbuilder.removeNode(parentPath, anchorIndex);\n\t\t}\n\n\t\tif (lastBlockId) {\n\t\t\tbuilder.setSelection(createCollapsedSelection(lastBlockId, lastTextLen));\n\t\t}\n\n\t\tthis.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\t/** Validates a rich block against the schema registry. Returns undefined for invalid blocks. */\n\tprivate validateRichBlockData(raw: RichBlockData): RichBlockData | undefined {\n\t\tif (!raw.type) return undefined;\n\n\t\tif (!this.schemaRegistry) return raw;\n\n\t\tconst spec = this.schemaRegistry.getNodeSpec(raw.type);\n\t\tif (!spec) return undefined;\n\n\t\tconst attrs: Record<string, string | number | boolean> | undefined = sanitizeAttrs(\n\t\t\traw.attrs,\n\t\t\tspec.attrs,\n\t\t);\n\n\t\treturn { ...raw, attrs };\n\t}\n\n\t/** Finds a table_cell ancestor for the given block (or the block itself). */\n\tprivate findTableCellAncestor(state: EditorState, blockId: BlockId): BlockId | undefined {\n\t\tconst block: BlockNode | undefined = state.getBlock(blockId);\n\t\tif (block?.type === 'table_cell') return blockId;\n\n\t\tconst path: BlockId[] | undefined = findNodePath(state.doc, blockId) as BlockId[] | undefined;\n\t\tif (!path) return undefined;\n\n\t\tfor (const id of path) {\n\t\t\tconst node: BlockNode | undefined = state.getBlock(id as BlockId);\n\t\t\tif (node?.type === 'table_cell') return id as BlockId;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Checks for files in clipboard data and delegates to registered handlers. */\n\tprivate handleFilePaste(clipboardData: DataTransfer): boolean {\n\t\tif (!this.fileHandlerRegistry) return false;\n\n\t\t// Check clipboardData.files first\n\t\tconst files: File[] = Array.from(clipboardData.files);\n\n\t\t// Also check items for file entries (some browsers use items instead)\n\t\tif (files.length === 0) {\n\t\t\tfor (let i = 0; i < clipboardData.items.length; i++) {\n\t\t\t\tconst item = clipboardData.items[i];\n\t\t\t\tif (item && item.kind === 'file') {\n\t\t\t\t\tconst file = item.getAsFile();\n\t\t\t\t\tif (file) files.push(file);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (files.length === 0) return false;\n\n\t\tlet handled = false;\n\t\tfor (const file of files) {\n\t\t\tconst handlers = this.fileHandlerRegistry.matchFileHandlers(file.type);\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = handler(file, null);\n\t\t\t\tif (result === true || result instanceof Promise) {\n\t\t\t\t\thandled = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn handled;\n\t}\n\n\t/** Extracts embedded rich block JSON from HTML (data-notectl-rich attribute). */\n\tprivate extractRichData(html: string): string | undefined {\n\t\tconst template = document.createElement('template');\n\t\ttemplate.innerHTML = html;\n\t\tconst richEl: Element | null = template.content.querySelector('[data-notectl-rich]');\n\t\tif (!richEl) return undefined;\n\t\treturn richEl.getAttribute('data-notectl-rich') ?? undefined;\n\t}\n\n\tprivate extractTextFromHTML(html: string): string {\n\t\tconst template = document.createElement('template');\n\t\ttemplate.innerHTML = html;\n\t\treturn template.content.textContent ?? '';\n\t}\n\n\tdestroy(): void {\n\t\tthis.element.removeEventListener('paste', this.handlePaste);\n\t}\n}\n","/**\n * Reconciler: diffs old and new state and applies minimal DOM patches.\n * Uses block-level granularity — changed blocks are re-rendered entirely.\n * Supports plugin-registered NodeSpecs, MarkSpecs, and NodeViews via SchemaRegistry.\n */\n\nimport type { Decoration, DecorationAttrs, InlineDecoration } from '../decorations/Decoration.js';\nimport { type DecorationSet, decorationArraysEqual } from '../decorations/Decoration.js';\nimport type { NodeAttrsFor } from '../model/AttrRegistry.js';\nimport type { BlockNode, InlineNode, TextNode } from '../model/Document.js';\nimport {\n\tgetBlockChildren,\n\tgetInlineChildren,\n\tisInlineNode,\n\tisLeafBlock,\n\tisTextNode,\n\tmarkSetsEqual,\n} from '../model/Document.js';\nimport { createBlockElement } from '../model/NodeSpec.js';\nimport type { WrapperSpec } from '../model/NodeSpec.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport { blockId as toBlockId } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport { createMarkElement, getMarkRank } from './MarkRendering.js';\nimport type { NodeView } from './NodeView.js';\nimport type { NodeViewRegistry } from './NodeViewRegistry.js';\n\nexport interface ReconcileOptions {\n\tregistry?: SchemaRegistry;\n\tnodeViewRegistry?: NodeViewRegistry;\n\tnodeViews?: Map<string, NodeView>;\n\tgetState?: () => EditorState;\n\tdispatch?: (tr: import('../state/Transaction.js').Transaction) => void;\n\tdecorations?: DecorationSet;\n\toldDecorations?: DecorationSet;\n\tselectedNodeId?: BlockId;\n\tpreviousSelectedNodeId?: BlockId;\n\t/** When set, the block with this ID is skipped during reconciliation to preserve IME composition. */\n\tcompositionBlockId?: BlockId;\n}\n\n/** Reconciles the DOM container to match the new state. */\nexport function reconcile(\n\tcontainer: HTMLElement,\n\toldState: EditorState | null,\n\tnewState: EditorState,\n\toptions?: ReconcileOptions,\n): void {\n\tconst oldBlocks = oldState?.doc.children ?? [];\n\tconst newBlocks = newState.doc.children;\n\tconst registry = options?.registry;\n\tconst nodeViews = options?.nodeViews;\n\n\t// Unwrap blocks from existing wrapper elements (e.g. <ul>/<ol>)\n\t// so the main reconciliation loop sees all blocks as direct children.\n\t// Skip during active IME composition — moving DOM nodes breaks the browser's\n\t// composition session. Wrappers are structural (based on block types) and\n\t// don't change during text composition; the next non-composing reconcile will fix them.\n\tconst isComposing = options?.compositionBlockId != null;\n\tif (!isComposing) {\n\t\tunwrapBlocks(container);\n\t}\n\n\tconst oldBlockMap = new Map<BlockId, HTMLElement>();\n\tfor (const el of getRenderedBlockElements(container)) {\n\t\tconst bid = el.getAttribute('data-block-id');\n\t\tif (bid) oldBlockMap.set(toBlockId(bid), el);\n\t}\n\n\t// Build set of new block IDs for removal detection\n\tconst newBlockIds = new Set(newBlocks.map((b) => b.id));\n\n\t// Remove blocks that no longer exist\n\tfor (const [blockId, el] of oldBlockMap) {\n\t\tif (!newBlockIds.has(blockId)) {\n\t\t\tremoveBlockElement(el);\n\t\t\toldBlockMap.delete(blockId);\n\t\t\t// Destroy NodeView if exists\n\t\t\tconst nv = nodeViews?.get(blockId);\n\t\t\tif (nv) {\n\t\t\t\tnv.destroy?.();\n\t\t\t\tnodeViews?.delete(blockId);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Mapping from old state for change detection\n\tconst oldBlockById = new Map<string, BlockNode>();\n\tfor (const block of oldBlocks) {\n\t\toldBlockById.set(block.id, block);\n\t}\n\n\t// Insert/update blocks in order\n\tlet previousSibling: Element | null = null;\n\n\tconst selectedNodeId = options?.selectedNodeId;\n\tconst previousSelectedNodeId = options?.previousSelectedNodeId;\n\n\tfor (const block of newBlocks) {\n\t\tconst existingEl = oldBlockMap.get(block.id);\n\t\tconst oldBlock = oldBlockById.get(block.id);\n\n\t\t// Skip reconciliation for the block under active IME composition\n\t\tif (options?.compositionBlockId === block.id && existingEl) {\n\t\t\tpreviousSibling = existingEl;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst oldDecos = options?.oldDecorations?.find(block.id);\n\t\tconst newDecos = options?.decorations?.find(block.id);\n\n\t\tif (existingEl && oldBlock && !blockChanged(oldBlock, block, oldDecos, newDecos)) {\n\t\t\t// Block unchanged — keep existing DOM\n\t\t\tpreviousSibling = existingEl;\n\t\t} else if (existingEl) {\n\t\t\t// Block changed — try NodeView update first\n\t\t\tconst existingNv = nodeViews?.get(block.id);\n\t\t\tif (existingNv) {\n\t\t\t\tconst handled = existingNv.update?.(block) ?? false;\n\t\t\t\tif (handled) {\n\t\t\t\t\t// Re-render inline content into contentDOM for leaf blocks\n\t\t\t\t\tif (isLeafBlock(block) && existingNv.contentDOM) {\n\t\t\t\t\t\texistingNv.contentDOM.textContent = '';\n\t\t\t\t\t\tconst updatedInlineDecos = options?.decorations?.findInline(block.id);\n\t\t\t\t\t\trenderBlockContent(existingNv.contentDOM, block, registry, updatedInlineDecos);\n\t\t\t\t\t}\n\t\t\t\t\tpreviousSibling = existingNv.dom;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Update not handled — destroy and re-create\n\t\t\t\texistingNv.destroy?.();\n\t\t\t\tnodeViews?.delete(block.id);\n\t\t\t}\n\n\t\t\tconst newEl = renderBlock(block, registry, nodeViews, options);\n\t\t\treplaceBlockElement(existingEl, newEl, container);\n\t\t\tpreviousSibling = newEl;\n\t\t} else {\n\t\t\t// New block — insert after previousSibling\n\t\t\tconst newEl = renderBlock(block, registry, nodeViews, options);\n\t\t\tinsertAfterPreviousSibling(container, previousSibling, newEl);\n\t\t\tpreviousSibling = newEl;\n\t\t}\n\n\t\t// Handle NodeSelection visual state (CSS class only — aria-selected is\n\t\t// invalid on generic block elements like <figure>, <pre>, etc.)\n\t\tif (selectedNodeId === block.id) {\n\t\t\tconst nv = nodeViews?.get(block.id);\n\t\t\tif (nv) {\n\t\t\t\tnv.selectNode?.();\n\t\t\t} else {\n\t\t\t\tconst el = oldBlockMap.get(block.id) ?? previousSibling;\n\t\t\t\tif (el instanceof HTMLElement) {\n\t\t\t\t\tel.classList.add('notectl-node-selected');\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (previousSelectedNodeId === block.id) {\n\t\t\tconst nv = nodeViews?.get(block.id);\n\t\t\tif (nv) {\n\t\t\t\tnv.deselectNode?.();\n\t\t\t} else {\n\t\t\t\tconst el = oldBlockMap.get(block.id) ?? previousSibling;\n\t\t\t\tif (el instanceof HTMLElement) {\n\t\t\t\t\tel.classList.remove('notectl-node-selected');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Handle selection for nested NodeViews (e.g. images inside table cells)\n\tif (previousSelectedNodeId && previousSelectedNodeId !== selectedNodeId) {\n\t\tconst nested = nodeViews?.get(previousSelectedNodeId);\n\t\tif (nested && !newBlockIds.has(previousSelectedNodeId)) {\n\t\t\tnested.deselectNode?.();\n\t\t}\n\t}\n\tif (selectedNodeId && !newBlockIds.has(selectedNodeId)) {\n\t\tconst nested = nodeViews?.get(selectedNodeId);\n\t\tif (nested) {\n\t\t\tnested.selectNode?.();\n\t\t}\n\t}\n\n\t// Group consecutive blocks into wrapper elements (e.g. <ul>/<ol> for list items)\n\tif (!isComposing) {\n\t\twrapBlocks(container, newBlocks, registry);\n\t}\n}\n\n/** Checks whether a block has changed by comparing its children, attrs, and decorations. */\nfunction blockChanged(\n\toldBlock: BlockNode,\n\tnewBlock: BlockNode,\n\toldDecos?: readonly Decoration[],\n\tnewDecos?: readonly Decoration[],\n): boolean {\n\tif (oldBlock.type !== newBlock.type) return true;\n\tif (oldBlock.children.length !== newBlock.children.length) return true;\n\n\t// Compare attrs\n\tconst oldAttrs = oldBlock.attrs;\n\tconst newAttrs = newBlock.attrs;\n\tif (oldAttrs !== newAttrs) {\n\t\tif (!oldAttrs || !newAttrs) return true;\n\t\tconst oldKeys = Object.keys(oldAttrs);\n\t\tconst newKeys = Object.keys(newAttrs);\n\t\tif (oldKeys.length !== newKeys.length) return true;\n\t\tfor (const key of oldKeys) {\n\t\t\tif (oldAttrs[key] !== newAttrs[key]) return true;\n\t\t}\n\t}\n\n\tfor (let i = 0; i < oldBlock.children.length; i++) {\n\t\tconst oldChild = oldBlock.children[i];\n\t\tconst newChild = newBlock.children[i];\n\t\tif (!oldChild || !newChild) return true;\n\n\t\tif (isTextNode(oldChild) && isTextNode(newChild)) {\n\t\t\tif (oldChild.text !== newChild.text) return true;\n\t\t\tif (!markSetsEqual(oldChild.marks, newChild.marks)) return true;\n\t\t} else if (isInlineNode(oldChild) && isInlineNode(newChild)) {\n\t\t\tif (oldChild.inlineType !== newChild.inlineType) return true;\n\t\t\tif (!inlineAttrsEqual(oldChild.attrs, newChild.attrs)) return true;\n\t\t} else if (\n\t\t\t!isTextNode(oldChild) &&\n\t\t\t!isTextNode(newChild) &&\n\t\t\t!isInlineNode(oldChild) &&\n\t\t\t!isInlineNode(newChild)\n\t\t) {\n\t\t\t// Both are BlockNodes — compare recursively\n\t\t\tif (blockChanged(oldChild as BlockNode, newChild as BlockNode)) return true;\n\t\t} else {\n\t\t\t// Different child types\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Compare decorations\n\tconst oldArr = oldDecos ?? [];\n\tconst newArr = newDecos ?? [];\n\tif (oldArr !== newArr && !decorationArraysEqual(oldArr, newArr)) return true;\n\n\treturn false;\n}\n\n/** Renders a block node to a DOM element, using registry specs or NodeViews. */\nexport function renderBlock(\n\tblock: BlockNode,\n\tregistry?: SchemaRegistry,\n\tnodeViews?: Map<string, NodeView>,\n\toptions?: ReconcileOptions,\n): HTMLElement {\n\tconst inlineDecos = options?.decorations?.findInline(block.id);\n\n\t// 1. Try NodeViewFactory\n\tconst nodeViewRegistry = options?.nodeViewRegistry;\n\tif (nodeViewRegistry && registry && nodeViews && options?.getState && options?.dispatch) {\n\t\tconst factory = nodeViewRegistry.getNodeViewFactory(block.type);\n\t\tif (factory) {\n\t\t\tconst nv = factory(block, options.getState, options.dispatch);\n\t\t\tnodeViews.set(block.id, nv);\n\n\t\t\t// Mark void blocks\n\t\t\tconst nvSpec = registry.getNodeSpec(block.type);\n\t\t\tif (nvSpec?.isVoid) {\n\t\t\t\tnv.dom.setAttribute('data-void', 'true');\n\t\t\t}\n\t\t\tif (nvSpec?.selectable) {\n\t\t\t\tnv.dom.setAttribute('data-selectable', 'true');\n\t\t\t}\n\n\t\t\t// Mark contentDOM so SelectionSync can find it\n\t\t\tif (nv.contentDOM && nv.contentDOM !== nv.dom) {\n\t\t\t\tnv.contentDOM.setAttribute('data-content-dom', 'true');\n\t\t\t}\n\n\t\t\t// Render children into NodeView content area\n\t\t\tif (isLeafBlock(block) && nv.contentDOM) {\n\t\t\t\t// Leaf blocks: render inline content (TextNodes) into contentDOM\n\t\t\t\trenderBlockContent(nv.contentDOM, block, registry, inlineDecos);\n\t\t\t} else {\n\t\t\t\t// Container blocks: recursively render block children\n\t\t\t\tconst blockChildren = getBlockChildren(block);\n\t\t\t\tconst contentDOMChildren = new Map<HTMLElement, BlockNode[]>();\n\t\t\t\tfor (const child of blockChildren) {\n\t\t\t\t\tconst contentDOM = nv.getContentDOM?.(child.id) ?? nv.contentDOM;\n\t\t\t\t\tif (contentDOM) {\n\t\t\t\t\t\tconst childEl = renderBlock(child, registry, nodeViews, options);\n\t\t\t\t\t\tcontentDOM.appendChild(childEl);\n\t\t\t\t\t\tlet arr = contentDOMChildren.get(contentDOM);\n\t\t\t\t\t\tif (!arr) {\n\t\t\t\t\t\t\tarr = [];\n\t\t\t\t\t\t\tcontentDOMChildren.set(contentDOM, arr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tarr.push(child);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Wrap blocks in each contentDOM (e.g., list items in table cells → <ul>/<ol>)\n\t\t\t\tfor (const [dom, children] of contentDOMChildren) {\n\t\t\t\t\twrapBlocks(dom, children, registry);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnv.dom.setAttribute('data-block-type', block.type);\n\t\t\tapplyNodeDecorations(nv.dom, block.id, options);\n\t\t\treturn nv.dom;\n\t\t}\n\t}\n\n\t// 2. Try NodeSpec\n\tif (registry) {\n\t\tconst spec = registry.getNodeSpec(block.type);\n\t\tif (spec) {\n\t\t\tconst el = spec.toDOM(\n\t\t\t\tblock as Omit<BlockNode, 'attrs'> & { readonly attrs: NodeAttrsFor<string> },\n\t\t\t);\n\t\t\tif (spec.isVoid) {\n\t\t\t\tel.setAttribute('data-void', 'true');\n\t\t\t}\n\t\t\tif (spec.selectable) {\n\t\t\t\tel.setAttribute('data-selectable', 'true');\n\t\t\t}\n\t\t\tif (!spec.isVoid) {\n\t\t\t\tif (isLeafBlock(block)) {\n\t\t\t\t\trenderBlockContent(el, block, registry, inlineDecos);\n\t\t\t\t} else {\n\t\t\t\t\t// Render block children recursively\n\t\t\t\t\tconst blockChildren = getBlockChildren(block);\n\t\t\t\t\tfor (const child of blockChildren) {\n\t\t\t\t\t\tconst childEl = renderBlock(child, registry, nodeViews, options);\n\t\t\t\t\t\tel.appendChild(childEl);\n\t\t\t\t\t}\n\t\t\t\t\t// Wrap blocks (e.g., list items → <ul>/<ol>)\n\t\t\t\t\twrapBlocks(el, blockChildren, registry);\n\t\t\t\t}\n\t\t\t}\n\t\t\tel.setAttribute('data-block-type', block.type);\n\t\t\tapplyNodeDecorations(el, block.id, options);\n\t\t\treturn el;\n\t\t}\n\t}\n\n\t// 3. Fallback — render as paragraph\n\treturn renderParagraphFallback(block, registry, inlineDecos);\n}\n\n/** Renders block content (inline children) into a container element. */\nexport function renderBlockContent(\n\tcontainer: HTMLElement,\n\tblock: BlockNode,\n\tregistry?: SchemaRegistry,\n\tinlineDecos?: readonly InlineDecoration[],\n): void {\n\t// Remove stale CursorWrapper spans that may survive into reconciliation\n\tfor (const el of container.querySelectorAll('[data-cursor-wrapper]')) {\n\t\tel.remove();\n\t}\n\n\tconst inlineChildren = getInlineChildren(block);\n\n\t// Empty block: single empty text node → render <br> placeholder\n\tif (\n\t\tinlineChildren.length === 1 &&\n\t\tisTextNode(inlineChildren[0]) &&\n\t\tinlineChildren[0].text === ''\n\t) {\n\t\tcontainer.appendChild(document.createElement('br'));\n\t\treturn;\n\t}\n\n\t// Fast path: no inline decorations\n\tif (!inlineDecos || inlineDecos.length === 0) {\n\t\tfor (const child of inlineChildren) {\n\t\t\tif (isTextNode(child)) {\n\t\t\t\tcontainer.appendChild(renderTextNode(child, registry));\n\t\t\t} else {\n\t\t\t\tcontainer.appendChild(renderInlineNode(child, registry));\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Decorated path: split content into micro-segments\n\t\trenderDecoratedContent(container, inlineChildren, inlineDecos, registry);\n\t}\n\n\t// Trailing <br> hack: when the last child is a hard_break InlineNode,\n\t// browsers won't render an empty line after a trailing <br>.\n\t// Append an extra plain <br> (without contenteditable=\"false\") so the\n\t// cursor can be placed on the new line. SelectionSync skips non-\n\t// contenteditable, non-text elements, so offset counting stays correct.\n\tconst lastChild = inlineChildren[inlineChildren.length - 1];\n\tif (lastChild && isInlineNode(lastChild) && lastChild.inlineType === 'hard_break') {\n\t\tcontainer.appendChild(document.createElement('br'));\n\t}\n}\n\n/** Fallback paragraph rendering when no NodeSpec is found. */\nfunction renderParagraphFallback(\n\tblock: BlockNode,\n\tregistry?: SchemaRegistry,\n\tinlineDecos?: readonly InlineDecoration[],\n): HTMLElement {\n\tconst p = createBlockElement('p', block.id);\n\tp.setAttribute('data-block-type', block.type);\n\trenderBlockContent(p, block, registry, inlineDecos);\n\treturn p;\n}\n\n/**\n * Converts spaces for contenteditable rendering.\n * Trailing spaces and double spaces are replaced with \\u00a0 (non-breaking space)\n * to prevent the browser from collapsing them.\n */\nfunction preserveSpaces(text: string): string {\n\t// Replace consecutive spaces: alternate regular and non-breaking\n\tlet result = text.replace(/ {2}/g, ' \\u00a0');\n\t// If the text ends with a space, replace it with nbsp\n\tif (result.endsWith(' ')) {\n\t\tresult = `${result.slice(0, -1)}\\u00a0`;\n\t}\n\t// If the text starts with a space, replace it with nbsp\n\tif (result.startsWith(' ')) {\n\t\tresult = `\\u00a0${result.slice(1)}`;\n\t}\n\treturn result;\n}\n\n/** Renders a text node with marks as nested inline elements. */\nfunction renderTextNode(node: TextNode, registry?: SchemaRegistry): Node {\n\tif (node.text === '') {\n\t\treturn document.createTextNode('');\n\t}\n\n\tconst textNode = document.createTextNode(preserveSpaces(node.text));\n\n\tif (node.marks.length === 0) {\n\t\treturn textNode;\n\t}\n\n\t// Sort marks: use MarkSpec.rank if available, otherwise fallback order\n\tconst sortedMarks = [...node.marks].sort(\n\t\t(a, b) => getMarkRank(a, registry) - getMarkRank(b, registry),\n\t);\n\n\tlet current: Node = textNode;\n\n\t// Wrap from inside out (last mark is outermost)\n\tfor (let i = sortedMarks.length - 1; i >= 0; i--) {\n\t\tconst mark = sortedMarks[i];\n\t\tif (!mark) continue;\n\t\tconst el = createMarkElement(mark, registry);\n\t\tel.appendChild(current);\n\t\tcurrent = el;\n\t}\n\n\treturn current;\n}\n\n/** Renders an InlineNode, using InlineNodeSpec.toDOM() or a fallback element. */\nfunction renderInlineNode(node: InlineNode, registry?: SchemaRegistry): HTMLElement {\n\tif (registry) {\n\t\tconst spec = registry.getInlineNodeSpec(node.inlineType);\n\t\tif (spec) {\n\t\t\tconst el = spec.toDOM(node);\n\t\t\tel.setAttribute('contenteditable', 'false');\n\t\t\treturn el;\n\t\t}\n\t}\n\t// Fallback: generic non-editable span\n\tconst el = document.createElement('span');\n\tel.setAttribute('data-inline-type', node.inlineType);\n\tel.setAttribute('contenteditable', 'false');\n\treturn el;\n}\n\n/** Compares two InlineNode attr records for equality. */\nfunction inlineAttrsEqual(\n\ta: Readonly<Record<string, string | number | boolean>>,\n\tb: Readonly<Record<string, string | number | boolean>>,\n): boolean {\n\tconst aKeys = Object.keys(a);\n\tconst bKeys = Object.keys(b);\n\tif (aKeys.length !== bKeys.length) return false;\n\tfor (const key of aKeys) {\n\t\tif (a[key] !== b[key]) return false;\n\t}\n\treturn true;\n}\n\n// --- Decoration Rendering ---\n\n/**\n * Renders inline content with decorations. InlineNodes are width-1 split points\n * rendered as their own elements (not wrapped by decorations).\n *\n * For each child:\n * - TextNode: split by decoration boundaries, render text → marks → decorations\n * - InlineNode: render directly without decoration wrapping\n */\nfunction renderDecoratedContent(\n\tcontainer: HTMLElement,\n\tinlineChildren: readonly (TextNode | InlineNode)[],\n\tinlineDecos: readonly InlineDecoration[],\n\tregistry?: SchemaRegistry,\n): void {\n\tlet globalOffset = 0;\n\n\tfor (const child of inlineChildren) {\n\t\tif (isInlineNode(child)) {\n\t\t\t// InlineNodes are rendered directly, not wrapped by decorations\n\t\t\tcontainer.appendChild(renderInlineNode(child, registry));\n\t\t\tglobalOffset += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// TextNode: split by decoration boundaries within this node's range\n\t\tconst textFrom = globalOffset;\n\t\tconst textTo = globalOffset + child.text.length;\n\n\t\tif (child.text.length === 0) {\n\t\t\tglobalOffset = textTo;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Find split points within this text range\n\t\tconst splitSet = new Set<number>();\n\t\tsplitSet.add(textFrom);\n\t\tsplitSet.add(textTo);\n\t\tfor (const deco of inlineDecos) {\n\t\t\tconst dFrom = Math.max(textFrom, deco.from);\n\t\t\tconst dTo = Math.min(textTo, deco.to);\n\t\t\tif (dFrom > textFrom && dFrom < textTo) splitSet.add(dFrom);\n\t\t\tif (dTo > textFrom && dTo < textTo) splitSet.add(dTo);\n\t\t}\n\t\tconst splits = [...splitSet].sort((a, b) => a - b);\n\n\t\t// Render micro-segments\n\t\tfor (let i = 0; i < splits.length - 1; i++) {\n\t\t\tconst from = splits[i];\n\t\t\tconst to = splits[i + 1];\n\t\t\tif (from === undefined || to === undefined || from >= to) continue;\n\n\t\t\tconst localFrom = from - textFrom;\n\t\t\tconst localTo = to - textFrom;\n\t\t\tconst text = child.text.slice(localFrom, localTo);\n\n\t\t\t// Find decorations that fully cover this micro-segment\n\t\t\tconst activeDecos: InlineDecoration[] = [];\n\t\t\tfor (const deco of inlineDecos) {\n\t\t\t\tif (deco.from <= from && deco.to >= to) {\n\t\t\t\t\tactiveDecos.push(deco);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Render: text → marks (inner) → decorations (outer)\n\t\t\tconst textNode = document.createTextNode(preserveSpaces(text));\n\t\t\tlet current: Node = textNode;\n\n\t\t\t// Wrap with marks (innermost to outermost)\n\t\t\tif (child.marks.length > 0) {\n\t\t\t\tconst sortedMarks = [...child.marks].sort(\n\t\t\t\t\t(a, b) => getMarkRank(a, registry) - getMarkRank(b, registry),\n\t\t\t\t);\n\t\t\t\tfor (let j = sortedMarks.length - 1; j >= 0; j--) {\n\t\t\t\t\tconst mark = sortedMarks[j];\n\t\t\t\t\tif (!mark) continue;\n\t\t\t\t\tconst el = createMarkElement(mark, registry);\n\t\t\t\t\tel.appendChild(current);\n\t\t\t\t\tcurrent = el;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Wrap with decorations (outermost)\n\t\t\tfor (const deco of activeDecos) {\n\t\t\t\tconst el = createDecorationElement(deco.attrs);\n\t\t\t\tel.appendChild(current);\n\t\t\t\tcurrent = el;\n\t\t\t}\n\n\t\t\tcontainer.appendChild(current);\n\t\t}\n\n\t\tglobalOffset = textTo;\n\t}\n}\n\n/** Creates a DOM element for an inline decoration. */\nfunction createDecorationElement(attrs: DecorationAttrs): HTMLElement {\n\tconst tagName = attrs.nodeName ?? 'span';\n\tconst el = document.createElement(tagName);\n\tel.setAttribute('data-decoration', 'true');\n\n\tif (attrs.class) {\n\t\tfor (const cls of attrs.class.split(' ')) {\n\t\t\tif (cls) el.classList.add(cls);\n\t\t}\n\t}\n\tif (attrs.style) {\n\t\tel.style.cssText = attrs.style;\n\t}\n\n\t// Apply any other custom attributes\n\tfor (const [key, value] of Object.entries(attrs)) {\n\t\tif (key === 'class' || key === 'style' || key === 'nodeName') continue;\n\t\tif (value !== undefined) {\n\t\t\tel.setAttribute(key, value);\n\t\t}\n\t}\n\n\treturn el;\n}\n\n/** Applies node decorations (CSS classes/styles) to a block element. */\nfunction applyNodeDecorations(el: HTMLElement, bid: BlockId, options?: ReconcileOptions): void {\n\tconst nodeDecos = options?.decorations?.findNode(bid);\n\tif (!nodeDecos || nodeDecos.length === 0) return;\n\n\tfor (const deco of nodeDecos) {\n\t\tif (deco.attrs.class) {\n\t\t\tfor (const cls of deco.attrs.class.split(' ')) {\n\t\t\t\tif (cls) el.classList.add(cls);\n\t\t\t}\n\t\t}\n\t\tif (deco.attrs.style) {\n\t\t\tconst current: string = el.style.cssText;\n\t\t\tel.style.cssText = current ? `${current}; ${deco.attrs.style}` : deco.attrs.style;\n\t\t}\n\t}\n}\n\n// --- Block Wrapper Management ---\n\n/**\n * Moves block elements out of wrapper elements (e.g. `<ul>`, `<ol>`) so the\n * main reconciliation loop sees all blocks as direct children of the container.\n */\nfunction unwrapBlocks(container: HTMLElement): void {\n\tconst wrappers: Element[] = Array.from(\n\t\tcontainer.querySelectorAll(':scope > [data-block-wrapper]'),\n\t);\n\tfor (const wrapper of wrappers) {\n\t\twhile (wrapper.firstChild) {\n\t\t\tcontainer.insertBefore(wrapper.firstChild, wrapper);\n\t\t}\n\t\twrapper.remove();\n\t}\n}\n\n/**\n * Groups consecutive blocks that declare the same wrapper key into shared\n * wrapper elements (`<ul>`, `<ol>`, etc.). Called after the main reconcile loop.\n */\nfunction wrapBlocks(\n\tcontainer: HTMLElement,\n\tblocks: readonly BlockNode[],\n\tregistry?: SchemaRegistry,\n): void {\n\tif (!registry) return;\n\n\t// Compute wrapper groups from the block model\n\tinterface WrapperGroup {\n\t\treadonly spec: WrapperSpec;\n\t\treadonly blockIds: readonly BlockId[];\n\t}\n\n\tconst groups: WrapperGroup[] = [];\n\tlet currentSpec: WrapperSpec | null = null;\n\tlet currentIds: BlockId[] = [];\n\n\tfor (const block of blocks) {\n\t\tconst nodeSpec = registry.getNodeSpec(block.type);\n\t\tconst wSpec: WrapperSpec | undefined = nodeSpec?.wrapper?.(block as never);\n\n\t\tif (wSpec && currentSpec && wSpec.key === currentSpec.key) {\n\t\t\tcurrentIds.push(block.id);\n\t\t} else if (wSpec) {\n\t\t\tif (currentSpec && currentIds.length > 0) {\n\t\t\t\tgroups.push({ spec: currentSpec, blockIds: currentIds });\n\t\t\t}\n\t\t\tcurrentSpec = wSpec;\n\t\t\tcurrentIds = [block.id];\n\t\t} else {\n\t\t\tif (currentSpec && currentIds.length > 0) {\n\t\t\t\tgroups.push({ spec: currentSpec, blockIds: currentIds });\n\t\t\t}\n\t\t\tcurrentSpec = null;\n\t\t\tcurrentIds = [];\n\t\t}\n\t}\n\tif (currentSpec && currentIds.length > 0) {\n\t\tgroups.push({ spec: currentSpec, blockIds: currentIds });\n\t}\n\n\t// Apply wrapper elements to the DOM\n\tfor (const group of groups) {\n\t\tconst firstEl: HTMLElement | null = container.querySelector(\n\t\t\t`[data-block-id=\"${group.blockIds[0]}\"]`,\n\t\t);\n\t\tif (!firstEl) continue;\n\n\t\tconst wrapper: HTMLElement = document.createElement(group.spec.tag);\n\t\twrapper.setAttribute('data-block-wrapper', group.spec.key);\n\t\tif (group.spec.className) {\n\t\t\twrapper.className = group.spec.className;\n\t\t}\n\t\tif (group.spec.attrs) {\n\t\t\tfor (const [key, value] of Object.entries(group.spec.attrs)) {\n\t\t\t\twrapper.setAttribute(key, value);\n\t\t\t}\n\t\t}\n\n\t\tfirstEl.before(wrapper);\n\t\tfor (const bid of group.blockIds) {\n\t\t\tconst el: HTMLElement | null = container.querySelector(`[data-block-id=\"${bid}\"]`);\n\t\t\tif (el) {\n\t\t\t\twrapper.appendChild(el);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Returns rendered top-level block elements in visual order.\n * Includes direct children and immediate children of block wrappers.\n */\nfunction getRenderedBlockElements(container: HTMLElement): readonly HTMLElement[] {\n\tconst blocks: HTMLElement[] = [];\n\tfor (const child of Array.from(container.children)) {\n\t\tif (!(child instanceof HTMLElement)) continue;\n\t\tif (child.hasAttribute('data-block-id')) {\n\t\t\tblocks.push(child);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!child.hasAttribute('data-block-wrapper')) continue;\n\n\t\tfor (const wrappedChild of Array.from(child.children)) {\n\t\t\tif (!(wrappedChild instanceof HTMLElement)) continue;\n\t\t\tif (wrappedChild.hasAttribute('data-block-id')) {\n\t\t\t\tblocks.push(wrappedChild);\n\t\t\t}\n\t\t}\n\t}\n\treturn blocks;\n}\n\n/** Removes a rendered block from whichever parent currently owns it. */\nfunction removeBlockElement(el: HTMLElement): void {\n\tel.parentElement?.removeChild(el);\n}\n\n/** Replaces a rendered block in-place, honoring wrapper parents when present. */\nfunction replaceBlockElement(oldEl: HTMLElement, newEl: HTMLElement, container: HTMLElement): void {\n\tconst parent = oldEl.parentElement;\n\tif (parent) {\n\t\tparent.replaceChild(newEl, oldEl);\n\t\treturn;\n\t}\n\tcontainer.replaceChild(newEl, oldEl);\n}\n\n/**\n * Inserts a new rendered block after the given sibling.\n * If the sibling is inside a wrapper, insertion happens inside that wrapper.\n */\nfunction insertAfterPreviousSibling(\n\tcontainer: HTMLElement,\n\tpreviousSibling: Element | null,\n\tnewEl: HTMLElement,\n): void {\n\tif (previousSibling?.parentElement) {\n\t\tconst parent = previousSibling.parentElement;\n\t\tif (previousSibling.nextSibling) {\n\t\t\tparent.insertBefore(newEl, previousSibling.nextSibling);\n\t\t} else {\n\t\t\tparent.appendChild(newEl);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (container.firstChild) {\n\t\tcontainer.insertBefore(newEl, container.firstChild);\n\t} else {\n\t\tcontainer.appendChild(newEl);\n\t}\n}\n","/**\n * EditorView: orchestrates input handling, reconciliation, and selection sync.\n */\n\nimport { DecorationSet } from '../decorations/Decoration.js';\nimport { ClipboardHandler } from '../input/ClipboardHandler.js';\nimport { CompositionTracker } from '../input/CompositionTracker.js';\nimport type { FileHandlerRegistry } from '../input/FileHandlerRegistry.js';\nimport { InputHandler } from '../input/InputHandler.js';\nimport type { InputRuleRegistry } from '../input/InputRuleRegistry.js';\nimport { KeyboardHandler } from '../input/KeyboardHandler.js';\nimport type { KeymapRegistry } from '../input/KeymapRegistry.js';\nimport { PasteHandler } from '../input/PasteHandler.js';\nimport { generateBlockId, getBlockLength } from '../model/Document.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { Position } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n\tselectionsEqual,\n} from '../model/Selection.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport { nodeType, blockId as toBlockId } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport { HistoryManager } from '../state/History.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport {\n\ttype CaretDirection,\n\tendOfTextblock,\n\tgetCaretRectFromSelection,\n\tnavigateAcrossBlocks,\n\tnavigateVerticalWithGoalColumn,\n\tskipInlineNode,\n} from './CaretNavigation.js';\nimport { CursorWrapper } from './CursorWrapper.js';\nimport { domPositionFromPoint } from './DomPointUtils.js';\nimport type { NodeView } from './NodeView.js';\nimport type { NodeViewRegistry } from './NodeViewRegistry.js';\nimport { getTextDirection } from './Platform.js';\nimport { type ReconcileOptions, reconcile } from './Reconciler.js';\nimport { domPositionToState, readSelectionFromDOM, syncSelectionToDOM } from './SelectionSync.js';\n\nexport type StateChangeCallback = (\n\toldState: EditorState,\n\tnewState: EditorState,\n\ttr: Transaction,\n) => void;\n\nexport interface EditorViewOptions {\n\tstate: EditorState;\n\tschemaRegistry?: SchemaRegistry;\n\tkeymapRegistry?: KeymapRegistry;\n\tinputRuleRegistry?: InputRuleRegistry;\n\tfileHandlerRegistry?: FileHandlerRegistry;\n\tnodeViewRegistry?: NodeViewRegistry;\n\tmaxHistoryDepth?: number;\n\tonStateChange?: StateChangeCallback;\n\tgetDecorations?: (state: EditorState, tr?: Transaction) => DecorationSet;\n\tisReadOnly?: () => boolean;\n}\n\nexport class EditorView {\n\tprivate state: EditorState;\n\tprivate readonly contentElement: HTMLElement;\n\tprivate readonly inputHandler: InputHandler;\n\tprivate readonly keyboardHandler: KeyboardHandler;\n\tprivate readonly pasteHandler: PasteHandler;\n\tprivate readonly clipboardHandler: ClipboardHandler;\n\treadonly history: HistoryManager;\n\tprivate readonly stateChangeCallbacks: StateChangeCallback[] = [];\n\tprivate readonly handleSelectionChange: () => void;\n\tprivate readonly handleMousedown: (e: MouseEvent) => void;\n\tprivate readonly handleDragover: (e: DragEvent) => void;\n\tprivate readonly handleDrop: (e: DragEvent) => void;\n\tprivate readonly handleCompositionStartForWrapper: () => void;\n\tprivate readonly handleCompositionEndForWrapper: () => void;\n\tprivate isUpdating = false;\n\tprivate pendingNodeSelectionClear = false;\n\tprivate pendingGapCursorClear = false;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate readonly keymapRegistry?: KeymapRegistry;\n\tprivate readonly fileHandlerRegistry?: FileHandlerRegistry;\n\tprivate readonly nodeViewRegistry?: NodeViewRegistry;\n\tprivate readonly nodeViews = new Map<string, NodeView>();\n\tprivate decorations: DecorationSet = DecorationSet.empty;\n\tprivate readonly getDecorations?: (state: EditorState, tr?: Transaction) => DecorationSet;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate navigationKeymap: Record<string, () => boolean> | null = null;\n\treadonly compositionTracker: CompositionTracker = new CompositionTracker();\n\tprivate readonly cursorWrapper: CursorWrapper;\n\tprivate goalColumn: number | null = null;\n\tprivate preserveGoalColumn = false;\n\n\tconstructor(contentElement: HTMLElement, options: EditorViewOptions) {\n\t\tthis.state = options.state;\n\t\tthis.contentElement = contentElement;\n\t\tthis.schemaRegistry = options.schemaRegistry;\n\t\tthis.keymapRegistry = options.keymapRegistry;\n\t\tthis.fileHandlerRegistry = options.fileHandlerRegistry;\n\t\tthis.nodeViewRegistry = options.nodeViewRegistry;\n\t\tthis.getDecorations = options.getDecorations;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\n\t\tthis.history = new HistoryManager({\n\t\t\tmaxDepth: options.maxHistoryDepth ?? 100,\n\t\t});\n\n\t\tif (options.onStateChange) {\n\t\t\tthis.stateChangeCallbacks.push(options.onStateChange);\n\t\t}\n\n\t\tthis.inputHandler = new InputHandler(contentElement, {\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tsyncSelection: () => this.syncSelectionFromDOM(),\n\t\t\tinputRuleRegistry: options.inputRuleRegistry,\n\t\t\tisReadOnly: this.isReadOnly,\n\t\t\tcompositionTracker: this.compositionTracker,\n\t\t});\n\t\tthis.keyboardHandler = new KeyboardHandler(contentElement, {\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tundo: () => this.undo(),\n\t\t\tredo: () => this.redo(),\n\t\t\tkeymapRegistry: this.keymapRegistry,\n\t\t\tisReadOnly: this.isReadOnly,\n\t\t\tcompositionTracker: this.compositionTracker,\n\t\t});\n\t\tthis.pasteHandler = new PasteHandler(contentElement, {\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tschemaRegistry: this.schemaRegistry,\n\t\t\tfileHandlerRegistry: this.fileHandlerRegistry,\n\t\t\tisReadOnly: this.isReadOnly,\n\t\t});\n\t\tthis.clipboardHandler = new ClipboardHandler(contentElement, {\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tschemaRegistry: this.schemaRegistry,\n\t\t\tsyncSelection: () => this.syncSelectionFromDOM(),\n\t\t\tisReadOnly: this.isReadOnly,\n\t\t});\n\n\t\tthis.cursorWrapper = new CursorWrapper(contentElement, this.schemaRegistry);\n\n\t\tthis.handleCompositionStartForWrapper = () => {\n\t\t\tthis.cursorWrapper.onCompositionStart(this.state);\n\t\t};\n\t\tthis.handleCompositionEndForWrapper = () => {\n\t\t\tthis.cursorWrapper.cleanup();\n\t\t};\n\t\tcontentElement.addEventListener('compositionstart', this.handleCompositionStartForWrapper);\n\t\tcontentElement.addEventListener('compositionend', this.handleCompositionEndForWrapper);\n\n\t\tthis.handleSelectionChange = this.onSelectionChange.bind(this);\n\t\tdocument.addEventListener('selectionchange', this.handleSelectionChange);\n\n\t\tthis.handleMousedown = this.onMousedown.bind(this);\n\t\tcontentElement.addEventListener('mousedown', this.handleMousedown);\n\n\t\tthis.handleDragover = this.onDragover.bind(this);\n\t\tcontentElement.addEventListener('dragover', this.handleDragover);\n\n\t\tthis.handleDrop = this.onDrop.bind(this);\n\t\tcontentElement.addEventListener('drop', this.handleDrop);\n\n\t\t// Initial render\n\t\tthis.decorations = this.getDecorations?.(this.state) ?? DecorationSet.empty;\n\t\treconcile(contentElement, null, this.state, {\n\t\t\t...this.reconcileOptions(),\n\t\t\tdecorations: this.decorations,\n\t\t});\n\t\tsyncSelectionToDOM(contentElement, this.state.selection);\n\n\t\tthis.registerNavigationKeymaps();\n\t}\n\n\t/** Returns the current editor state. */\n\tgetState(): EditorState {\n\t\treturn this.state;\n\t}\n\n\t/**\n\t * Central update cycle: sets state, collects decorations, reconciles DOM,\n\t * syncs selection, and notifies listeners. Guarded against re-entrancy.\n\t */\n\tprivate applyUpdate(\n\t\tnewState: EditorState,\n\t\ttr: Transaction,\n\t\toptions?: { readonly pushHistory?: boolean },\n\t): void {\n\t\tif (this.isUpdating) return;\n\t\tthis.isUpdating = true;\n\t\ttry {\n\t\t\tconst oldState = this.state;\n\t\t\tthis.state = newState;\n\n\t\t\t// Clean up stale CursorWrapper when storedMarks are cleared by a dispatch\n\t\t\tif (this.cursorWrapper.isActive && !newState.storedMarks?.length) {\n\t\t\t\tthis.cursorWrapper.cleanup();\n\t\t\t}\n\n\t\t\tif (options?.pushHistory && tr.metadata.origin !== 'history') {\n\t\t\t\tthis.history.push(tr);\n\t\t\t}\n\n\t\t\tconst oldDecorations = this.decorations;\n\t\t\tconst newDecorations = this.getDecorations?.(newState, tr) ?? DecorationSet.empty;\n\t\t\tthis.decorations = newDecorations;\n\n\t\t\treconcile(this.contentElement, oldState, newState, {\n\t\t\t\t...this.reconcileOptions(oldState.selection),\n\t\t\t\tdecorations: newDecorations,\n\t\t\t\toldDecorations,\n\t\t\t\tcompositionBlockId: this.compositionTracker.isComposing\n\t\t\t\t\t? (this.compositionTracker.activeBlockId ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t});\n\t\t\tif (!this.compositionTracker.isComposing) {\n\t\t\t\tsyncSelectionToDOM(this.contentElement, newState.selection);\n\t\t\t}\n\n\t\t\tfor (const cb of this.stateChangeCallbacks) {\n\t\t\t\tcb(oldState, newState, tr);\n\t\t\t}\n\t\t\t// Reset goalColumn unless a vertical navigation is in progress\n\t\t\tif (!this.preserveGoalColumn) {\n\t\t\t\tthis.goalColumn = null;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.isUpdating = false;\n\t\t}\n\t}\n\n\t/** Dispatches a transaction, updates state, reconciles DOM, syncs selection. */\n\tdispatch(tr: Transaction): void {\n\t\tconst newState = this.state.apply(tr);\n\t\tthis.applyUpdate(newState, tr, { pushHistory: true });\n\t}\n\n\t/** Performs undo. */\n\tundo(): void {\n\t\tif (this.isUpdating || this.isReadOnly()) return;\n\t\tconst result = this.history.undo(this.state);\n\t\tif (!result) return;\n\t\tthis.applyUpdate(result.state, result.transaction);\n\t}\n\n\t/** Performs redo. */\n\tredo(): void {\n\t\tif (this.isUpdating || this.isReadOnly()) return;\n\t\tconst result = this.history.redo(this.state);\n\t\tif (!result) return;\n\t\tthis.applyUpdate(result.state, result.transaction);\n\t}\n\n\t/** Registers a state change callback. */\n\tonStateChange(callback: StateChangeCallback): () => void {\n\t\tthis.stateChangeCallbacks.push(callback);\n\t\treturn () => {\n\t\t\tconst idx = this.stateChangeCallbacks.indexOf(callback);\n\t\t\tif (idx !== -1) this.stateChangeCallbacks.splice(idx, 1);\n\t\t};\n\t}\n\n\t/** Replaces the editor state without destroying handlers or history. */\n\treplaceState(newState: EditorState): void {\n\t\tif (this.isUpdating) return;\n\t\tthis.isUpdating = true;\n\t\ttry {\n\t\t\tconst oldState = this.state;\n\t\t\tthis.state = newState;\n\t\t\tthis.history.clear();\n\n\t\t\tconst oldDecorations = this.decorations;\n\t\t\tconst newDecorations = this.getDecorations?.(newState) ?? DecorationSet.empty;\n\t\t\tthis.decorations = newDecorations;\n\n\t\t\treconcile(this.contentElement, oldState, newState, {\n\t\t\t\t...this.reconcileOptions(oldState.selection),\n\t\t\t\tdecorations: newDecorations,\n\t\t\t\toldDecorations,\n\t\t\t\tcompositionBlockId: this.compositionTracker.isComposing\n\t\t\t\t\t? (this.compositionTracker.activeBlockId ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t});\n\t\t\tif (!this.compositionTracker.isComposing) {\n\t\t\t\tsyncSelectionToDOM(this.contentElement, newState.selection);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.isUpdating = false;\n\t\t}\n\t}\n\n\t/** Syncs the DOM selection to the editor state. */\n\tprivate syncSelectionFromDOM(): void {\n\t\t// During IME composition, do not override the DOM selection\n\t\tif (this.compositionTracker.isComposing) return;\n\n\t\t// Selection change outside composition means CursorWrapper is stale\n\t\tif (this.cursorWrapper.isActive) {\n\t\t\tthis.cursorWrapper.cleanup();\n\t\t}\n\n\t\t// If NodeSelection or GapCursor is active, preserve it — DOM selectionchange should not override.\n\t\t// Exception: after mousedown on a non-selectable block, allow the DOM selection to take over.\n\t\tif (isNodeSelection(this.state.selection) && !this.pendingNodeSelectionClear) return;\n\t\tif (isGapCursor(this.state.selection) && !this.pendingGapCursorClear) return;\n\t\tthis.pendingNodeSelectionClear = false;\n\t\tthis.pendingGapCursorClear = false;\n\n\t\tconst sel = readSelectionFromDOM(this.contentElement);\n\t\tif (!sel) return;\n\n\t\t// Check if selection actually changed\n\t\tif (selectionsEqual(sel, this.state.selection)) return;\n\n\t\t// Update state with new selection (clear stored marks on selection change)\n\t\tconst tr = this.state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(sel)\n\t\t\t.setStoredMarks(null, this.state.storedMarks)\n\t\t\t.build();\n\n\t\tconst newState = this.state.apply(tr);\n\t\tthis.applyUpdate(newState, tr);\n\t}\n\n\t/** Handles mousedown on selectable/void blocks to create NodeSelection. */\n\tprivate onMousedown(e: MouseEvent): void {\n\t\tif (this.isUpdating) return;\n\t\tthis.goalColumn = null;\n\t\tconst target = e.target;\n\t\tif (!(target instanceof HTMLElement)) return;\n\n\t\tconst nearestBlockEl = target.closest('[data-block-id]');\n\n\t\t// Click in empty space below all blocks → create a paragraph\n\t\tif (!(nearestBlockEl instanceof HTMLElement) || !this.contentElement.contains(nearestBlockEl)) {\n\t\t\tif (this.contentElement.contains(target) || target === this.contentElement) {\n\t\t\t\tthis.handleClickBelowContent(e);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst isNodeSelectable =\n\t\t\tnearestBlockEl.hasAttribute('data-void') || nearestBlockEl.hasAttribute('data-selectable');\n\t\tif (!isNodeSelectable) {\n\t\t\t// When clicking a non-selectable block while NodeSelection or GapCursor is active,\n\t\t\t// allow the next syncSelectionFromDOM to override the selection\n\t\t\tif (isNodeSelection(this.state.selection)) {\n\t\t\t\tthis.pendingNodeSelectionClear = true;\n\t\t\t}\n\t\t\tif (isGapCursor(this.state.selection)) {\n\t\t\t\tthis.pendingGapCursorClear = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// If clicking inside contentDOM (e.g. code block content area),\n\t\t// allow browser cursor placement instead of creating NodeSelection.\n\t\tconst contentDOM: Element | null = nearestBlockEl.querySelector('[data-content-dom]');\n\t\tif (contentDOM?.contains(target)) {\n\t\t\tif (isNodeSelection(this.state.selection)) {\n\t\t\t\tthis.pendingNodeSelectionClear = true;\n\t\t\t}\n\t\t\tif (isGapCursor(this.state.selection)) {\n\t\t\t\tthis.pendingGapCursorClear = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\t\tthis.contentElement.focus();\n\n\t\tconst bid = toBlockId(nearestBlockEl.getAttribute('data-block-id') ?? '');\n\t\tconst path = this.buildBlockPath(nearestBlockEl);\n\t\tconst sel = createNodeSelection(bid, path);\n\n\t\tconst tr = this.state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(sel)\n\t\t\t.setStoredMarks(null, this.state.storedMarks)\n\t\t\t.build();\n\n\t\tconst newState = this.state.apply(tr);\n\t\tthis.applyUpdate(newState, tr);\n\t}\n\n\t/**\n\t * When the user clicks in empty space below all rendered blocks,\n\t * appends a new paragraph after the last block and focuses it.\n\t */\n\tprivate handleClickBelowContent(e: MouseEvent): void {\n\t\tif (this.isReadOnly()) return;\n\t\tconst blockOrder: readonly BlockId[] = this.state.getBlockOrder();\n\t\tconst lastBlockId: BlockId | undefined = blockOrder[blockOrder.length - 1];\n\t\tif (!lastBlockId) return;\n\t\tconst lastBlockEl: Element | null = this.contentElement.querySelector(\n\t\t\t`[data-block-id=\"${lastBlockId}\"]`,\n\t\t);\n\t\tif (!lastBlockEl) return;\n\n\t\t// Only act if click is below the last block\n\t\tconst lastRect: DOMRect = lastBlockEl.getBoundingClientRect();\n\t\tif (e.clientY <= lastRect.bottom) return;\n\n\t\t// Check if the last block is already an empty paragraph we can focus\n\t\tconst lastBlock = this.state.getBlock(lastBlockId);\n\t\tif (lastBlock?.type === 'paragraph' && getBlockLength(lastBlock) === 0) {\n\t\t\t// Focus the existing empty paragraph\n\t\t\tconst tr: Transaction = this.state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setSelection(createCollapsedSelection(lastBlockId, 0))\n\t\t\t\t.build();\n\t\t\tthis.dispatch(tr);\n\t\t\te.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\t// Create a new paragraph after the last block\n\t\te.preventDefault();\n\t\tthis.contentElement.focus();\n\n\t\tconst newId: BlockId = generateBlockId();\n\t\tconst lastLen: number = lastBlock ? getBlockLength(lastBlock) : 0;\n\n\t\tconst tr: Transaction = this.state\n\t\t\t.transaction('input')\n\t\t\t.splitBlock(lastBlockId, lastLen, newId)\n\t\t\t.setBlockType(newId, nodeType('paragraph'))\n\t\t\t.setSelection(createCollapsedSelection(newId, 0))\n\t\t\t.build();\n\n\t\tthis.dispatch(tr);\n\t}\n\n\t/** Builds an array of block IDs from root to leaf. */\n\tprivate buildBlockPath(leafBlockEl: HTMLElement): BlockId[] {\n\t\tconst path: BlockId[] = [];\n\t\tlet current: HTMLElement | null = leafBlockEl;\n\t\twhile (current && current !== this.contentElement) {\n\t\t\tif (current.hasAttribute('data-block-id')) {\n\t\t\t\tpath.unshift(toBlockId(current.getAttribute('data-block-id') ?? ''));\n\t\t\t}\n\t\t\tcurrent = current.parentElement;\n\t\t}\n\t\treturn path;\n\t}\n\n\t/** Allows file drop by preventing default on dragover when files are present. */\n\tprivate onDragover(e: DragEvent): void {\n\t\tif (!this.fileHandlerRegistry) return;\n\t\tif (!e.dataTransfer) return;\n\t\tif (e.dataTransfer.types.includes('Files')) {\n\t\t\te.preventDefault();\n\t\t}\n\t}\n\n\t/** Handles file drop by delegating to registered file handlers. */\n\tprivate onDrop(e: DragEvent): void {\n\t\tif (this.isReadOnly()) return;\n\t\tif (!this.fileHandlerRegistry) return;\n\t\tif (!e.dataTransfer) return;\n\n\t\tconst files: File[] = Array.from(e.dataTransfer.files);\n\t\tif (files.length === 0) return;\n\n\t\tconst position: Position | null = this.getPositionFromPoint(e.clientX, e.clientY);\n\n\t\tlet handled = false;\n\t\tfor (const file of files) {\n\t\t\tconst handlers = this.fileHandlerRegistry.matchFileHandlers(file.type);\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = handler(file, position);\n\t\t\t\tif (result === true || result instanceof Promise) {\n\t\t\t\t\thandled = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (handled) {\n\t\t\te.preventDefault();\n\t\t}\n\t}\n\n\t/** Converts screen coordinates to an editor Position. */\n\tprivate getPositionFromPoint(x: number, y: number): Position | null {\n\t\tconst root = this.contentElement.getRootNode() as Document | ShadowRoot;\n\t\tconst domPoint = domPositionFromPoint(root, x, y);\n\t\tif (!domPoint) return null;\n\t\tif (!this.contentElement.contains(domPoint.node)) return null;\n\n\t\treturn domPositionToState(this.contentElement, domPoint.node, domPoint.offset);\n\t}\n\n\t/** Handles DOM selection changes (clicks, arrow keys). */\n\tprivate onSelectionChange(): void {\n\t\tif (this.isUpdating) return;\n\n\t\t// Only process if our content element is focused\n\t\tconst shadowRoot = this.contentElement.getRootNode() as ShadowRoot | Document;\n\t\tconst activeEl =\n\t\t\t'activeElement' in shadowRoot ? shadowRoot.activeElement : document.activeElement;\n\t\tif (!this.contentElement.contains(activeEl) && activeEl !== this.contentElement) return;\n\n\t\tthis.syncSelectionFromDOM();\n\t}\n\n\tprivate reconcileOptions(\n\t\toldSelection?: import('../model/Selection.js').EditorSelection,\n\t): ReconcileOptions {\n\t\tconst selectedNodeId = isNodeSelection(this.state.selection)\n\t\t\t? this.state.selection.nodeId\n\t\t\t: undefined;\n\t\tconst previousSelectedNodeId =\n\t\t\toldSelection && isNodeSelection(oldSelection) ? oldSelection.nodeId : undefined;\n\t\treturn {\n\t\t\tregistry: this.schemaRegistry,\n\t\t\tnodeViewRegistry: this.nodeViewRegistry,\n\t\t\tnodeViews: this.nodeViews,\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tselectedNodeId,\n\t\t\tpreviousSelectedNodeId,\n\t\t};\n\t}\n\n\t/** Registers arrow-key keymaps with navigation priority for cross-block movement. */\n\tprivate registerNavigationKeymaps(): void {\n\t\tif (!this.keymapRegistry) return;\n\n\t\tconst directions: Record<string, CaretDirection> = {\n\t\t\tArrowLeft: 'left',\n\t\t\tArrowRight: 'right',\n\t\t\tArrowUp: 'up',\n\t\t\tArrowDown: 'down',\n\t\t};\n\n\t\tconst keymap: Record<string, () => boolean> = {};\n\t\tfor (const [key, dir] of Object.entries(directions)) {\n\t\t\tkeymap[key] = () => this.handleNavigationArrow(dir);\n\t\t}\n\n\t\tthis.navigationKeymap = keymap;\n\t\tthis.keymapRegistry.registerKeymap(keymap, { priority: 'navigation' });\n\t}\n\n\t/** Handles a navigation arrow key: cross-block movement if at textblock boundary. */\n\tprivate handleNavigationArrow(direction: CaretDirection): boolean {\n\t\t// NodeSelection arrows are handled by handleNodeSelectionKeys\n\t\tif (isNodeSelection(this.state.selection)) return false;\n\t\t// GapCursor arrows are handled by GapCursorPlugin keymap\n\t\tif (isGapCursor(this.state.selection)) return false;\n\n\t\t// Non-collapsed: plain arrows collapse the selection (browser handles this)\n\t\tif (!isCollapsed(this.state.selection)) return false;\n\n\t\tif (direction === 'left' || direction === 'right') {\n\t\t\treturn this.handleHorizontalArrow(direction);\n\t\t}\n\t\treturn this.handleVerticalArrow(direction);\n\t}\n\n\t/** Handles horizontal arrow navigation: InlineNode skip + cross-block. */\n\tprivate handleHorizontalArrow(direction: 'left' | 'right'): boolean {\n\t\t// Reset goalColumn on any horizontal movement\n\t\tthis.goalColumn = null;\n\t\tconst logicalDirection: 'left' | 'right' = this.resolveLogicalHorizontalDirection(direction);\n\n\t\t// Skip over InlineNodes atomically\n\t\tconst inlineSkipTr: Transaction | null = skipInlineNode(this.state, logicalDirection);\n\t\tif (inlineSkipTr) {\n\t\t\tthis.dispatch(inlineSkipTr);\n\t\t\tthis.validateSelectionAfterInlineSkip();\n\t\t\treturn true;\n\t\t}\n\n\t\t// Cross-block at textblock boundaries\n\t\tif (!endOfTextblock(this.contentElement, this.state, direction)) return false;\n\n\t\tconst tr: Transaction | null = navigateAcrossBlocks(this.state, logicalDirection);\n\t\tif (tr) {\n\t\t\tthis.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Maps visual horizontal arrow intent (left/right key) to logical movement\n\t * direction in offset space for the current block direction.\n\t */\n\tprivate resolveLogicalHorizontalDirection(visual: 'left' | 'right'): 'left' | 'right' {\n\t\tconst sel = this.state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return visual;\n\t\tconst blockEl = this.contentElement.querySelector(`[data-block-id=\"${sel.anchor.blockId}\"]`);\n\t\tconst isRtl: boolean = blockEl instanceof HTMLElement && getTextDirection(blockEl) === 'rtl';\n\t\tif (!isRtl) return visual;\n\t\treturn visual === 'left' ? 'right' : 'left';\n\t}\n\n\t/** Handles vertical arrow navigation with goalColumn preservation. */\n\tprivate handleVerticalArrow(direction: 'up' | 'down'): boolean {\n\t\t// Read caret rect once — used for both boundary check and goalColumn\n\t\tconst domSel: globalThis.Selection | null =\n\t\t\tthis.contentElement.ownerDocument.getSelection?.() ?? null;\n\t\tconst caretRect: DOMRect | null = domSel ? getCaretRectFromSelection(domSel) : null;\n\n\t\tif (!endOfTextblock(this.contentElement, this.state, direction, caretRect)) return false;\n\n\t\t// Capture goalColumn from current caret position (only on first vertical move)\n\t\tif (this.goalColumn === null && caretRect) {\n\t\t\tthis.goalColumn = caretRect.left;\n\t\t}\n\n\t\tthis.preserveGoalColumn = true;\n\t\tconst tr: Transaction | null = navigateVerticalWithGoalColumn(\n\t\t\tthis.contentElement,\n\t\t\tthis.state,\n\t\t\tdirection,\n\t\t\tthis.goalColumn,\n\t\t);\n\n\t\tif (tr) {\n\t\t\tthis.dispatch(tr);\n\t\t\tthis.preserveGoalColumn = false;\n\t\t\treturn true;\n\t\t}\n\t\tthis.preserveGoalColumn = false;\n\t\treturn false;\n\t}\n\n\t/**\n\t * Validates the DOM cursor position after an InlineNode skip.\n\t *\n\t * Chrome can place the cursor inside a `contenteditable=\"false\"` element\n\t * (phantom position), and Firefox may lose the cursor entirely next to such\n\t * elements. This read-back roundtrip detects drift between the model\n\t * selection and the actual DOM selection. If they diverge, we force\n\t * `syncSelectionToDOM()` a second time to correct the position.\n\t */\n\tprivate validateSelectionAfterInlineSkip(): void {\n\t\tconst domSel = readSelectionFromDOM(this.contentElement);\n\t\tif (!domSel) {\n\t\t\t// DOM selection lost (Firefox) — force re-sync\n\t\t\tsyncSelectionToDOM(this.contentElement, this.state.selection);\n\t\t\treturn;\n\t\t}\n\t\tif (!selectionsEqual(domSel, this.state.selection)) {\n\t\t\t// DOM position drifted (Chrome phantom) — force re-sync\n\t\t\tsyncSelectionToDOM(this.contentElement, this.state.selection);\n\t\t}\n\t}\n\n\t/** Cleans up all event listeners and handlers. */\n\tdestroy(): void {\n\t\tthis.cursorWrapper.cleanup();\n\t\tthis.inputHandler.destroy();\n\t\tthis.keyboardHandler.destroy();\n\t\tthis.pasteHandler.destroy();\n\t\tthis.clipboardHandler.destroy();\n\t\tthis.contentElement.removeEventListener(\n\t\t\t'compositionstart',\n\t\t\tthis.handleCompositionStartForWrapper,\n\t\t);\n\t\tthis.contentElement.removeEventListener('compositionend', this.handleCompositionEndForWrapper);\n\t\tdocument.removeEventListener('selectionchange', this.handleSelectionChange);\n\t\tthis.contentElement.removeEventListener('mousedown', this.handleMousedown);\n\t\tthis.contentElement.removeEventListener('dragover', this.handleDragover);\n\t\tthis.contentElement.removeEventListener('drop', this.handleDrop);\n\t\t// Remove navigation keymaps from registry\n\t\tif (this.navigationKeymap && this.keymapRegistry) {\n\t\t\tthis.keymapRegistry.removeKeymap(this.navigationKeymap);\n\t\t\tthis.navigationKeymap = null;\n\t\t}\n\t\t// Destroy all NodeViews\n\t\tfor (const nv of this.nodeViews.values()) {\n\t\t\tnv.destroy?.();\n\t\t}\n\t\tthis.nodeViews.clear();\n\t}\n}\n","/** Core editor styles — :host, .notectl-editor, .notectl-content, generic utilities. */\nexport const BASE_CSS = `\n:host {\n\tdisplay: block;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n\tfont-size: 16px;\n\tline-height: 1.6;\n\tcolor: var(--notectl-fg);\n}\n\n.notectl-editor {\n\tdisplay: flex;\n\tflex-direction: column;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\toverflow: hidden;\n\tbackground: var(--notectl-bg);\n}\n\n.notectl-editor:focus-within {\n\tborder-color: var(--notectl-border-focus);\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n}\n\n/* Content Area */\n.notectl-content {\n\tflex: 1;\n\tpadding: 12px 16px;\n\toutline: none;\n\tmin-height: var(--notectl-content-min-height, 400px);\n\tcursor: text;\n\tposition: relative;\n\twhite-space: pre-wrap;\n\tword-wrap: break-word;\n\t-moz-tab-size: 4;\n\ttab-size: 4;\n}\n\n.notectl-content p {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tmin-height: 1.6em;\n}\n\n.notectl-content p + p {\n\tmargin-top: 0;\n}\n\n/* Horizontal Rule */\n.notectl-content hr {\n\tborder: none;\n\tborder-top: 1px solid var(--notectl-border);\n\tmargin: 8px 0;\n\tpadding: 0;\n\tcursor: default;\n\tuser-select: none;\n}\n\n/* Placeholder */\n.notectl-content.notectl-content--empty::before {\n\tcontent: attr(data-placeholder);\n\tcolor: var(--notectl-fg-muted);\n\tpointer-events: none;\n\tposition: absolute;\n\ttop: 12px;\n\tleft: 16px;\n}\n\n/* Plugin container bottom */\n.notectl-plugin-container--bottom {\n\tborder-top: 1px solid var(--notectl-border);\n}\n\n/* Screen reader announcements */\n.notectl-sr-only {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\tmargin: -1px;\n\tpadding: 0;\n\toverflow: hidden;\n\tclip: rect(0, 0, 0, 0);\n\twhite-space: nowrap;\n\tborder: 0;\n}\n\n/* Node selection */\n.notectl-node-selected {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n}\n`;\n","/**\n * Editor styles using Adopted Stylesheets for Shadow DOM.\n *\n * All colors reference CSS custom properties set by the ThemeEngine.\n * The theme stylesheet is always injected first, providing all --notectl-* values.\n *\n * Only core styles (base + reduced-motion) live here.\n * Plugin-specific CSS is registered via `PluginContext.registerStyleSheet()`.\n */\n\nimport { BASE_CSS } from './styles/base.js';\nimport { PAPER_CSS } from './styles/paper.js';\nimport { REDUCED_MOTION_CSS } from './styles/reduced-motion.js';\n\n/**\n * Combined CSS for the core editor shell.\n * Plugin styles are added separately via the plugin system.\n */\nconst EDITOR_CSS: string = [BASE_CSS, REDUCED_MOTION_CSS, PAPER_CSS].join('\\n');\n\nlet cachedStyleSheet: CSSStyleSheet | null = null;\n\n/** Returns the shared editor stylesheet. */\nexport function getEditorStyleSheet(): CSSStyleSheet {\n\tif (!cachedStyleSheet) {\n\t\tcachedStyleSheet = new CSSStyleSheet();\n\t\tcachedStyleSheet.replaceSync(EDITOR_CSS);\n\t}\n\treturn cachedStyleSheet;\n}\n","/** Reduced motion preference (WCAG 2.3.3). */\nexport const REDUCED_MOTION_CSS = `\n@media (prefers-reduced-motion: reduce) {\n\t.notectl-toolbar-btn,\n\t.notectl-image__resize-handle,\n\t.notectl-image__size-indicator,\n\t.notectl-color-picker__swatch,\n\t.notectl-font-picker__item,\n\t.notectl-heading-picker__item,\n\t.notectl-font-size-picker__item,\n\t.ntbl-handle,\n\t.ntbl-handle-delete,\n\t.ntbl-insert-line,\n\t.ntbl-insert-btn,\n\t.ntbl-add-zone,\n\t.ntbl-add-icon,\n\t.ntbl-col-bar,\n\t.ntbl-row-bar,\n\t.ntbl-delete-table-btn,\n\t.notectl-code-block__copy {\n\t\ttransition: none !important;\n\t}\n}\n`;\n","/** Paper mode styles — viewport, surface, content overrides, and scale transitions. */\n\nimport {\n\tPAPER_MARGIN_HORIZONTAL_PX,\n\tPAPER_MARGIN_TOP_PX,\n\tPAPER_VIEWPORT_PADDING_PX,\n} from '../PaperSize.js';\n\nconst PT: number = PAPER_MARGIN_TOP_PX;\nconst PH: number = PAPER_MARGIN_HORIZONTAL_PX;\nconst VP: number = PAPER_VIEWPORT_PADDING_PX;\n\nexport const PAPER_CSS: string = `\n/* Paper viewport: scroll container with centered gray background */\n.notectl-paper-viewport {\n\tflex: 1;\n\toverflow-y: auto;\n\toverflow-x: hidden;\n\tbackground: var(--notectl-paper-viewport-bg, #e8e8e8);\n\tpadding: ${VP}px 0;\n}\n\n/* Paper surface: white page with shadow, centered */\n.notectl-paper-surface {\n\tmargin: 0 auto;\n\tbackground: var(--notectl-bg);\n\tborder-radius: 2px;\n\tbox-shadow: 0 2px 8px var(--notectl-shadow, rgba(0, 0, 0, 0.15));\n\ttransform-origin: top center;\n\ttransition: transform 0.15s ease-out;\n}\n\n/* Content overrides in paper mode: wider document margins */\n.notectl-editor[data-paper-mode] .notectl-content {\n\tflex: none;\n\tpadding: ${PT}px ${PH}px;\n\tmin-height: auto;\n}\n\n/* Placeholder position override for paper mode */\n.notectl-editor[data-paper-mode] .notectl-content.notectl-content--empty::before {\n\ttop: ${PT}px;\n\tleft: ${PH}px;\n}\n\n/* Dark mode: darker viewport background */\n:host([theme=\"dark\"]) .notectl-paper-viewport {\n\t--notectl-paper-viewport-bg: #181825;\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.notectl-paper-surface {\n\t\ttransition: none !important;\n\t}\n}\n`;\n","/**\n * EditorThemeController — manages theme lifecycle for a Shadow DOM host.\n * Owns the theme CSSStyleSheet, system-theme media listener, and cleanup.\n */\n\nimport { getEditorStyleSheet } from './styles.js';\nimport { generateThemeCSS } from './theme/ThemeEngine.js';\nimport { type Theme, ThemePreset, resolveTheme } from './theme/ThemeTokens.js';\n\nexport class EditorThemeController {\n\tprivate themeStyleSheet: CSSStyleSheet = new CSSStyleSheet();\n\tprivate systemThemeQuery: MediaQueryList | null = null;\n\tprivate systemThemeHandler: ((e: MediaQueryListEvent) => void) | null = null;\n\tprivate pluginSheets: readonly CSSStyleSheet[] = [];\n\tprivate readonly shadow: ShadowRoot;\n\n\tconstructor(shadow: ShadowRoot) {\n\t\tthis.shadow = shadow;\n\t}\n\n\t/** Applies a theme preset or custom Theme to the shadow root. */\n\tapply(theme: ThemePreset | Theme): void {\n\t\tthis.cleanupSystemThemeListener();\n\n\t\tif (theme === ThemePreset.System) {\n\t\t\tthis.setupSystemThemeListener();\n\t\t\tconst resolved: Theme = resolveTheme(this.getSystemTheme());\n\t\t\tthis.setThemeStyleSheet(resolved);\n\t\t} else {\n\t\t\tthis.setThemeStyleSheet(resolveTheme(theme));\n\t\t}\n\t}\n\n\t/** Updates the plugin-registered stylesheets and refreshes adoptedStyleSheets. */\n\tsetPluginStyleSheets(sheets: readonly CSSStyleSheet[]): void {\n\t\tthis.pluginSheets = sheets;\n\t\tthis.refreshAdoptedStyleSheets();\n\t}\n\n\t/** Removes the system-theme listener. */\n\tdestroy(): void {\n\t\tthis.cleanupSystemThemeListener();\n\t}\n\n\tprivate setThemeStyleSheet(theme: Theme): void {\n\t\tthis.themeStyleSheet.replaceSync(generateThemeCSS(theme));\n\t\tthis.refreshAdoptedStyleSheets();\n\t}\n\n\tprivate refreshAdoptedStyleSheets(): void {\n\t\tthis.shadow.adoptedStyleSheets = [\n\t\t\tthis.themeStyleSheet,\n\t\t\tgetEditorStyleSheet(),\n\t\t\t...this.pluginSheets,\n\t\t];\n\t}\n\n\tprivate setupSystemThemeListener(): void {\n\t\tthis.systemThemeQuery = window.matchMedia('(prefers-color-scheme: dark)');\n\t\tthis.systemThemeHandler = (_e: MediaQueryListEvent): void => {\n\t\t\tconst resolved: Theme = resolveTheme(this.getSystemTheme());\n\t\t\tthis.setThemeStyleSheet(resolved);\n\t\t};\n\t\tthis.systemThemeQuery.addEventListener('change', this.systemThemeHandler);\n\t}\n\n\tprivate cleanupSystemThemeListener(): void {\n\t\tif (this.systemThemeQuery && this.systemThemeHandler) {\n\t\t\tthis.systemThemeQuery.removeEventListener('change', this.systemThemeHandler);\n\t\t}\n\t\tthis.systemThemeQuery = null;\n\t\tthis.systemThemeHandler = null;\n\t}\n\n\tprivate getSystemTheme(): ThemePreset {\n\t\tconst prefersDark: boolean = window.matchMedia('(prefers-color-scheme: dark)').matches;\n\t\treturn prefersDark ? ThemePreset.Dark : ThemePreset.Light;\n\t}\n}\n","/**\n * Manages the paper-mode DOM transformation and scale-to-fit behavior.\n *\n * In paper mode, the content element is reparented into a viewport/surface\n * structure that constrains it to the exact paper width. A ResizeObserver\n * drives CSS `transform: scale()` when the container is narrower than\n * the paper, producing a Google Docs-like shrink-to-fit effect.\n */\n\nimport { PAPER_VIEWPORT_PADDING_PX, type PaperSize, getPaperDimensions } from './PaperSize.js';\n\nexport class PaperLayoutController {\n\tprivate readonly wrapper: HTMLElement;\n\tprivate readonly content: HTMLElement;\n\n\tprivate viewport: HTMLElement | null = null;\n\tprivate surface: HTMLElement | null = null;\n\n\tprivate viewportObserver: ResizeObserver | null = null;\n\tprivate surfaceObserver: ResizeObserver | null = null;\n\n\tprivate currentSize: PaperSize | null = null;\n\tprivate currentPaperWidthPx = 0;\n\tprivate currentPaperHeightPx = 0;\n\tprivate currentScale = 1;\n\tprivate compensationFrameId: number | null = null;\n\n\tconstructor(wrapper: HTMLElement, content: HTMLElement) {\n\t\tthis.wrapper = wrapper;\n\t\tthis.content = content;\n\t}\n\n\t/** Enables, changes, or disables paper mode. Pass `null` to disable. */\n\tapply(paperSize: PaperSize | null): void {\n\t\tif (paperSize === null) {\n\t\t\tthis.disable();\n\t\t\treturn;\n\t\t}\n\n\t\tconst dims = getPaperDimensions(paperSize);\n\t\tthis.currentPaperWidthPx = dims.widthPx;\n\t\tthis.currentPaperHeightPx = dims.heightPx;\n\t\tthis.currentSize = paperSize;\n\n\t\tif (!this.viewport) {\n\t\t\tthis.enable();\n\t\t}\n\n\t\tthis.updateSurfaceDimensions();\n\t\tthis.wrapper.setAttribute('data-paper-mode', paperSize);\n\t}\n\n\t/** Cleans up observers and restores original DOM. */\n\tdestroy(): void {\n\t\tthis.disable();\n\t}\n\n\t/** Returns the currently applied paper size, or null if disabled. */\n\tgetPaperSize(): PaperSize | null {\n\t\treturn this.currentSize;\n\t}\n\n\t// --- Private ---\n\n\tprivate enable(): void {\n\t\t// Create viewport (scroll container)\n\t\tthis.viewport = document.createElement('div');\n\t\tthis.viewport.className = 'notectl-paper-viewport';\n\n\t\t// Create surface (page representation)\n\t\tthis.surface = document.createElement('div');\n\t\tthis.surface.className = 'notectl-paper-surface';\n\n\t\t// Reparent content: remove from wrapper, place inside surface\n\t\tthis.wrapper.removeChild(this.content);\n\t\tthis.surface.appendChild(this.content);\n\t\tthis.viewport.appendChild(this.surface);\n\n\t\t// Insert viewport after top plugin container (index 1 in wrapper children)\n\t\tconst bottomContainer: Element | null = this.wrapper.querySelector(\n\t\t\t'.notectl-plugin-container--bottom',\n\t\t);\n\t\tif (bottomContainer) {\n\t\t\tthis.wrapper.insertBefore(this.viewport, bottomContainer);\n\t\t} else {\n\t\t\tthis.wrapper.appendChild(this.viewport);\n\t\t}\n\n\t\t// Observe viewport width for scale-to-fit\n\t\tthis.viewportObserver = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tthis.onViewportResize(entry.contentRect.width);\n\t\t\t}\n\t\t});\n\t\tthis.viewportObserver.observe(this.viewport);\n\n\t\t// Observe surface height to compensate for layout shift from transform\n\t\tthis.surfaceObserver = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tthis.onSurfaceResize(entry.contentRect.height);\n\t\t\t}\n\t\t});\n\t\tthis.surfaceObserver.observe(this.surface);\n\t}\n\n\tprivate disable(): void {\n\t\tif (this.compensationFrameId !== null) {\n\t\t\tcancelAnimationFrame(this.compensationFrameId);\n\t\t\tthis.compensationFrameId = null;\n\t\t}\n\t\tthis.viewportObserver?.disconnect();\n\t\tthis.viewportObserver = null;\n\t\tthis.surfaceObserver?.disconnect();\n\t\tthis.surfaceObserver = null;\n\n\t\tif (this.viewport && this.surface) {\n\t\t\t// Reparent content back to wrapper\n\t\t\tthis.surface.removeChild(this.content);\n\n\t\t\tconst bottomContainer: Element | null = this.wrapper.querySelector(\n\t\t\t\t'.notectl-plugin-container--bottom',\n\t\t\t);\n\t\t\tif (bottomContainer) {\n\t\t\t\tthis.wrapper.insertBefore(this.content, bottomContainer);\n\t\t\t} else {\n\t\t\t\tthis.wrapper.appendChild(this.content);\n\t\t\t}\n\n\t\t\t// Remove viewport from wrapper\n\t\t\tthis.wrapper.removeChild(this.viewport);\n\t\t}\n\n\t\tthis.viewport = null;\n\t\tthis.surface = null;\n\t\tthis.currentSize = null;\n\t\tthis.currentPaperWidthPx = 0;\n\t\tthis.currentPaperHeightPx = 0;\n\t\tthis.currentScale = 1;\n\t\tthis.wrapper.removeAttribute('data-paper-mode');\n\t}\n\n\tprivate updateSurfaceDimensions(): void {\n\t\tif (!this.surface) return;\n\t\tthis.surface.style.width = `${this.currentPaperWidthPx}px`;\n\t\tthis.surface.style.minHeight = `${this.currentPaperHeightPx}px`;\n\t}\n\n\tprivate onViewportResize(viewportWidth: number): void {\n\t\tif (!this.surface || this.currentPaperWidthPx === 0) return;\n\n\t\tconst availableWidth: number = viewportWidth - 2 * PAPER_VIEWPORT_PADDING_PX;\n\t\tconst scale: number = Math.min(1, availableWidth / this.currentPaperWidthPx);\n\t\tthis.currentScale = scale;\n\n\t\tthis.surface.style.transform = scale < 1 ? `scale(${scale})` : '';\n\n\t\t// Compensate margin-bottom so parent layout sees correct visual height\n\t\tthis.scheduleHeightCompensation(scale);\n\t}\n\n\tprivate onSurfaceResize(_height: number): void {\n\t\tif (!this.surface || !this.viewport) return;\n\t\tthis.scheduleHeightCompensation(this.currentScale);\n\t}\n\n\tprivate scheduleHeightCompensation(scale: number): void {\n\t\tif (this.compensationFrameId !== null) {\n\t\t\tcancelAnimationFrame(this.compensationFrameId);\n\t\t}\n\t\tthis.compensationFrameId = requestAnimationFrame(() => {\n\t\t\tthis.compensationFrameId = null;\n\t\t\tthis.updateHeightCompensation(scale);\n\t\t});\n\t}\n\n\tprivate updateHeightCompensation(scale: number): void {\n\t\tif (!this.surface) return;\n\n\t\tif (scale >= 1) {\n\t\t\tthis.surface.style.marginBottom = '';\n\t\t\treturn;\n\t\t}\n\n\t\t// transform doesn't affect layout size, so the parent sees unscaled height.\n\t\t// Negative margin-bottom compensates: surfaceHeight * (1 - scale).\n\t\tconst surfaceHeight: number = this.surface.scrollHeight;\n\t\tconst visualHeight: number = surfaceHeight * scale;\n\t\tconst compensation: number = visualHeight - surfaceHeight;\n\t\tthis.surface.style.marginBottom = `${compensation}px`;\n\t}\n}\n","/**\n * NotectlEditor Web Component — the public-facing editor element.\n */\n\nimport { selectAll } from '../commands/Commands.js';\nimport { DecorationSet } from '../decorations/Decoration.js';\nimport type { Locale } from '../i18n/Locale.js';\nimport { LocaleService, LocaleServiceKey } from '../i18n/LocaleService.js';\nimport { registerBuiltinSpecs } from '../model/BuiltinSpecs.js';\nimport { type Document, getBlockText } from '../model/Document.js';\nimport { formatHTML } from '../model/HTMLUtils.js';\nimport { isMarkAllowed, schemaFromRegistry } from '../model/Schema.js';\nimport { createCollapsedSelection, selectionsEqual } from '../model/Selection.js';\nimport { blockId } from '../model/TypeBrands.js';\nimport type {\n\tEventKey,\n\tPlugin,\n\tPluginConfig,\n\tPluginEventCallback,\n\tServiceKey,\n} from '../plugins/Plugin.js';\nimport { PluginManager } from '../plugins/PluginManager.js';\nimport { CaretNavigationPlugin } from '../plugins/caret-navigation/CaretNavigationPlugin.js';\nimport { GapCursorPlugin } from '../plugins/gap-cursor/GapCursorPlugin.js';\nimport { BEFORE_PRINT } from '../plugins/print/PrintTypes.js';\nimport { TextFormattingPlugin } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport type { TextFormattingConfig } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport type { ToolbarOverflowBehavior } from '../plugins/toolbar/ToolbarOverflowBehavior.js';\nimport { ToolbarPlugin } from '../plugins/toolbar/ToolbarPlugin.js';\nimport type { ToolbarLayoutConfig } from '../plugins/toolbar/ToolbarPlugin.js';\nimport { EditorState } from '../state/EditorState.js';\nimport { isAllowedInReadonly } from '../state/ReadonlyGuard.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { EditorView } from '../view/EditorView.js';\nimport { buildAnnouncement } from './Announcer.js';\nimport { parseHTMLToDocument } from './DocumentParser.js';\nimport { serializeDocumentToHTML } from './DocumentSerializer.js';\nimport { createEditorDOM } from './EditorDOM.js';\nimport { EditorThemeController } from './EditorThemeController.js';\nimport { PaperLayoutController } from './PaperLayoutController.js';\nimport { type PaperSize, isValidPaperSize } from './PaperSize.js';\nimport { type Theme, ThemePreset } from './theme/ThemeTokens.js';\n\n/**\n * Expanded toolbar configuration for `createEditor`.\n * Allows specifying both the plugin layout and overflow behavior.\n */\nexport interface ToolbarConfig {\n\t/**\n\t * Plugin groups defining toolbar layout. Each inner array is a visual group;\n\t * separators are rendered between groups. Order = array order.\n\t */\n\treadonly groups: ReadonlyArray<ReadonlyArray<Plugin>>;\n\t/**\n\t * Controls responsive overflow behavior when items exceed available width.\n\t * Defaults to `ToolbarOverflowBehavior.BurgerMenu`.\n\t */\n\treadonly overflow?: ToolbarOverflowBehavior;\n}\n\nexport interface NotectlEditorConfig {\n\t/** Controls which inline marks are enabled. Used to auto-configure TextFormattingPlugin. */\n\tfeatures?: Partial<TextFormattingConfig>;\n\tplugins?: readonly Plugin[];\n\t/**\n\t * Toolbar configuration. Accepts either:\n\t * - A shorthand array of plugin groups: `[[BoldPlugin, ItalicPlugin], [HeadingPlugin]]`\n\t * - A full config object: `{ groups: [...], overflow: ToolbarOverflowBehavior.Flow }`\n\t *\n\t * When set, a ToolbarPlugin is created internally — do not add one to `plugins`.\n\t */\n\ttoolbar?: ReadonlyArray<ReadonlyArray<Plugin>> | ToolbarConfig;\n\tplaceholder?: string;\n\treadonly?: boolean;\n\tautofocus?: boolean;\n\tmaxHistoryDepth?: number;\n\t/** Theme preset or custom Theme object. Defaults to ThemePreset.Light. */\n\ttheme?: ThemePreset | Theme;\n\t/** Paper size for WYSIWYG page layout. When set, content renders at exact paper width. */\n\tpaperSize?: PaperSize;\n\t/** Editor locale. Defaults to Locale.BROWSER (auto-detect from navigator.language). */\n\tlocale?: Locale;\n}\n\nexport interface StateChangeEvent {\n\toldState: EditorState;\n\tnewState: EditorState;\n\ttransaction: Transaction;\n}\n\ntype EventMap = {\n\tstateChange: StateChangeEvent;\n\tselectionChange: { selection: import('../model/Selection.js').EditorSelection };\n\tfocus: undefined;\n\tblur: undefined;\n\tready: undefined;\n};\n\ntype EventCallback<T> = (payload: T) => void;\n\nexport class NotectlEditor extends HTMLElement {\n\tprivate view: EditorView | null = null;\n\tprivate pluginManager: PluginManager | null = null;\n\tprivate contentElement: HTMLElement | null = null;\n\tprivate editorWrapper: HTMLElement | null = null;\n\tprivate topPluginContainer: HTMLElement | null = null;\n\tprivate bottomPluginContainer: HTMLElement | null = null;\n\tprivate announcer: HTMLElement | null = null;\n\tprivate config: NotectlEditorConfig = {};\n\tprivate eventListeners: Map<string, Set<EventCallback<unknown>>> = new Map();\n\tprivate readyPromiseResolve: (() => void) | null = null;\n\tprivate readonly readyPromise: Promise<void>;\n\tprivate initialized = false;\n\tprivate preInitPlugins: Plugin[] = [];\n\tprivate themeController: EditorThemeController | null = null;\n\tprivate paperLayout: PaperLayoutController | null = null;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.readyPromise = new Promise((resolve) => {\n\t\t\tthis.readyPromiseResolve = resolve;\n\t\t});\n\t\tthis.attachShadow({ mode: 'open' });\n\t}\n\n\tstatic get observedAttributes(): string[] {\n\t\treturn ['placeholder', 'readonly', 'theme', 'paper-size'];\n\t}\n\n\tconnectedCallback(): void {\n\t\tif (this.initialized) return;\n\t\tthis.init();\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tsetTimeout(() => {\n\t\t\tif (!this.isConnected) {\n\t\t\t\tthis.destroy();\n\t\t\t}\n\t\t}, 0);\n\t}\n\n\tattributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n\t\tif (name === 'placeholder' && this.contentElement) {\n\t\t\tthis.contentElement.setAttribute('data-placeholder', newValue ?? '');\n\t\t}\n\t\tif (name === 'readonly' && this.contentElement) {\n\t\t\tconst isReadonly: boolean = newValue !== null;\n\t\t\tthis.contentElement.contentEditable = isReadonly ? 'false' : 'true';\n\t\t\tif (isReadonly) {\n\t\t\t\tthis.contentElement.setAttribute('aria-readonly', 'true');\n\t\t\t} else {\n\t\t\t\tthis.contentElement.removeAttribute('aria-readonly');\n\t\t\t}\n\t\t\tthis.config = { ...this.config, readonly: isReadonly };\n\t\t\tthis.pluginManager?.setReadOnly(isReadonly);\n\t\t}\n\t\tif (name === 'theme' && this.themeController) {\n\t\t\tthis.themeController.apply((newValue as ThemePreset) ?? ThemePreset.Light);\n\t\t}\n\t\tif (name === 'paper-size') {\n\t\t\tif (newValue === null) {\n\t\t\t\tthis.configure({ paperSize: undefined });\n\t\t\t} else if (isValidPaperSize(newValue)) {\n\t\t\t\tthis.configure({ paperSize: newValue });\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Registers a plugin before initialization. */\n\tregisterPlugin(plugin: Plugin): void {\n\t\tif (this.initialized) {\n\t\t\tthrow new Error(\n\t\t\t\t'Cannot register plugins after initialization. Register before calling init() or adding to DOM.',\n\t\t\t);\n\t\t}\n\t\tthis.preInitPlugins.push(plugin);\n\t}\n\n\t/** Initializes the editor with the given config. */\n\tasync init(config?: NotectlEditorConfig): Promise<void> {\n\t\tif (this.initialized) return;\n\t\tthis.initialized = true;\n\n\t\tif (config) this.config = config;\n\n\t\tconst shadow = this.shadowRoot;\n\t\tif (!shadow) return;\n\n\t\t// Apply theme (default: Light) — must happen before editor stylesheet\n\t\tthis.themeController = new EditorThemeController(shadow);\n\t\tthis.themeController.apply(this.config.theme ?? ThemePreset.Light);\n\n\t\t// 1. Build DOM structure\n\t\tconst dom = createEditorDOM({\n\t\t\treadonly: this.config.readonly,\n\t\t\tplaceholder: this.config.placeholder,\n\t\t});\n\t\tthis.editorWrapper = dom.wrapper;\n\t\tthis.contentElement = dom.content;\n\t\tthis.topPluginContainer = dom.topPluginContainer;\n\t\tthis.bottomPluginContainer = dom.bottomPluginContainer;\n\t\tthis.announcer = dom.announcer;\n\n\t\tshadow.appendChild(this.editorWrapper);\n\n\t\t// Apply paper layout if configured (before plugins, so initial render is correct)\n\t\tif (this.config.paperSize) {\n\t\t\tthis.paperLayout = new PaperLayoutController(this.editorWrapper, this.contentElement);\n\t\t\tthis.paperLayout.apply(this.config.paperSize);\n\t\t}\n\n\t\t// 2. Create PluginManager (SchemaRegistry is available)\n\t\tthis.pluginManager = new PluginManager();\n\n\t\t// Register global LocaleService before plugins so they can resolve locale\n\t\tconst localeService = new LocaleService(this.config.locale ?? 'browser');\n\t\tthis.pluginManager.registerService(LocaleServiceKey, localeService);\n\n\t\t// 3. Register built-in specs on the registry\n\t\tregisterBuiltinSpecs(this.pluginManager.schemaRegistry);\n\n\t\t// Process declarative toolbar config (registers ToolbarPlugin + toolbar plugins)\n\t\tthis.processToolbarConfig();\n\n\t\t// Register plugins from config\n\t\tfor (const plugin of this.config.plugins ?? []) {\n\t\t\tthis.pluginManager.register(plugin);\n\t\t}\n\n\t\t// Register plugins from registerPlugin() calls\n\t\tfor (const plugin of this.preInitPlugins) {\n\t\t\tthis.pluginManager.register(plugin);\n\t\t}\n\t\tthis.preInitPlugins = [];\n\n\t\t// Auto-register essential plugins if none were explicitly provided\n\t\tthis.ensureTextFormattingPlugin();\n\t\tthis.ensureCaretNavigationPlugin();\n\t\tthis.ensureGapCursorPlugin();\n\n\t\t// Set up DOM events before plugin init\n\t\tthis.contentElement.addEventListener('focus', () => this.emit('focus', undefined));\n\t\tthis.contentElement.addEventListener('blur', () => this.emit('blur', undefined));\n\n\t\t// 4. Initialize plugins — specs are registered during init().\n\t\t// onBeforeReady fires after all init() but before onReady(),\n\t\t// so the schema is complete and the view renders once.\n\t\tconst contentEl = this.contentElement;\n\t\tconst pluginMgr = this.pluginManager;\n\t\tconst topContainer = this.topPluginContainer;\n\t\tconst bottomContainer = this.bottomPluginContainer;\n\t\tif (!contentEl || !pluginMgr || !topContainer || !bottomContainer) return;\n\n\t\tconst announcer = this.announcer;\n\t\tawait pluginMgr.init({\n\t\t\tgetState: () => {\n\t\t\t\tif (!this.view) throw new Error('View not initialized');\n\t\t\t\treturn this.view.getState();\n\t\t\t},\n\t\t\tdispatch: (tr) => this.dispatch(tr),\n\t\t\tgetContainer: () => contentEl,\n\t\t\tgetPluginContainer: (position) => (position === 'top' ? topContainer : bottomContainer),\n\t\t\tannounce: (text: string) => {\n\t\t\t\tif (announcer) announcer.textContent = text;\n\t\t\t},\n\t\t\thasAnnouncement: () => !!announcer?.textContent,\n\t\t\tonBeforeReady: () => {\n\t\t\t\tconst schema = schemaFromRegistry(pluginMgr.schemaRegistry);\n\t\t\t\tconst state = EditorState.create({ schema });\n\t\t\t\tthis.view = new EditorView(contentEl, {\n\t\t\t\t\tstate,\n\t\t\t\t\tschemaRegistry: pluginMgr.schemaRegistry,\n\t\t\t\t\tkeymapRegistry: pluginMgr.keymapRegistry,\n\t\t\t\t\tinputRuleRegistry: pluginMgr.inputRuleRegistry,\n\t\t\t\t\tfileHandlerRegistry: pluginMgr.fileHandlerRegistry,\n\t\t\t\t\tnodeViewRegistry: pluginMgr.nodeViewRegistry,\n\t\t\t\t\tmaxHistoryDepth: this.config.maxHistoryDepth,\n\t\t\t\t\tgetDecorations: (s, tr) =>\n\t\t\t\t\t\tthis.pluginManager?.collectDecorations(s, tr) ?? DecorationSet.empty,\n\t\t\t\t\tonStateChange: (oldState, newState, tr) => {\n\t\t\t\t\t\tthis.onStateChange(oldState, newState, tr);\n\t\t\t\t\t},\n\t\t\t\t\tisReadOnly: () => this.config.readonly ?? false,\n\t\t\t\t});\n\t\t\t\tthis.updateEmptyState();\n\n\t\t\t\t// Inject plugin-registered stylesheets into adopted stylesheets\n\t\t\t\tconst pluginSheets = pluginMgr.getPluginStyleSheets();\n\t\t\t\tif (pluginSheets.length > 0) {\n\t\t\t\t\tthis.themeController?.setPluginStyleSheets(pluginSheets);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\t// Guard: editor may have been destroyed during async plugin init\n\t\tif (!this.pluginManager) return;\n\n\t\t// Notify plugins of initial readonly state\n\t\tif (this.config.readonly) {\n\t\t\tthis.pluginManager.setReadOnly(true);\n\t\t}\n\n\t\t// Register BEFORE_PRINT listener to inject paperSize as fallback\n\t\tthis.pluginManager.onEvent(BEFORE_PRINT, (event) => {\n\t\t\tif (!event.options.paperSize && this.config.paperSize) {\n\t\t\t\tevent.options = { ...event.options, paperSize: this.config.paperSize };\n\t\t\t}\n\t\t});\n\n\t\tif (this.config.autofocus) {\n\t\t\trequestAnimationFrame(() => this.contentElement?.focus());\n\t\t}\n\n\t\tthis.readyPromiseResolve?.();\n\t\tthis.emit('ready', undefined);\n\t}\n\n\t/** Returns whether the editor is in read-only mode. */\n\tget isReadOnly(): boolean {\n\t\treturn this.config.readonly ?? false;\n\t}\n\n\t// --- Content API ---\n\n\t/** Returns the document as JSON. */\n\tgetJSON(): Document {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\treturn this.view.getState().doc;\n\t}\n\n\t/** Sets the document from JSON. */\n\tsetJSON(doc: Document): void {\n\t\tconst schema = this.pluginManager\n\t\t\t? schemaFromRegistry(this.pluginManager.schemaRegistry)\n\t\t\t: undefined;\n\t\tconst state = EditorState.create({\n\t\t\tdoc,\n\t\t\tschema,\n\t\t\tselection: createCollapsedSelection(doc.children[0]?.id ?? blockId(''), 0),\n\t\t});\n\t\tthis.replaceState(state);\n\t}\n\n\t/** Returns sanitized HTML representation of the document. */\n\tgetContentHTML(options?: { pretty?: boolean }): string {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\tconst html: string = serializeDocumentToHTML(\n\t\t\tthis.view.getState().doc,\n\t\t\tthis.pluginManager?.schemaRegistry,\n\t\t);\n\t\treturn options?.pretty ? formatHTML(html) : html;\n\t}\n\n\t/** Sets content from HTML (sanitized). */\n\tsetContentHTML(html: string): void {\n\t\tconst doc = parseHTMLToDocument(html, this.pluginManager?.schemaRegistry);\n\t\tthis.setJSON(doc);\n\t}\n\n\t/** Returns plain text content. */\n\tgetText(): string {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\tconst doc = this.view.getState().doc;\n\t\treturn doc.children.map((b) => getBlockText(b)).join('\\n');\n\t}\n\n\t/** Returns true if the editor is empty (single empty paragraph). */\n\tisEmpty(): boolean {\n\t\tif (!this.view) return true;\n\t\tconst doc = this.view.getState().doc;\n\t\tif (doc.children.length === 0) return true;\n\t\tif (doc.children.length > 1) return false;\n\t\tconst block = doc.children[0];\n\t\tif (!block) return true;\n\t\treturn block.type === 'paragraph' && getBlockText(block) === '';\n\t}\n\n\t// --- Command API ---\n\n\treadonly commands = {\n\t\ttoggleBold: () => this.executeCommand('toggleBold'),\n\t\ttoggleItalic: () => this.executeCommand('toggleItalic'),\n\t\ttoggleUnderline: () => this.executeCommand('toggleUnderline'),\n\t\tundo: () => {\n\t\t\tif (this.config.readonly) return;\n\t\t\tthis.view?.undo();\n\t\t},\n\t\tredo: () => {\n\t\t\tif (this.config.readonly) return;\n\t\t\tthis.view?.redo();\n\t\t},\n\t\tselectAll: () => {\n\t\t\tif (!this.view) return;\n\t\t\tconst tr = selectAll(this.view.getState());\n\t\t\tthis.dispatch(tr);\n\t\t},\n\t};\n\n\t/** Checks whether a command can be executed. */\n\tcan(): {\n\t\ttoggleBold: () => boolean;\n\t\ttoggleItalic: () => boolean;\n\t\ttoggleUnderline: () => boolean;\n\t\tundo: () => boolean;\n\t\tredo: () => boolean;\n\t\tselectAll: () => boolean;\n\t} {\n\t\tconst schema = this.view?.getState().schema;\n\t\tconst readonly: boolean = this.config.readonly ?? false;\n\t\treturn {\n\t\t\ttoggleBold: () => !readonly && (schema ? isMarkAllowed(schema, 'bold') : false),\n\t\t\ttoggleItalic: () => !readonly && (schema ? isMarkAllowed(schema, 'italic') : false),\n\t\t\ttoggleUnderline: () => !readonly && (schema ? isMarkAllowed(schema, 'underline') : false),\n\t\t\tundo: () => !readonly && (this.view?.history.canUndo() ?? false),\n\t\t\tredo: () => !readonly && (this.view?.history.canRedo() ?? false),\n\t\t\tselectAll: () => this.canExecuteCommand('selectAll'),\n\t\t};\n\t}\n\n\t/** Returns whether a named command can be executed. */\n\tcanExecuteCommand(name: string): boolean {\n\t\treturn this.pluginManager?.canExecuteCommand(name) ?? false;\n\t}\n\n\t/** Executes a named command registered by a plugin. */\n\texecuteCommand(name: string): boolean {\n\t\treturn this.pluginManager?.executeCommand(name) ?? false;\n\t}\n\n\t/** Configures a plugin at runtime. */\n\tconfigurePlugin(pluginId: string, config: PluginConfig): void {\n\t\tthis.pluginManager?.configurePlugin(pluginId, config);\n\t}\n\n\t/** Returns a registered plugin service by typed key. */\n\tgetService<T>(key: ServiceKey<T>): T | undefined {\n\t\treturn this.pluginManager?.getService(key);\n\t}\n\n\t/** Subscribes to a plugin event. Returns an unsubscribe function. */\n\tonPluginEvent<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void {\n\t\treturn this.pluginManager?.onEvent(key, callback) ?? (() => {});\n\t}\n\n\t// --- State API ---\n\n\t/** Returns the current editor state. */\n\tgetState(): EditorState {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\treturn this.view.getState();\n\t}\n\n\t/** Dispatches a transaction (routed through middleware if any). */\n\tdispatch(tr: Transaction): void {\n\t\tif (!this.view || !this.pluginManager) return;\n\t\tif (\n\t\t\tthis.config.readonly &&\n\t\t\t!isAllowedInReadonly(tr) &&\n\t\t\t!this.pluginManager.isReadonlyBypassed()\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tthis.pluginManager.dispatchWithMiddleware(tr, this.view.getState(), (finalTr) =>\n\t\t\tthis.view?.dispatch(finalTr),\n\t\t);\n\t}\n\n\t// --- Event API ---\n\n\t/** Registers an event listener. */\n\ton<K extends keyof EventMap>(event: K, callback: EventCallback<EventMap[K]>): void {\n\t\tif (!this.eventListeners.has(event)) {\n\t\t\tthis.eventListeners.set(event, new Set());\n\t\t}\n\t\tthis.eventListeners.get(event)?.add(callback as EventCallback<unknown>);\n\t}\n\n\t/** Removes an event listener. */\n\toff<K extends keyof EventMap>(event: K, callback: EventCallback<EventMap[K]>): void {\n\t\tthis.eventListeners.get(event)?.delete(callback as EventCallback<unknown>);\n\t}\n\n\t// --- Lifecycle ---\n\n\t/** Waits for the editor to be ready. */\n\twhenReady(): Promise<void> {\n\t\treturn this.readyPromise;\n\t}\n\n\t/** Updates configuration at runtime. */\n\tconfigure(config: Partial<NotectlEditorConfig>): void {\n\t\tif (config.placeholder !== undefined && this.contentElement) {\n\t\t\tthis.contentElement.setAttribute('data-placeholder', config.placeholder);\n\t\t}\n\n\t\tif (config.readonly !== undefined && this.contentElement) {\n\t\t\tthis.contentElement.contentEditable = config.readonly ? 'false' : 'true';\n\t\t\tif (config.readonly) {\n\t\t\t\tthis.contentElement.setAttribute('aria-readonly', 'true');\n\t\t\t} else {\n\t\t\t\tthis.contentElement.removeAttribute('aria-readonly');\n\t\t\t}\n\t\t\tthis.pluginManager?.setReadOnly(config.readonly);\n\t\t}\n\n\t\tif ('paperSize' in config) {\n\t\t\tthis.applyPaperSize(config.paperSize);\n\t\t}\n\n\t\tthis.config = { ...this.config, ...config };\n\t}\n\n\t// --- Theme API ---\n\n\t/** Changes the theme at runtime. */\n\tsetTheme(theme: ThemePreset | Theme): void {\n\t\tthis.config = { ...this.config, theme };\n\t\tthis.themeController?.apply(theme);\n\t}\n\n\t/** Returns the current theme setting. */\n\tgetTheme(): ThemePreset | Theme {\n\t\treturn this.config.theme ?? ThemePreset.Light;\n\t}\n\n\t// --- Paper Size API ---\n\n\t/** Returns the currently configured paper size, or undefined if fluid layout. */\n\tgetPaperSize(): PaperSize | undefined {\n\t\treturn this.config.paperSize;\n\t}\n\n\t/** Cleans up the editor. Awaiting ensures async plugin teardown completes. */\n\tdestroy(): Promise<void> {\n\t\tthis.paperLayout?.destroy();\n\t\tthis.paperLayout = null;\n\t\tthis.themeController?.destroy();\n\t\tthis.themeController = null;\n\t\tthis.view?.destroy();\n\t\tconst pluginTeardown = this.pluginManager?.destroy() ?? Promise.resolve();\n\t\tthis.view = null;\n\t\tthis.pluginManager = null;\n\t\tthis.initialized = false;\n\t\tthis.editorWrapper?.remove();\n\t\tthis.editorWrapper = null;\n\t\tthis.contentElement = null;\n\t\tthis.topPluginContainer = null;\n\t\tthis.bottomPluginContainer = null;\n\t\tthis.announcer = null;\n\t\treturn pluginTeardown;\n\t}\n\n\t/**\n\t * Processes the declarative `toolbar` config: registers a ToolbarPlugin\n\t * with layout groups, then registers all plugins from the toolbar groups.\n\t * Accepts both the shorthand array and the full ToolbarConfig object.\n\t */\n\tprivate processToolbarConfig(): void {\n\t\tif (!this.pluginManager || !this.config.toolbar) return;\n\n\t\tconst toolbarCfg = this.config.toolbar;\n\t\tconst isShorthand: boolean = Array.isArray(toolbarCfg);\n\t\tconst pluginGroups: ReadonlyArray<ReadonlyArray<Plugin>> = isShorthand\n\t\t\t? (toolbarCfg as ReadonlyArray<ReadonlyArray<Plugin>>)\n\t\t\t: (toolbarCfg as ToolbarConfig).groups;\n\t\tconst overflow: ToolbarOverflowBehavior | undefined = isShorthand\n\t\t\t? undefined\n\t\t\t: (toolbarCfg as ToolbarConfig).overflow;\n\n\t\tconst groups: string[][] = [];\n\t\tfor (const group of pluginGroups) {\n\t\t\tconst pluginIds: string[] = [];\n\t\t\tfor (const plugin of group) {\n\t\t\t\tpluginIds.push(plugin.id);\n\t\t\t\tthis.pluginManager.register(plugin);\n\t\t\t}\n\t\t\tgroups.push(pluginIds);\n\t\t}\n\n\t\tconst layoutConfig: ToolbarLayoutConfig = { groups, overflow };\n\t\tthis.pluginManager.register(new ToolbarPlugin(layoutConfig));\n\t}\n\n\t/**\n\t * Auto-registers TextFormattingPlugin if no plugin with id 'text-formatting'\n\t * was explicitly registered. Uses the `features` config to determine which marks to enable.\n\t */\n\tprivate ensureTextFormattingPlugin(): void {\n\t\tif (!this.pluginManager) return;\n\n\t\tconst hasTextFormatting = this.pluginManager.get('text-formatting') !== undefined;\n\t\tif (hasTextFormatting) return;\n\n\t\tconst features: TextFormattingConfig = {\n\t\t\tbold: this.config.features?.bold ?? true,\n\t\t\titalic: this.config.features?.italic ?? true,\n\t\t\tunderline: this.config.features?.underline ?? true,\n\t\t};\n\n\t\tthis.pluginManager.register(new TextFormattingPlugin(features));\n\t}\n\n\t/** Auto-registers CaretNavigationPlugin if not explicitly provided. */\n\tprivate ensureCaretNavigationPlugin(): void {\n\t\tif (!this.pluginManager) return;\n\t\tif (this.pluginManager.get('caret-navigation') !== undefined) return;\n\t\tthis.pluginManager.register(new CaretNavigationPlugin());\n\t}\n\n\t/** Auto-registers GapCursorPlugin if not explicitly provided. */\n\tprivate ensureGapCursorPlugin(): void {\n\t\tif (!this.pluginManager) return;\n\t\tif (this.pluginManager.get('gap-cursor') !== undefined) return;\n\t\tthis.pluginManager.register(new GapCursorPlugin());\n\t}\n\n\tprivate applyPaperSize(paperSize: PaperSize | undefined): void {\n\t\tif (!this.editorWrapper || !this.contentElement) return;\n\n\t\tif (!paperSize) {\n\t\t\tthis.paperLayout?.apply(null);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.paperLayout) {\n\t\t\tthis.paperLayout = new PaperLayoutController(this.editorWrapper, this.contentElement);\n\t\t}\n\t\tthis.paperLayout.apply(paperSize);\n\t}\n\n\tprivate emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n\t\tconst listeners = this.eventListeners.get(event);\n\t\tif (listeners) {\n\t\t\tfor (const cb of listeners) {\n\t\t\t\t(cb as EventCallback<EventMap[K]>)(payload);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onStateChange(oldState: EditorState, newState: EditorState, tr: Transaction): void {\n\t\t// Clear announcer so plugin announcements can be detected\n\t\tif (this.announcer) this.announcer.textContent = '';\n\n\t\t// Notify plugins (with transaction) — plugins may call context.announce()\n\t\tthis.pluginManager?.notifyStateChange(oldState, newState, tr);\n\n\t\t// Update empty state\n\t\tthis.updateEmptyState();\n\n\t\t// Emit events\n\t\tthis.emit('stateChange', { oldState, newState, transaction: tr });\n\n\t\tif (!selectionsEqual(oldState.selection, newState.selection)) {\n\t\t\tthis.emit('selectionChange', { selection: newState.selection });\n\t\t}\n\n\t\t// Announce state changes for screen readers (skip if a plugin already announced)\n\t\tif (!this.announcer?.textContent) {\n\t\t\tconst announcement: string | null = buildAnnouncement(oldState, newState, tr);\n\t\t\tif (announcement && this.announcer) {\n\t\t\t\tthis.announcer.textContent = announcement;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updateEmptyState(): void {\n\t\tif (!this.contentElement) return;\n\t\tthis.contentElement.classList.toggle('notectl-content--empty', this.isEmpty());\n\t}\n\n\tprivate replaceState(newState: EditorState): void {\n\t\tif (!this.view) return;\n\n\t\tthis.view.replaceState(newState);\n\t\tthis.updateEmptyState();\n\t}\n}\n\n// Register custom element (guarded for SSR / non-browser environments)\nif (typeof customElements !== 'undefined' && !customElements.get('notectl-editor')) {\n\tcustomElements.define('notectl-editor', NotectlEditor);\n}\n\n/** Factory function to create and configure a NotectlEditor instance. */\nexport async function createEditor(config?: NotectlEditorConfig): Promise<NotectlEditor> {\n\tconst editor = document.createElement('notectl-editor') as NotectlEditor;\n\tawait editor.init(config);\n\treturn editor;\n}\n","/**\n * EditorDOM: builds the editor's internal DOM structure.\n * Pure function — returns a struct of freshly created elements.\n */\n\nexport interface EditorDOMConfig {\n\treadonly readonly?: boolean;\n\treadonly placeholder?: string;\n}\n\nexport interface EditorDOMElements {\n\treadonly wrapper: HTMLElement;\n\treadonly content: HTMLElement;\n\treadonly topPluginContainer: HTMLElement;\n\treadonly bottomPluginContainer: HTMLElement;\n\treadonly announcer: HTMLElement;\n}\n\n/** Creates the editor DOM tree and returns references to all key elements. */\nexport function createEditorDOM(config: EditorDOMConfig): EditorDOMElements {\n\tconst wrapper: HTMLElement = document.createElement('div');\n\twrapper.className = 'notectl-editor';\n\n\tconst topPluginContainer: HTMLElement = document.createElement('div');\n\ttopPluginContainer.className = 'notectl-plugin-container--top';\n\ttopPluginContainer.setAttribute('data-notectl-no-print', '');\n\n\tconst content: HTMLElement = document.createElement('div');\n\tcontent.className = 'notectl-content';\n\tcontent.contentEditable = config.readonly ? 'false' : 'true';\n\tcontent.setAttribute('role', 'textbox');\n\tcontent.setAttribute('aria-multiline', 'true');\n\tcontent.setAttribute('aria-label', 'Rich text editor');\n\tif (config.readonly) {\n\t\tcontent.setAttribute('aria-readonly', 'true');\n\t}\n\tcontent.setAttribute('aria-description', 'Press Escape to exit the editor');\n\tcontent.setAttribute('data-placeholder', config.placeholder ?? 'Start typing...');\n\n\tconst bottomPluginContainer: HTMLElement = document.createElement('div');\n\tbottomPluginContainer.className = 'notectl-plugin-container--bottom';\n\tbottomPluginContainer.setAttribute('data-notectl-no-print', '');\n\n\t// Screen reader announcer\n\tconst announcer: HTMLElement = document.createElement('div');\n\tannouncer.className = 'notectl-sr-only';\n\tannouncer.setAttribute('data-notectl-no-print', '');\n\tannouncer.setAttribute('aria-live', 'polite');\n\tannouncer.setAttribute('aria-atomic', 'true');\n\n\twrapper.appendChild(topPluginContainer);\n\twrapper.appendChild(content);\n\twrapper.appendChild(bottomPluginContainer);\n\twrapper.appendChild(announcer);\n\n\treturn { wrapper, content, topPluginContainer, bottomPluginContainer, announcer };\n}\n","/**\n * Minimal preset: a lightweight editor with only font selection.\n */\n\nimport { FontPlugin } from '../plugins/font/FontPlugin.js';\nimport { STARTER_FONTS } from '../plugins/font/StarterFonts.js';\nimport type { MinimalPresetOptions, PresetConfig } from './PresetTypes.js';\n\n/**\n * Creates a minimal editor preset with font selection only.\n * CaretNavigation and GapCursor are auto-registered by the editor.\n */\nexport function createMinimalPreset(options?: MinimalPresetOptions): PresetConfig {\n\tconst fontPlugin: FontPlugin = new FontPlugin({\n\t\tfonts: STARTER_FONTS,\n\t\t...options?.font,\n\t});\n\n\treturn {\n\t\ttoolbar: [[fontPlugin]],\n\t\tplugins: [],\n\t};\n}\n","/**\n * Full preset: a fully-featured editor with all standard plugins.\n */\n\nimport { AlignmentPlugin } from '../plugins/alignment/AlignmentPlugin.js';\nimport { BlockquotePlugin } from '../plugins/blockquote/BlockquotePlugin.js';\nimport { CodeBlockPlugin } from '../plugins/code-block/CodeBlockPlugin.js';\nimport { FontSizePlugin } from '../plugins/font-size/FontSizePlugin.js';\nimport { FontPlugin } from '../plugins/font/FontPlugin.js';\nimport { STARTER_FONTS } from '../plugins/font/StarterFonts.js';\nimport { HardBreakPlugin } from '../plugins/hard-break/HardBreakPlugin.js';\nimport { HeadingPlugin } from '../plugins/heading/HeadingPlugin.js';\nimport { HighlightPlugin } from '../plugins/highlight/HighlightPlugin.js';\nimport { HorizontalRulePlugin } from '../plugins/horizontal-rule/HorizontalRulePlugin.js';\nimport { ImagePlugin } from '../plugins/image/ImagePlugin.js';\nimport { LinkPlugin } from '../plugins/link/LinkPlugin.js';\nimport { ListPlugin } from '../plugins/list/ListPlugin.js';\nimport { PrintPlugin } from '../plugins/print/PrintPlugin.js';\nimport { StrikethroughPlugin } from '../plugins/strikethrough/StrikethroughPlugin.js';\nimport { SuperSubPlugin } from '../plugins/super-sub/SuperSubPlugin.js';\nimport { TablePlugin } from '../plugins/table/TablePlugin.js';\nimport { TextColorPlugin } from '../plugins/text-color/TextColorPlugin.js';\nimport { TextFormattingPlugin } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport type { FullPresetOptions, PresetConfig } from './PresetTypes.js';\n\n/**\n * Creates a fully-featured editor preset with all standard plugins.\n *\n * Toolbar groups:\n * 1. Typography: Font, FontSize\n * 2. Inline marks: TextFormatting, Strikethrough, SuperSub\n * 3. Colors: TextColor, Highlight\n * 4. Block types: Heading, Blockquote, CodeBlock\n * 5. Paragraph layout: Alignment\n * 6. Lists: List\n * 7. Insert objects: Link, Table, HorizontalRule, Image\n * 8. Utility: Print\n */\nexport function createFullPreset(options?: FullPresetOptions): PresetConfig {\n\treturn {\n\t\ttoolbar: [\n\t\t\t[\n\t\t\t\tnew FontPlugin({ fonts: STARTER_FONTS, ...options?.font }),\n\t\t\t\tnew FontSizePlugin(options?.fontSize),\n\t\t\t],\n\t\t\t[\n\t\t\t\tnew TextFormattingPlugin(options?.textFormatting),\n\t\t\t\tnew StrikethroughPlugin(options?.strikethrough),\n\t\t\t\tnew SuperSubPlugin(options?.superSub),\n\t\t\t],\n\t\t\t[new TextColorPlugin(options?.textColor), new HighlightPlugin(options?.highlight)],\n\t\t\t[\n\t\t\t\tnew HeadingPlugin(options?.heading),\n\t\t\t\tnew BlockquotePlugin(options?.blockquote),\n\t\t\t\tnew CodeBlockPlugin(options?.codeBlock),\n\t\t\t],\n\t\t\t[new AlignmentPlugin(options?.alignment)],\n\t\t\t[new ListPlugin(options?.list)],\n\t\t\t[\n\t\t\t\tnew LinkPlugin(options?.link),\n\t\t\t\tnew TablePlugin(options?.table),\n\t\t\t\tnew HorizontalRulePlugin(options?.horizontalRule),\n\t\t\t\tnew ImagePlugin(options?.image),\n\t\t\t],\n\t\t\t[new PrintPlugin(options?.print)],\n\t\t],\n\t\tplugins: [new HardBreakPlugin()],\n\t};\n}\n"],"names":["SchemaRegistry","_nodeSpecs","Map","_markSpecs","_inlineNodeSpecs","spec","this","has","type","Error","set","get","delete","getNodeTypes","keys","getMarkTypes","getInlineNodeTypes","getBlockParseRules","results","parseHTML","rule","push","sort","a","b","priority","getInlineParseRules","getMarkParseRules","getAllowedTags","tags","Set","values","sanitize","tag","add","getAllowedAttrs","attrs","attr","clear","canContain","registry","parentType","childType","parentSpec","getNodeSpec","content","childSpec","childGroup","group","allowed","allow","validateContent","childTypes","min","max","Number","POSITIVE_INFINITY","blockChildTypes","filter","t","length","registerBuiltinSpecs","registerNodeSpec","toDOM","node","createBlockElement","id","toHTML","_node","mapBlock","doc","blockId","fn","children","mapBlockInChildren","map","child","isBlockNode","mappedChildren","mapNodeByPath","path","rootId","mapNodeByPathRecursive","depth","targetId","newChildren","findAndTransformChildren","predicate","transform","changed","result","sliceInlineContent","nodes","from","to","pos","isInlineNode","nodeEnd","text","sliceFrom","Math","sliceTo","slice","createTextNode","marks","applyMarkToInlineContent","mark","newMarks","addMarkToSet","removeMarkFromSet","overlapStart","overlapEnd","beforeText","insideText","afterText","replaceInlineChildren","original","newInlineChildren","every","c","isTextNode","blockChildren","applyStep","step","block","inlineChildren","getInlineChildren","segments","offset","inserted","seg","localOffset","before","after","normalizeInlineContent","deleteFrom","deleteTo","remaining","transformed","some","blockIndex","findIndex","len","getBlockLength","nodesBeforeSplit","nodesAfterSplit","updatedBlock","newBlock","createBlockNode","newBlockId","splice","targetBlockId","sourceBlockId","targetIdx","sourceIdx","target","source","targetInline","sourceInline","mergedChildren","mergedBlock","nodeType","parentPath","index","parent","nodeId","inlineNode","invertStep","deletedText","deletedMarks","deletedSegments","targetLengthBefore","previousMarks","previousNodeType","previousAttrs","removedNode","invertTransaction","tr","steps","reverse","selectionBefore","selectionAfter","storedMarksAfter","metadata","origin","timestamp","Date","now","TransactionBuilder","selection","storedMarks","workingDoc","_readonlyAllowed","currentSelection","currentStoredMarks","advanceDoc","findNode","getBlockSegmentsInRange","getBlockText","getBlockMarksAtOffset","deleteText","targetBlock","mergeBlocks","resolveNodeByPath","join","getContentAtOffset","kind","readonlyAllowed","createNodeSelection","EditorState","schema","_blockMap","_blockOrder","options","defaultSchema","createDocument","firstBlock","createCollapsedSelection","sel","isNodeSelection","fallbackSelection","isGapCursor","anchor","validatePosition","head","createSelection","walk","blocks","getBlockOrder","order","isLeafBlock","findNodePath","parentId","toJSON","json","createPosition","leaf","findFirstLeafBlock","nested","isSelectionOnlyTransaction","isAllowedInReadonly","HistoryManager","undoStack","redoStack","groupTimeoutMs","maxDepth","lastOrigin","lastGroup","isSameInputType","transactions","shift","state","pop","currentState","allSteps","i","inverted","apply","transaction","historyDirection","canUndo","canRedo","existing","incoming","lastTr","lastStepType","incomingStepType","deleteInDirection","config","deleteNodeSelection","isCollapsed","deleteSelectionCommand","getBlock","range","merge","deleteTextAt","setSelection","build","deleteBackward","mergeBlockBackward","_block","deleteForward","mergeBlockForward","KeyboardHandler","element","getState","dispatch","undo","redo","keymapRegistry","isReadOnly","compositionTracker","handleKeydown","onKeydown","bind","addEventListener","e","isComposing","handleNodeSelectionKeys","handleGapCursorKeys","descriptor","normalizeKeyDescriptor","navKeymaps","getKeymapsByPriority","navigation","handler","preventDefault","handleEscape","groups","keymaps","context","default","handleGapCursorArrowFallback","handleTab","metaKey","ctrlKey","key","toLowerCase","shiftKey","selectAll","altKey","navigateArrowIntoVoid","splitBlockCommand","deleteBackwardAtGap","deleteForwardAtGap","insertTextCommand","navigateFromGapCursor","selectionsEqual","blur","removeEventListener","parts","toUpperCase","buildMarkOrder","types","getMarkSpec","rank","serializeMarksToHTML","markOrder","html","escapeHTML","sortedMarks","styleParts","tagMarks","markSpec","toHTMLStyle","style","toHTMLString","current","ClipboardHandler","schemaRegistry","syncSelection","handleCopy","onCopy","handleCut","onCut","isTextSelection","clipboardData","writeNodeSelectionToClipboard","writeTextSelectionToClipboard","blockData","setData","JSON","stringify","altText","alt","blockOrder","selectionRange","fromIdx","indexOf","toIdx","lines","richBlocks","bid","blockLen","start","end","sliced","plainText","htmlParts","serializeBlockRangeToHTML","childEnd","getInlineNodeSpec","inlineType","destroy","CompositionTracker","_composing","_activeBlockId","KeymapRegistry","_contextKeymaps","_navigationKeymaps","_defaultKeymaps","keymap","allKeymaps","Object","console","debug","keymapArrayForPriority","arr","idx","InputRuleRegistry","_inputRules","getInputRules","FileHandlerRegistry","_fileHandlers","pattern","getFileHandlers","mimeType","handlers","entry","matchMimePattern","endsWith","prefix","startsWith","NodeViewRegistry","_nodeViews","factory","ToolbarRegistry","_toolbarItems","_toolbarItemPluginMap","item","pluginId","ids","items","getToolbarItems","BlockTypePickerRegistry","_entries","getBlockTypePickerEntries","getMarkRank","createMarkElement","document","createElement","CursorWrapper","wrapperElement","container","isActive","cleanup","wrapper","setAttribute","textNode","el","appendChild","domSel","getSelection","rangeCount","getRangeAt","insertNode","collapse","remove","GRID_NAV_KEYS","attachMenuKeyboard","focusedIndex","stopPropagation","Array","querySelectorAll","itemSelector","onClose","findNextDropdownItem","applyRovingTabindex","focus","onActivate","attachListboxKeyboard","onSelect","attachGridKeyboard","columns","totalCells","totalRows","ceil","cells","cellSelector","cell","currentRow","floor","currentCol","newRow","newCol","navigateGrid","newIdx","onNavigate","rowStart","rowEnd","EventBus","listeners","payload","listener","err","error","callback","size","PluginManager","plugins","commands","services","middlewares","registrations","eventBus","pluginStyleSheets","inputRuleRegistry","fileHandlerRegistry","nodeViewRegistry","toolbarRegistry","blockTypePickerRegistry","middlewareSorted","initOrder","initialized","initializing","readOnly","readonlyBypassActive","service","plugin","resolveOrder","createContext","init","onBeforeReady","onReady","oldState","newState","onStateChange","DecorationSet","empty","decorations","decos","isEmpty","finalDispatch","sorted","getSortedMiddleware","dispatched","next","currentTr","called","guardedNext","middleware","name","enableBypass","onConfigure","readonly","onReadOnlyChange","getMiddlewareChain","on","getPluginStyleSheets","reversed","destroyPlugin","cleanupRegistrations","reg","serviceId","unsub","unsubscribers","nodeSpecs","removeNodeSpec","markSpecs","removeMarkSpec","inlineNodeSpecs","removeInlineNodeSpec","nodeViews","removeNodeView","removeKeymap","inputRules","removeInputRule","itemId","toolbarItems","removeToolbarItem","fileHandlers","removeFileHandler","entryId","blockTypePickerEntries","removeBlockTypePickerEntry","sheet","stylesheets","pluginEventBus","emit","off","getContainer","getPluginContainer","registerCommand","executeCommand","getEventBus","registerMiddleware","registerService","getService","updateConfig","registerMarkSpec","registerNodeView","registerKeymap","registerInputRule","registerToolbarItem","registerInlineNodeSpec","registerFileHandler","registerBlockTypePickerEntry","getSchemaRegistry","getKeymapRegistry","getInputRuleRegistry","getFileHandlerRegistry","getNodeViewRegistry","getToolbarRegistry","getBlockTypePickerRegistry","registerStyleSheet","css","CSSStyleSheet","replaceSync","announce","hasAnnouncement","dep","dependencies","inDegree","dependents","deps","depList","queue","deg","newDeg","missing","includes","PRINT_LOCALE_EN","label","tooltip","shortcut","printingAnnouncement","PRINT_LOCALES","en","de","es","fr","zh","ru","ar","hi","resolveContent","value","MM_TO_PX","PaperSize","DINA4","DINA5","USLetter","USLegal","mmToPx","mm","round","PAPER_DIMENSIONS","widthMm","heightMm","widthPx","heightPx","CSS_SIZE_KEYWORDS","getPaperDimensions","dims","PAPER_MARGIN_TOP_PX","PAPER_MARGIN_HORIZONTAL_PX","PAPER_VIEWPORT_PADDING_PX","isValidPaperSize","getPaperCSSSize","keyword","PRINT_SERVICE_KEY","ServiceKey","BEFORE_PRINT","EventKey","AFTER_PRINT","NOOP_SERVICE","print","PrintPlugin","locale","resolvePluginLocale","rootNode","getRootNode","ShadowRoot","host","shadowRoot","mergeOptions","executePrint","beforeEvent","cancelled","finalOptions","title","lang","replace","adopted","adoptedStyleSheets","cssRules","cssText","theme","computed","getComputedStyle","tokens","prop","getPropertyValue","trim","paperSize","props","rules","printCSS","pageProps","margin","orientation","sizeParts","printRules","printBackground","customCSS","clone","querySelector","cloneNode","removeAttribute","selectionClasses","cls","classList","excludeBlockTypes","elements","pageBreakBefore","breakBefore","header","headerEl","className","innerHTML","insertBefore","firstChild","footer","footerEl","outerHTML","closest","getAttribute","documentElement","afterEvent","iframe","body","iframeDoc","contentDocument","removeChild","open","write","close","contentWindow","once","defaults","printLocale","keyBinding","showToolbarItem","formatShortcut","icon","command","ThemePreset","Light","Dark","System","LIGHT_THEME","primitives","background","foreground","mutedForeground","border","borderFocus","primary","primaryForeground","primaryMuted","surfaceRaised","surfaceOverlay","hoverBackground","activeBackground","danger","dangerMuted","success","shadow","focusRing","codeBlock","headerBackground","headerForeground","headerBorder","DARK_THEME","createTheme","base","overrides","toolbar","resolveTheme","VARIABLE_MAP","COMPONENT_FALLBACKS","resolvePath","split","part","generateThemeCSS","cssVar","fallback","createThemeStyleSheet","Locale","EN","DE","ES","FR","ZH","RU","AR","HI","BROWSER","VALID_ALIGNMENTS","serializeDocumentToHTML","serializeBlocks","allowedTags","allowedAttrs","DOMPurify","ALLOWED_TAGS","ALLOWED_ATTR","isNodeOfType","listItems","serializeListGroup","serializeBlock","stack","listType","indent","top","nextItem","nextIndent","stripTrailingLiClose","merged","prev","markSetsEqual","inlineSpec","getBlockChildren","align","alreadyHasAlign","test","parseHTMLToDocument","template","root","blockRules","childNodes","Node","ELEMENT_NODE","tagName","parseListElement","match","matchBlockParseRule","inlineContent","parseElementToInlineContent","extractAlignment","TEXT_NODE","textContent","listEl","li","checkbox","isChecklist","checked","hasAttribute","resolvedType","liChild","liChildTag","skipNestedLists","walkElement","currentMarks","markRules","inlineRules","getAttrs","createInlineNode","matchedTypes","m","markType","textAlign","InputHandler","handleBeforeInput","onBeforeInput","handleCompositionStart","onCompositionStart","handleCompositionEnd","onCompositionEnd","inputType","data","insertHardBreakCommand","findWordBoundaryBackward","findWordBoundaryForward","checkInputRules","_e","composedText","textBefore","exec","segmentsToText","reduce","acc","s","segmentsLength","gapInsertIndex","insertIndex","side","pasteBlocksAtGap","gap","builder","lastBlockId","insertAt","lastTextLen","newId","generateBlockId","textNodes","BLOCK_ELEMENTS","INLINE_ELEMENTS","HTMLParser","blockParseRules","markParseRules","parseContainer","resolveBlockType","pendingSegments","isBlockElement","flushPendingSegments","parseBlockElement","containsBlockDescendants","parseContainerWithMarks","marksFromElement","parseInlineNode","headingMatch","level","blockType","ensureSegments","parseInlineChildren","parseBlockWithLineBreaks","parseBlockquote","parseList","parseListItem","parsePreContent","parseTableAsParagraphs","blockMatch","matchBlockRule","hasCheckbox","resolvedListType","isCheckboxChecked","inlineSegments","nestedLists","normalizeSegments","nestedType","parentMarks","resolveMarks","childMarks","mergeMarks","upperTag","fw","fontWeight","numeric","parseInt","isNaN","href","additional","rawMarks","isMarkAllowed","isNodeTypeAllowed","segment","input","inheritedMarks","innerBlocks","prependMarks","normalized","FONT_SIZE_MAP","hasFontSizeInStyle","moveChildren","unwrap","parentNode","sanitizeAttrs","specAttrs","hasKeys","raw","PasteHandler","handlePaste","onPaste","blockJson","getData","handleBlockPaste","handleFilePaste","handleRichPaste","richJson","extractRichData","handleRichPasteFromJson","preTemplate","fonts","font","color","face","existingStyle","span","styles","mapped","replaceChild","normalizedHTML","sanitized","schemaFromRegistry","parser","totalLength","insertText","addDeleteSelectionSteps","insertBlockId","insertOffset","resolveInsertPoint","setBlockType","blockIdx","firstSlice","lastSlice","middleSlices","firstLen","splitOffset","tailBlockId","splitBlock","mid","lastLen","parse","extractTextFromHTML","parsed","typeName","anchorBlockId","cellId","findTableCellAncestor","cellPath","isArray","insertRichBlocksIntoCell","insertRichBlocksAtRoot","anchorBlock","anchorIndex","isAnchorEmpty","validateRichBlockData","removeNode","files","file","getAsFile","handled","matchFileHandlers","Promise","richEl","reconcile","oldBlocks","newBlocks","compositionBlockId","wrappers","oldBlockMap","HTMLElement","wrappedChild","toBlockId","newBlockIds","removeBlockElement","nv","oldBlockById","previousSibling","selectedNodeId","previousSelectedNodeId","existingEl","oldBlock","oldDecos","oldDecorations","find","newDecos","blockChanged","existingNv","update","contentDOM","updatedInlineDecos","findInline","renderBlockContent","dom","newEl","renderBlock","replaceBlockElement","insertAfterPreviousSibling","selectNode","deselectNode","wrapBlocks","oldAttrs","newAttrs","oldKeys","newKeys","oldChild","newChild","inlineAttrsEqual","oldArr","newArr","decorationArraysEqual","inlineDecos","getNodeViewFactory","nvSpec","isVoid","selectable","contentDOMChildren","getContentDOM","childEl","applyNodeDecorations","p","globalOffset","renderInlineNode","textFrom","textTo","splitSet","deco","dFrom","dTo","splits","localFrom","localTo","activeDecos","preserveSpaces","j","createDecorationElement","renderTextNode","lastChild","aKeys","bKeys","nodeName","class","entries","nodeDecos","currentSpec","currentIds","nodeSpec","wSpec","blockIds","firstEl","parentElement","oldEl","nextSibling","EditorView","contentElement","inputHandler","keyboardHandler","pasteHandler","clipboardHandler","history","stateChangeCallbacks","handleSelectionChange","handleMousedown","handleDragover","handleDrop","handleCompositionStartForWrapper","handleCompositionEndForWrapper","isUpdating","pendingNodeSelectionClear","pendingGapCursorClear","getDecorations","navigationKeymap","cursorWrapper","goalColumn","preserveGoalColumn","maxHistoryDepth","syncSelectionFromDOM","onSelectionChange","onMousedown","onDragover","onDrop","reconcileOptions","syncSelectionToDOM","registerNavigationKeymaps","pushHistory","newDecorations","activeBlockId","cb","applyUpdate","readSelectionFromDOM","setStoredMarks","nearestBlockEl","contains","handleClickBelowContent","buildBlockPath","lastBlockEl","lastRect","getBoundingClientRect","clientY","bottom","lastBlock","leafBlockEl","unshift","dataTransfer","position","getPositionFromPoint","clientX","x","y","domPoint","domPositionFromPoint","domPositionToState","activeEl","activeElement","oldSelection","directions","ArrowLeft","ArrowRight","ArrowUp","ArrowDown","dir","handleNavigationArrow","direction","handleHorizontalArrow","handleVerticalArrow","logicalDirection","resolveLogicalHorizontalDirection","inlineSkipTr","skipInlineNode","validateSelectionAfterInlineSkip","endOfTextblock","navigateAcrossBlocks","visual","blockEl","getTextDirection","ownerDocument","caretRect","getCaretRectFromSelection","left","navigateVerticalWithGoalColumn","EDITOR_CSS","cachedStyleSheet","EditorThemeController","themeStyleSheet","systemThemeQuery","systemThemeHandler","pluginSheets","cleanupSystemThemeListener","setupSystemThemeListener","resolved","getSystemTheme","setThemeStyleSheet","sheets","refreshAdoptedStyleSheets","window","matchMedia","matches","PaperLayoutController","viewport","surface","viewportObserver","surfaceObserver","currentSize","currentPaperWidthPx","currentPaperHeightPx","currentScale","compensationFrameId","disable","enable","updateSurfaceDimensions","getPaperSize","bottomContainer","ResizeObserver","onViewportResize","contentRect","width","observe","onSurfaceResize","height","cancelAnimationFrame","disconnect","minHeight","viewportWidth","availableWidth","scale","scheduleHeightCompensation","_height","requestAnimationFrame","updateHeightCompensation","marginBottom","surfaceHeight","scrollHeight","compensation","NotectlEditor","view","pluginManager","editorWrapper","topPluginContainer","bottomPluginContainer","announcer","eventListeners","readyPromiseResolve","readyPromise","preInitPlugins","themeController","paperLayout","super","resolve","attachShadow","mode","observedAttributes","connectedCallback","disconnectedCallback","setTimeout","isConnected","_oldValue","newValue","isReadonly","contentEditable","setReadOnly","configure","placeholder","localeService","LocaleService","LocaleServiceKey","processToolbarConfig","register","ensureTextFormattingPlugin","ensureCaretNavigationPlugin","ensureGapCursorPlugin","contentEl","pluginMgr","topContainer","create","collectDecorations","updateEmptyState","setPluginStyleSheets","onEvent","event","autofocus","getJSON","replaceState","pretty","formatHTML","setJSON","getText","toggleBold","toggleItalic","toggleUnderline","can","canExecuteCommand","configurePlugin","isReadonlyBypassed","dispatchWithMiddleware","finalTr","applyPaperSize","getTheme","pluginTeardown","toolbarCfg","isShorthand","pluginGroups","overflow","pluginIds","layoutConfig","ToolbarPlugin","features","bold","italic","underline","TextFormattingPlugin","CaretNavigationPlugin","GapCursorPlugin","notifyStateChange","announcement","buildAnnouncement","toggle","async","createEditor","editor","createMinimalPreset","FontPlugin","STARTER_FONTS","createFullPreset","FontSizePlugin","fontSize","textFormatting","StrikethroughPlugin","strikethrough","SuperSubPlugin","superSub","TextColorPlugin","textColor","HighlightPlugin","highlight","HeadingPlugin","heading","BlockquotePlugin","blockquote","CodeBlockPlugin","AlignmentPlugin","alignment","ListPlugin","list","LinkPlugin","link","TablePlugin","table","HorizontalRulePlugin","horizontalRule","ImagePlugin","image","HardBreakPlugin","customElements","define"],"mappings":"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"}
1
+ {"version":3,"file":"notectl-core.mjs","sources":["../src/model/SchemaRegistry.ts","../src/model/ContentModel.ts","../src/model/BuiltinSpecs.ts","../src/state/BlockTreeOps.ts","../src/state/InlineContentOps.ts","../src/state/StepApplication.ts","../src/state/Transaction.ts","../src/state/EditorState.ts","../src/state/ReadonlyGuard.ts","../src/state/History.ts","../src/commands/DeleteCommands.ts","../src/input/KeyboardHandler.ts","../src/editor/MarkSerializer.ts","../src/input/InternalClipboard.ts","../src/input/ClipboardHandler.ts","../src/input/CompositionTracker.ts","../src/input/KeymapRegistry.ts","../src/input/InputRuleRegistry.ts","../src/input/FileHandlerRegistry.ts","../src/view/NodeViewRegistry.ts","../src/plugins/toolbar/ToolbarRegistry.ts","../src/plugins/heading/BlockTypePickerRegistry.ts","../src/view/MarkRendering.ts","../src/view/CursorWrapper.ts","../src/plugins/shared/PopupKeyboardPatterns.ts","../src/plugins/EventBus.ts","../src/plugins/PluginManager.ts","../src/plugins/print/PrintLocale.ts","../src/plugins/print/PrintContentPreparer.ts","../src/editor/PaperSize.ts","../src/plugins/print/PrintTypes.ts","../src/plugins/print/PrintPlugin.ts","../src/plugins/print/PrintServiceImpl.ts","../src/plugins/print/PrintStyleCollector.ts","../src/editor/theme/ThemeTokens.ts","../src/editor/theme/ThemeEngine.ts","../src/i18n/Locale.ts","../src/editor/CSSClassCollector.ts","../src/editor/DocumentSerializer.ts","../src/editor/DocumentParser.ts","../src/editor/ContentStyleInjector.ts","../src/input/InputHandler.ts","../src/model/ContentSlice.ts","../src/commands/PasteCommand.ts","../src/model/HTMLParser.ts","../src/input/LegacyHTMLNormalizer.ts","../src/input/PasteHandler.ts","../src/view/Reconciler.ts","../src/view/EditorView.ts","../src/editor/styles/base.ts","../src/editor/styles.ts","../src/editor/styles/reduced-motion.ts","../src/editor/styles/paper.ts","../src/editor/EditorThemeController.ts","../src/editor/PaperLayoutController.ts","../src/editor/NotectlEditor.ts","../src/editor/EditorDOM.ts","../src/presets/MinimalPreset.ts","../src/presets/FullPreset.ts"],"sourcesContent":["/**\n * SchemaRegistry: central registry for node specs, mark specs,\n * and inline node specs registered by plugins.\n *\n * Model-only — no imports from input/, plugins/, or view/ layers.\n */\n\nimport type { InlineNodeSpec } from './InlineNodeSpec.js';\nimport type { MarkSpec } from './MarkSpec.js';\nimport type { NodeSpec } from './NodeSpec.js';\nimport type { ParseRule } from './ParseRule.js';\n\nexport class SchemaRegistry {\n\tprivate readonly _nodeSpecs = new Map<string, NodeSpec>();\n\tprivate readonly _markSpecs = new Map<string, MarkSpec>();\n\tprivate readonly _inlineNodeSpecs = new Map<string, InlineNodeSpec>();\n\n\t// --- NodeSpec ---\n\n\tregisterNodeSpec<T extends string>(spec: NodeSpec<T>): void {\n\t\tif (this._nodeSpecs.has(spec.type)) {\n\t\t\tthrow new Error(`NodeSpec for type \"${spec.type}\" is already registered.`);\n\t\t}\n\t\tthis._nodeSpecs.set(spec.type, spec);\n\t}\n\n\tgetNodeSpec(type: string): NodeSpec | undefined {\n\t\treturn this._nodeSpecs.get(type);\n\t}\n\n\tremoveNodeSpec(type: string): void {\n\t\tthis._nodeSpecs.delete(type);\n\t}\n\n\tgetNodeTypes(): string[] {\n\t\treturn [...this._nodeSpecs.keys()];\n\t}\n\n\t// --- MarkSpec ---\n\n\tregisterMarkSpec<T extends string>(spec: MarkSpec<T>): void {\n\t\tif (this._markSpecs.has(spec.type)) {\n\t\t\tthrow new Error(`MarkSpec for type \"${spec.type}\" is already registered.`);\n\t\t}\n\t\tthis._markSpecs.set(spec.type, spec);\n\t}\n\n\tgetMarkSpec(type: string): MarkSpec | undefined {\n\t\treturn this._markSpecs.get(type);\n\t}\n\n\tremoveMarkSpec(type: string): void {\n\t\tthis._markSpecs.delete(type);\n\t}\n\n\tgetMarkTypes(): string[] {\n\t\treturn [...this._markSpecs.keys()];\n\t}\n\n\t// --- InlineNodeSpec ---\n\n\tregisterInlineNodeSpec<T extends string>(spec: InlineNodeSpec<T>): void {\n\t\tif (this._inlineNodeSpecs.has(spec.type)) {\n\t\t\tthrow new Error(`InlineNodeSpec for type \"${spec.type}\" is already registered.`);\n\t\t}\n\t\tthis._inlineNodeSpecs.set(spec.type, spec);\n\t}\n\n\tgetInlineNodeSpec(type: string): InlineNodeSpec | undefined {\n\t\treturn this._inlineNodeSpecs.get(type);\n\t}\n\n\tremoveInlineNodeSpec(type: string): void {\n\t\tthis._inlineNodeSpecs.delete(type);\n\t}\n\n\tgetInlineNodeTypes(): string[] {\n\t\treturn [...this._inlineNodeSpecs.keys()];\n\t}\n\n\t// --- Parse Rules & Sanitize Config ---\n\n\t/** Returns all NodeSpec parseHTML rules, sorted by priority descending. */\n\tgetBlockParseRules(): readonly { readonly rule: ParseRule; readonly type: string }[] {\n\t\tconst results: { readonly rule: ParseRule; readonly type: string }[] = [];\n\t\tfor (const [type, spec] of this._nodeSpecs) {\n\t\t\tif (spec.parseHTML) {\n\t\t\t\tfor (const rule of spec.parseHTML) {\n\t\t\t\t\tresults.push({ rule, type });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results.sort((a, b) => (b.rule.priority ?? 50) - (a.rule.priority ?? 50));\n\t}\n\n\t/** Returns all InlineNodeSpec parseHTML rules, sorted by priority descending. */\n\tgetInlineParseRules(): readonly { readonly rule: ParseRule; readonly type: string }[] {\n\t\tconst results: { readonly rule: ParseRule; readonly type: string }[] = [];\n\t\tfor (const [type, spec] of this._inlineNodeSpecs) {\n\t\t\tif (spec.parseHTML) {\n\t\t\t\tfor (const rule of spec.parseHTML) {\n\t\t\t\t\tresults.push({ rule, type });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results.sort((a, b) => (b.rule.priority ?? 50) - (a.rule.priority ?? 50));\n\t}\n\n\t/** Returns all MarkSpec parseHTML rules, sorted by priority descending. */\n\tgetMarkParseRules(): readonly { readonly rule: ParseRule; readonly type: string }[] {\n\t\tconst results: { readonly rule: ParseRule; readonly type: string }[] = [];\n\t\tfor (const [type, spec] of this._markSpecs) {\n\t\t\tif (spec.parseHTML) {\n\t\t\t\tfor (const rule of spec.parseHTML) {\n\t\t\t\t\tresults.push({ rule, type });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results.sort((a, b) => (b.rule.priority ?? 50) - (a.rule.priority ?? 50));\n\t}\n\n\t/** Returns all allowed HTML tags from base defaults + all spec sanitize configs. */\n\tgetAllowedTags(): string[] {\n\t\tconst tags = new Set<string>(['p', 'br', 'div', 'span']);\n\t\tfor (const spec of this._nodeSpecs.values()) {\n\t\t\tif (spec.sanitize?.tags) {\n\t\t\t\tfor (const tag of spec.sanitize.tags) tags.add(tag);\n\t\t\t}\n\t\t}\n\t\tfor (const spec of this._inlineNodeSpecs.values()) {\n\t\t\tif (spec.sanitize?.tags) {\n\t\t\t\tfor (const tag of spec.sanitize.tags) tags.add(tag);\n\t\t\t}\n\t\t}\n\t\tfor (const spec of this._markSpecs.values()) {\n\t\t\tif (spec.sanitize?.tags) {\n\t\t\t\tfor (const tag of spec.sanitize.tags) tags.add(tag);\n\t\t\t}\n\t\t}\n\t\treturn [...tags];\n\t}\n\n\t/** Returns all allowed HTML attributes from base defaults + all spec sanitize configs. */\n\tgetAllowedAttrs(): string[] {\n\t\tconst attrs = new Set<string>(['style']);\n\t\tfor (const spec of this._nodeSpecs.values()) {\n\t\t\tif (spec.sanitize?.attrs) {\n\t\t\t\tfor (const attr of spec.sanitize.attrs) attrs.add(attr);\n\t\t\t}\n\t\t}\n\t\tfor (const spec of this._inlineNodeSpecs.values()) {\n\t\t\tif (spec.sanitize?.attrs) {\n\t\t\t\tfor (const attr of spec.sanitize.attrs) attrs.add(attr);\n\t\t\t}\n\t\t}\n\t\tfor (const spec of this._markSpecs.values()) {\n\t\t\tif (spec.sanitize?.attrs) {\n\t\t\t\tfor (const attr of spec.sanitize.attrs) attrs.add(attr);\n\t\t\t}\n\t\t}\n\t\treturn [...attrs];\n\t}\n\n\t// --- Bulk ---\n\n\tclear(): void {\n\t\tthis._nodeSpecs.clear();\n\t\tthis._markSpecs.clear();\n\t\tthis._inlineNodeSpecs.clear();\n\t}\n}\n","/**\n * Content model validation for nested document structures.\n * Validates whether a parent node type can contain given child types.\n */\n\nimport type { SchemaRegistry } from './SchemaRegistry.js';\n\n/**\n * Checks if a parent node type can contain a child node type,\n * using the content rules and group system from NodeSpec.\n */\nexport function canContain(\n\tregistry: SchemaRegistry,\n\tparentType: string,\n\tchildType: string,\n): boolean {\n\tconst parentSpec = registry.getNodeSpec(parentType);\n\tif (!parentSpec?.content) return true; // No content rule = anything allowed\n\n\tconst childSpec = registry.getNodeSpec(childType);\n\tconst childGroup = childSpec?.group;\n\n\tfor (const allowed of parentSpec.content.allow) {\n\t\tif (allowed === childType) return true;\n\t\tif (allowed === 'text') continue; // 'text' refers to TextNodes, not BlockNodes\n\t\tif (childGroup && allowed === childGroup) return true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Validates whether the given children types are valid for a parent node type.\n * Checks allow list, min/max constraints.\n */\nexport function validateContent(\n\tregistry: SchemaRegistry,\n\tparentType: string,\n\tchildTypes: readonly string[],\n): boolean {\n\tconst parentSpec = registry.getNodeSpec(parentType);\n\tif (!parentSpec?.content) return true;\n\n\tconst { min = 0, max = Number.POSITIVE_INFINITY } = parentSpec.content;\n\n\t// Check count constraints (only for block children, not text)\n\tconst blockChildTypes = childTypes.filter((t) => t !== 'text');\n\tif (blockChildTypes.length < min || blockChildTypes.length > max) return false;\n\n\t// Check each child is allowed\n\tfor (const childType of blockChildTypes) {\n\t\tif (!canContain(registry, parentType, childType)) return false;\n\t}\n\n\treturn true;\n}\n","/**\n * Registers built-in node specs on a SchemaRegistry.\n * Called during editor initialization before plugins.\n *\n * Note: Mark specs (bold, italic, underline) are registered by the\n * TextFormattingPlugin, not here. Only structural node types belong here.\n */\n\nimport { createBlockElement } from './NodeSpec.js';\nimport type { SchemaRegistry } from './SchemaRegistry.js';\n\n/** Registers the built-in paragraph NodeSpec. */\nexport function registerBuiltinSpecs(registry: SchemaRegistry): void {\n\tregistry.registerNodeSpec({\n\t\ttype: 'paragraph',\n\t\tgroup: 'block',\n\t\tcontent: { allow: ['text'] },\n\t\ttoDOM(node) {\n\t\t\treturn createBlockElement('p', node.id);\n\t\t},\n\t\ttoHTML(_node, content) {\n\t\t\treturn `<p>${content || '<br>'}</p>`;\n\t\t},\n\t\tparseHTML: [{ tag: 'p' }, { tag: 'div', priority: 10 }],\n\t\tsanitize: { tags: ['p'] },\n\t});\n}\n","/**\n * Pure functions for recursive block-tree traversal and transformation.\n * Extracted from StepApplication.ts to keep files under ~500 lines.\n */\n\nimport { type BlockNode, type ChildNode, type Document, isBlockNode } from '../model/Document.js';\n\n/** Finds a block by ID anywhere in the tree and applies a transform. */\nexport function mapBlock(\n\tdoc: Document,\n\tblockId: string,\n\tfn: (block: BlockNode) => BlockNode,\n): Document {\n\treturn {\n\t\tchildren: mapBlockInChildren(doc.children, blockId, fn) as BlockNode[],\n\t};\n}\n\n/** Recursively maps over children to find and transform a block by ID. */\nexport function mapBlockInChildren(\n\tchildren: readonly ChildNode[],\n\tblockId: string,\n\tfn: (block: BlockNode) => BlockNode,\n): ChildNode[] {\n\treturn children.map((child) => {\n\t\tif (!isBlockNode(child)) return child;\n\t\tif (child.id === blockId) return fn(child);\n\t\t// Recurse into block children\n\t\tconst mappedChildren: ChildNode[] = mapBlockInChildren(child.children, blockId, fn);\n\t\tif (mappedChildren === child.children) return child;\n\t\treturn { ...child, children: mappedChildren };\n\t});\n}\n\n/**\n * Maps a node at the given path, replacing it with the result of fn.\n * Navigates down the path immutably, creating new parent nodes as needed.\n */\nexport function mapNodeByPath(\n\tdoc: Document,\n\tpath: readonly string[],\n\tfn: (node: BlockNode) => BlockNode,\n): Document {\n\tif (path.length === 0) return doc;\n\n\tconst rootId: string | undefined = path[0];\n\tif (!rootId) return doc;\n\treturn {\n\t\tchildren: doc.children.map((child) => {\n\t\t\tif (!isBlockNode(child) || child.id !== rootId) return child;\n\t\t\tif (path.length === 1) return fn(child);\n\t\t\treturn mapNodeByPathRecursive(child, path, 1, fn);\n\t\t}),\n\t};\n}\n\n/** Recursive helper for mapNodeByPath — walks one level deeper. */\nexport function mapNodeByPathRecursive(\n\tnode: BlockNode,\n\tpath: readonly string[],\n\tdepth: number,\n\tfn: (node: BlockNode) => BlockNode,\n): BlockNode {\n\tconst targetId: string | undefined = path[depth];\n\tif (!targetId) return node;\n\tconst newChildren: ChildNode[] = node.children.map((child) => {\n\t\tif (!isBlockNode(child) || child.id !== targetId) return child;\n\t\tif (depth === path.length - 1) return fn(child);\n\t\treturn mapNodeByPathRecursive(child, path, depth + 1, fn);\n\t});\n\treturn { ...node, children: newChildren };\n}\n\n/**\n * Searches children for a level where `predicate` matches,\n * then applies `transform` at that level.\n * Recurses into nested BlockNodes if not found at the current level.\n *\n * Returns `null` if no matching level was found.\n */\nexport function findAndTransformChildren(\n\tchildren: readonly ChildNode[],\n\tpredicate: (children: readonly ChildNode[]) => boolean,\n\ttransform: (children: readonly ChildNode[]) => readonly ChildNode[],\n): readonly ChildNode[] | null {\n\tif (predicate(children)) {\n\t\treturn transform(children);\n\t}\n\n\tlet changed = false;\n\tconst newChildren: ChildNode[] = children.map((child) => {\n\t\tif (!isBlockNode(child)) return child;\n\t\tconst result: readonly ChildNode[] | null = findAndTransformChildren(\n\t\t\tchild.children,\n\t\t\tpredicate,\n\t\t\ttransform,\n\t\t);\n\t\tif (result) {\n\t\t\tchanged = true;\n\t\t\treturn { ...child, children: result };\n\t\t}\n\t\treturn child;\n\t});\n\n\treturn changed ? newChildren : null;\n}\n","/**\n * Pure functions for manipulating inline content (TextNode / InlineNode arrays).\n * Extracted from StepApplication.ts to keep files under ~500 lines.\n */\n\nimport {\n\ttype ChildNode,\n\ttype InlineNode,\n\ttype Mark,\n\ttype TextNode,\n\ttype TextSegment,\n\taddMarkToSet,\n\tcreateTextNode,\n\tisInlineNode,\n\tisTextNode,\n\tremoveMarkFromSet,\n} from '../model/Document.js';\n\n/**\n * Inserts text into mixed inline content at the given offset.\n * Handles both TextNode and InlineNode children.\n */\nexport function insertTextIntoInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n\ttext: string,\n\tmarks: readonly Mark[],\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\tlet inserted = false;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (!inserted && offset === pos) {\n\t\t\t\tresult.push(createTextNode(text, marks));\n\t\t\t\tinserted = true;\n\t\t\t}\n\t\t\tresult.push(node);\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (!inserted && offset >= pos && offset <= nodeEnd) {\n\t\t\tconst localOffset: number = offset - pos;\n\t\t\tconst before: string = node.text.slice(0, localOffset);\n\t\t\tconst after: string = node.text.slice(localOffset);\n\n\t\t\tif (before) result.push(createTextNode(before, node.marks));\n\t\t\tresult.push(createTextNode(text, marks));\n\t\t\tif (after) result.push(createTextNode(after, node.marks));\n\t\t\tinserted = true;\n\t\t} else {\n\t\t\tresult.push(node);\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\tif (!inserted) {\n\t\tresult.push(createTextNode(text, marks));\n\t}\n\n\treturn result;\n}\n\n/**\n * Inserts segments into mixed inline content at the given offset.\n */\nexport function insertSegmentsIntoInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n\tsegments: readonly TextSegment[],\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\tlet inserted = false;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (!inserted && offset === pos) {\n\t\t\t\tfor (const seg of segments) {\n\t\t\t\t\tresult.push(createTextNode(seg.text, seg.marks));\n\t\t\t\t}\n\t\t\t\tinserted = true;\n\t\t\t}\n\t\t\tresult.push(node);\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (!inserted && offset >= pos && offset <= nodeEnd) {\n\t\t\tconst localOffset: number = offset - pos;\n\t\t\tconst before: string = node.text.slice(0, localOffset);\n\t\t\tconst after: string = node.text.slice(localOffset);\n\n\t\t\tif (before) result.push(createTextNode(before, node.marks));\n\t\t\tfor (const seg of segments) {\n\t\t\t\tresult.push(createTextNode(seg.text, seg.marks));\n\t\t\t}\n\t\t\tif (after) result.push(createTextNode(after, node.marks));\n\t\t\tinserted = true;\n\t\t} else {\n\t\t\tresult.push(node);\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\tif (!inserted) {\n\t\tfor (const seg of segments) {\n\t\t\tresult.push(createTextNode(seg.text, seg.marks));\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Deletes content from mixed inline content in the given range.\n * Removes InlineNodes that fall within the range.\n */\nexport function deleteFromInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\tfrom: number,\n\tto: number,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tconst nodeEnd: number = pos + 1;\n\t\t\t// Keep if outside the delete range\n\t\t\tif (nodeEnd <= from || pos >= to) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t\tpos = nodeEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (nodeEnd <= from || pos >= to) {\n\t\t\tresult.push(node);\n\t\t} else {\n\t\t\tconst deleteFrom: number = Math.max(0, from - pos);\n\t\t\tconst deleteTo: number = Math.min(node.text.length, to - pos);\n\t\t\tconst remaining: string = node.text.slice(0, deleteFrom) + node.text.slice(deleteTo);\n\t\t\tif (remaining.length > 0) {\n\t\t\t\tresult.push(createTextNode(remaining, node.marks));\n\t\t\t}\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\treturn result;\n}\n\n/**\n * Slices mixed inline content to the given range.\n * InlineNodes are preserved as atoms (included if within range).\n */\nexport function sliceInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\tfrom: number,\n\tto: number,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tconst nodeEnd: number = pos + 1;\n\t\t\tif (nodeEnd > from && pos < to) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t\tpos = nodeEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (nodeEnd <= from || pos >= to) {\n\t\t\t// Outside the slice range\n\t\t} else {\n\t\t\tconst sliceFrom: number = Math.max(0, from - pos);\n\t\t\tconst sliceTo: number = Math.min(node.text.length, to - pos);\n\t\t\tconst text: string = node.text.slice(sliceFrom, sliceTo);\n\t\t\tif (text.length > 0) {\n\t\t\t\tresult.push(createTextNode(text, node.marks));\n\t\t\t}\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\tif (result.length === 0) {\n\t\tresult.push(createTextNode(''));\n\t}\n\n\treturn result;\n}\n\n/**\n * Applies or removes a mark from mixed inline content in the given range.\n * InlineNodes are passed through unchanged (marks only apply to text).\n */\nexport function applyMarkToInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n\tfrom: number,\n\tto: number,\n\tmark: Mark,\n\tadd: boolean,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tresult.push(node);\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (nodeEnd <= from || pos >= to) {\n\t\t\tresult.push(node);\n\t\t} else if (pos >= from && nodeEnd <= to) {\n\t\t\tconst newMarks: readonly Mark[] = add\n\t\t\t\t? addMarkToSet(node.marks, mark)\n\t\t\t\t: removeMarkFromSet(node.marks, mark.type);\n\t\t\tresult.push(createTextNode(node.text, newMarks));\n\t\t} else {\n\t\t\tconst overlapStart: number = Math.max(0, from - pos);\n\t\t\tconst overlapEnd: number = Math.min(node.text.length, to - pos);\n\n\t\t\tconst beforeText: string = node.text.slice(0, overlapStart);\n\t\t\tconst insideText: string = node.text.slice(overlapStart, overlapEnd);\n\t\t\tconst afterText: string = node.text.slice(overlapEnd);\n\n\t\t\tif (beforeText) result.push(createTextNode(beforeText, node.marks));\n\t\t\tif (insideText) {\n\t\t\t\tconst newMarks: readonly Mark[] = add\n\t\t\t\t\t? addMarkToSet(node.marks, mark)\n\t\t\t\t\t: removeMarkFromSet(node.marks, mark.type);\n\t\t\t\tresult.push(createTextNode(insideText, newMarks));\n\t\t\t}\n\t\t\tif (afterText) result.push(createTextNode(afterText, node.marks));\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\treturn result;\n}\n\n/** Inserts an InlineNode at the given offset in mixed inline content. */\nexport function insertInlineNodeAtOffset(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n\tinlineNode: InlineNode,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\tlet inserted = false;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (!inserted && offset === pos) {\n\t\t\t\tresult.push(inlineNode);\n\t\t\t\tinserted = true;\n\t\t\t}\n\t\t\tresult.push(node);\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst nodeEnd: number = pos + node.text.length;\n\n\t\tif (!inserted && offset >= pos && offset <= nodeEnd) {\n\t\t\tconst localOffset: number = offset - pos;\n\t\t\tconst before: string = node.text.slice(0, localOffset);\n\t\t\tconst after: string = node.text.slice(localOffset);\n\n\t\t\tif (before) result.push(createTextNode(before, node.marks));\n\t\t\tresult.push(inlineNode);\n\t\t\tif (after) result.push(createTextNode(after, node.marks));\n\t\t\tinserted = true;\n\t\t} else {\n\t\t\tresult.push(node);\n\t\t}\n\n\t\tpos = nodeEnd;\n\t}\n\n\tif (!inserted) {\n\t\tresult.push(inlineNode);\n\t}\n\n\treturn result;\n}\n\n/** Removes the InlineNode at the given offset from mixed inline content. */\nexport function removeInlineNodeAtOffset(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (pos !== offset) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tresult.push(node);\n\t\tpos += node.text.length;\n\t}\n\n\treturn result;\n}\n\n/** Replaces the attrs of an InlineNode at the given offset. */\nexport function setInlineNodeAttrsAtOffset(\n\tnodes: readonly (TextNode | InlineNode)[],\n\toffset: number,\n\tattrs: Readonly<Record<string, string | number | boolean>>,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tlet pos = 0;\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tif (pos === offset) {\n\t\t\t\tresult.push({ ...node, attrs });\n\t\t\t} else {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tresult.push(node);\n\t\tpos += node.text.length;\n\t}\n\n\treturn result;\n}\n\n/**\n * Replaces the inline content children of a ChildNode array,\n * preserving any BlockNode children in their original positions.\n */\nexport function replaceInlineChildren(\n\toriginal: readonly ChildNode[],\n\tnewInlineChildren: readonly (TextNode | InlineNode)[],\n): readonly ChildNode[] {\n\t// Fast path: if no block children exist, just return new inline nodes\n\tif (original.every((c) => isTextNode(c) || isInlineNode(c))) {\n\t\treturn newInlineChildren;\n\t}\n\t// Mixed: put inline nodes first, then block nodes (preserves structure)\n\tconst blockChildren: ChildNode[] = original.filter((c) => !isTextNode(c) && !isInlineNode(c));\n\treturn [...newInlineChildren, ...blockChildren];\n}\n","/**\n * Pure step-application functions operating on Document.\n * Extracted from EditorState for reuse in TransactionBuilder.\n */\n\nimport {\n\ttype BlockNode,\n\ttype ChildNode,\n\ttype Document,\n\ttype InlineNode,\n\ttype TextNode,\n\tcreateBlockNode,\n\tgetBlockLength,\n\tgetInlineChildren,\n\tisBlockNode,\n\tnormalizeInlineContent,\n} from '../model/Document.js';\nimport { findAndTransformChildren, mapBlock, mapNodeByPath } from './BlockTreeOps.js';\nimport {\n\tapplyMarkToInlineContent,\n\tdeleteFromInlineContent,\n\tinsertInlineNodeAtOffset,\n\tinsertSegmentsIntoInlineContent,\n\tinsertTextIntoInlineContent,\n\tremoveInlineNodeAtOffset,\n\treplaceInlineChildren,\n\tsetInlineNodeAttrsAtOffset,\n\tsliceInlineContent,\n} from './InlineContentOps.js';\nimport type {\n\tAddMarkStep,\n\tDeleteTextStep,\n\tInsertInlineNodeStep,\n\tInsertNodeStep,\n\tInsertTextStep,\n\tMergeBlocksStep,\n\tRemoveInlineNodeStep,\n\tRemoveMarkStep,\n\tRemoveNodeStep,\n\tSetBlockTypeStep,\n\tSetInlineNodeAttrStep,\n\tSetNodeAttrStep,\n\tSplitBlockStep,\n\tStep,\n} from './Transaction.js';\n\n/** Applies a single step to a document and returns the new document. */\nexport function applyStep(doc: Document, step: Step): Document {\n\tswitch (step.type) {\n\t\tcase 'insertText':\n\t\t\treturn applyInsertText(doc, step);\n\t\tcase 'deleteText':\n\t\t\treturn applyDeleteText(doc, step);\n\t\tcase 'splitBlock':\n\t\t\treturn applySplitBlock(doc, step);\n\t\tcase 'mergeBlocks':\n\t\t\treturn applyMergeBlocks(doc, step);\n\t\tcase 'addMark':\n\t\t\treturn applyAddMark(doc, step);\n\t\tcase 'removeMark':\n\t\t\treturn applyRemoveMark(doc, step);\n\t\tcase 'setStoredMarks':\n\t\t\treturn doc; // Stored marks are handled at the state level, not document\n\t\tcase 'setBlockType':\n\t\t\treturn applySetBlockType(doc, step);\n\t\tcase 'insertNode':\n\t\t\treturn applyInsertNode(doc, step);\n\t\tcase 'removeNode':\n\t\t\treturn applyRemoveNode(doc, step);\n\t\tcase 'setNodeAttr':\n\t\t\treturn applySetNodeAttr(doc, step);\n\t\tcase 'insertInlineNode':\n\t\t\treturn applyInsertInlineNode(doc, step);\n\t\tcase 'removeInlineNode':\n\t\t\treturn applyRemoveInlineNode(doc, step);\n\t\tcase 'setInlineNodeAttr':\n\t\t\treturn applySetInlineNodeAttr(doc, step);\n\t}\n}\n\nfunction applyInsertText(doc: Document, step: InsertTextStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = step.segments\n\t\t\t? insertSegmentsIntoInlineContent(inlineChildren, step.offset, step.segments)\n\t\t\t: insertTextIntoInlineContent(inlineChildren, step.offset, step.text, step.marks);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applyDeleteText(doc: Document, step: DeleteTextStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = deleteFromInlineContent(\n\t\t\tinlineChildren,\n\t\t\tstep.from,\n\t\t\tstep.to,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applySplitBlock(doc: Document, step: SplitBlockStep): Document {\n\tconst splitAtLevel = (children: readonly ChildNode[]): readonly ChildNode[] => {\n\t\tconst blockIndex: number = children.findIndex((c) => isBlockNode(c) && c.id === step.blockId);\n\t\tif (blockIndex === -1) return children;\n\n\t\tconst block: BlockNode = children[blockIndex] as BlockNode;\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst len: number = getBlockLength(block);\n\t\tconst nodesBeforeSplit: (TextNode | InlineNode)[] = sliceInlineContent(\n\t\t\tinlineChildren,\n\t\t\t0,\n\t\t\tstep.offset,\n\t\t);\n\t\tconst nodesAfterSplit: (TextNode | InlineNode)[] = sliceInlineContent(\n\t\t\tinlineChildren,\n\t\t\tstep.offset,\n\t\t\tlen,\n\t\t);\n\n\t\tconst updatedBlock: BlockNode = {\n\t\t\t...block,\n\t\t\tchildren: normalizeInlineContent(nodesBeforeSplit),\n\t\t};\n\t\tconst newBlock: BlockNode = createBlockNode(\n\t\t\tblock.type,\n\t\t\tnormalizeInlineContent(nodesAfterSplit),\n\t\t\tstep.newBlockId,\n\t\t\tblock.attrs,\n\t\t);\n\n\t\tconst result: ChildNode[] = [...children];\n\t\tresult.splice(blockIndex, 1, updatedBlock, newBlock);\n\t\treturn result;\n\t};\n\n\tconst hasTarget = (children: readonly ChildNode[]): boolean =>\n\t\tchildren.some((c) => isBlockNode(c) && c.id === step.blockId);\n\n\tconst transformed: readonly ChildNode[] | null = findAndTransformChildren(\n\t\tdoc.children,\n\t\thasTarget,\n\t\tsplitAtLevel,\n\t);\n\treturn transformed ? { children: transformed as BlockNode[] } : doc;\n}\n\nfunction applyMergeBlocks(doc: Document, step: MergeBlocksStep): Document {\n\tconst mergeAtLevel = (children: readonly ChildNode[]): readonly ChildNode[] => {\n\t\tconst targetIdx: number = children.findIndex(\n\t\t\t(c) => isBlockNode(c) && c.id === step.targetBlockId,\n\t\t);\n\t\tconst sourceIdx: number = children.findIndex(\n\t\t\t(c) => isBlockNode(c) && c.id === step.sourceBlockId,\n\t\t);\n\t\tif (targetIdx === -1 || sourceIdx === -1) return children;\n\n\t\tconst target: BlockNode = children[targetIdx] as BlockNode;\n\t\tconst source: BlockNode = children[sourceIdx] as BlockNode;\n\t\tconst targetInline: readonly (TextNode | InlineNode)[] = getInlineChildren(target);\n\t\tconst sourceInline: readonly (TextNode | InlineNode)[] = getInlineChildren(source);\n\t\tconst mergedChildren: readonly (TextNode | InlineNode)[] = normalizeInlineContent([\n\t\t\t...targetInline,\n\t\t\t...sourceInline,\n\t\t]);\n\t\tconst mergedBlock: BlockNode = { ...target, children: mergedChildren };\n\n\t\tconst filtered: ChildNode[] = children.filter(\n\t\t\t(c) => !isBlockNode(c) || c.id !== step.sourceBlockId,\n\t\t);\n\t\treturn filtered.map((c) => (isBlockNode(c) && c.id === step.targetBlockId ? mergedBlock : c));\n\t};\n\n\tconst hasTargetAndSource = (children: readonly ChildNode[]): boolean =>\n\t\tchildren.some((c) => isBlockNode(c) && c.id === step.targetBlockId) &&\n\t\tchildren.some((c) => isBlockNode(c) && c.id === step.sourceBlockId);\n\n\tconst transformed: readonly ChildNode[] | null = findAndTransformChildren(\n\t\tdoc.children,\n\t\thasTargetAndSource,\n\t\tmergeAtLevel,\n\t);\n\treturn transformed ? { children: transformed as BlockNode[] } : doc;\n}\n\nfunction applyAddMark(doc: Document, step: AddMarkStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = applyMarkToInlineContent(\n\t\t\tinlineChildren,\n\t\t\tstep.from,\n\t\t\tstep.to,\n\t\t\tstep.mark,\n\t\t\ttrue,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applyRemoveMark(doc: Document, step: RemoveMarkStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = applyMarkToInlineContent(\n\t\t\tinlineChildren,\n\t\t\tstep.from,\n\t\t\tstep.to,\n\t\t\tstep.mark,\n\t\t\tfalse,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\n// --- InlineNode Step Application ---\n\nfunction applyInsertInlineNode(doc: Document, step: InsertInlineNodeStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = insertInlineNodeAtOffset(\n\t\t\tinlineChildren,\n\t\t\tstep.offset,\n\t\t\tstep.node,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applyRemoveInlineNode(doc: Document, step: RemoveInlineNodeStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = removeInlineNodeAtOffset(\n\t\t\tinlineChildren,\n\t\t\tstep.offset,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, normalizeInlineContent(newChildren)),\n\t\t};\n\t});\n}\n\nfunction applySetInlineNodeAttr(doc: Document, step: SetInlineNodeAttrStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => {\n\t\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst newChildren: (TextNode | InlineNode)[] = setInlineNodeAttrsAtOffset(\n\t\t\tinlineChildren,\n\t\t\tstep.offset,\n\t\t\tstep.attrs,\n\t\t);\n\t\treturn {\n\t\t\t...block,\n\t\t\tchildren: replaceInlineChildren(block.children, newChildren),\n\t\t};\n\t});\n}\n\nfunction applySetBlockType(doc: Document, step: SetBlockTypeStep): Document {\n\treturn mapBlock(doc, step.blockId, (block) => ({\n\t\t...block,\n\t\ttype: step.nodeType,\n\t\t...(step.attrs ? { attrs: step.attrs } : { attrs: undefined }),\n\t}));\n}\n\n// --- Structural Step Application ---\n\nfunction applyInsertNode(doc: Document, step: InsertNodeStep): Document {\n\tif (step.parentPath.length === 0) {\n\t\t// Insert at document root\n\t\tconst newChildren: BlockNode[] = [...doc.children];\n\t\tnewChildren.splice(step.index, 0, step.node);\n\t\treturn { children: newChildren };\n\t}\n\n\treturn mapNodeByPath(doc, step.parentPath, (parent) => {\n\t\tconst newChildren: ChildNode[] = [...parent.children];\n\t\tnewChildren.splice(step.index, 0, step.node);\n\t\treturn { ...parent, children: newChildren };\n\t});\n}\n\nfunction applyRemoveNode(doc: Document, step: RemoveNodeStep): Document {\n\tif (step.parentPath.length === 0) {\n\t\t// Remove from document root\n\t\tconst newChildren: BlockNode[] = [...doc.children];\n\t\tnewChildren.splice(step.index, 1);\n\t\treturn { children: newChildren };\n\t}\n\n\treturn mapNodeByPath(doc, step.parentPath, (parent) => {\n\t\tconst newChildren: ChildNode[] = [...parent.children];\n\t\tnewChildren.splice(step.index, 1);\n\t\treturn { ...parent, children: newChildren };\n\t});\n}\n\nfunction applySetNodeAttr(doc: Document, step: SetNodeAttrStep): Document {\n\tconst nodeId: string | undefined = step.path[step.path.length - 1];\n\tif (!nodeId) return doc;\n\n\treturn mapBlock(doc, nodeId, (block) => ({\n\t\t...block,\n\t\tattrs: step.attrs,\n\t}));\n}\n","/**\n * Transaction system for the Notectl editor.\n * Transactions describe atomic, invertible state changes.\n */\n\nimport type {\n\tBlockAttrs,\n\tBlockNode,\n\tDocument,\n\tInlineNode,\n\tMark,\n\tTextSegment,\n} from '../model/Document.js';\nimport {\n\tgetBlockLength,\n\tgetBlockMarksAtOffset,\n\tgetBlockSegmentsInRange,\n\tgetBlockText,\n\tgetContentAtOffset,\n\tgetInlineChildren,\n\tisBlockNode,\n\tisInlineNode,\n} from '../model/Document.js';\nimport { findNode, resolveNodeByPath } from '../model/NodeResolver.js';\nimport type { EditorSelection } from '../model/Selection.js';\nimport { createNodeSelection } from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport { applyStep } from './StepApplication.js';\n\n// --- Step Types ---\n\nexport interface InsertTextStep {\n\treadonly type: 'insertText';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly text: string;\n\treadonly marks: readonly Mark[];\n\treadonly segments?: readonly TextSegment[];\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface DeleteTextStep {\n\treadonly type: 'deleteText';\n\treadonly blockId: BlockId;\n\treadonly from: number;\n\treadonly to: number;\n\treadonly deletedText: string;\n\treadonly deletedMarks: readonly Mark[];\n\treadonly deletedSegments: readonly TextSegment[];\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface SplitBlockStep {\n\treadonly type: 'splitBlock';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly newBlockId: BlockId;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface MergeBlocksStep {\n\treadonly type: 'mergeBlocks';\n\treadonly targetBlockId: BlockId;\n\treadonly sourceBlockId: BlockId;\n\treadonly targetLengthBefore: number;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface AddMarkStep {\n\treadonly type: 'addMark';\n\treadonly blockId: BlockId;\n\treadonly from: number;\n\treadonly to: number;\n\treadonly mark: Mark;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface RemoveMarkStep {\n\treadonly type: 'removeMark';\n\treadonly blockId: BlockId;\n\treadonly from: number;\n\treadonly to: number;\n\treadonly mark: Mark;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface SetStoredMarksStep {\n\treadonly type: 'setStoredMarks';\n\treadonly marks: readonly Mark[] | null;\n\treadonly previousMarks: readonly Mark[] | null;\n}\n\nexport interface SetBlockTypeStep {\n\treadonly type: 'setBlockType';\n\treadonly blockId: BlockId;\n\treadonly nodeType: NodeTypeName;\n\treadonly attrs?: BlockAttrs;\n\treadonly previousNodeType: NodeTypeName;\n\treadonly previousAttrs?: BlockAttrs;\n\treadonly path?: readonly BlockId[];\n}\n\n// --- Structural Steps (for nested documents) ---\n\nexport interface InsertNodeStep {\n\treadonly type: 'insertNode';\n\treadonly parentPath: readonly BlockId[];\n\treadonly index: number;\n\treadonly node: BlockNode;\n}\n\nexport interface RemoveNodeStep {\n\treadonly type: 'removeNode';\n\treadonly parentPath: readonly BlockId[];\n\treadonly index: number;\n\treadonly removedNode: BlockNode;\n}\n\nexport interface SetNodeAttrStep {\n\treadonly type: 'setNodeAttr';\n\treadonly path: readonly BlockId[];\n\treadonly attrs: BlockAttrs | undefined;\n\treadonly previousAttrs?: BlockAttrs;\n}\n\n// --- InlineNode Steps ---\n\nexport interface InsertInlineNodeStep {\n\treadonly type: 'insertInlineNode';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly node: InlineNode;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface RemoveInlineNodeStep {\n\treadonly type: 'removeInlineNode';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly removedNode: InlineNode;\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface SetInlineNodeAttrStep {\n\treadonly type: 'setInlineNodeAttr';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly attrs: Readonly<Record<string, string | number | boolean>>;\n\treadonly previousAttrs: Readonly<Record<string, string | number | boolean>>;\n\treadonly path?: readonly BlockId[];\n}\n\nexport type Step =\n\t| InsertTextStep\n\t| DeleteTextStep\n\t| SplitBlockStep\n\t| MergeBlocksStep\n\t| AddMarkStep\n\t| RemoveMarkStep\n\t| SetStoredMarksStep\n\t| SetBlockTypeStep\n\t| InsertNodeStep\n\t| RemoveNodeStep\n\t| SetNodeAttrStep\n\t| InsertInlineNodeStep\n\t| RemoveInlineNodeStep\n\t| SetInlineNodeAttrStep;\n\n// --- Transaction ---\n\nexport type TransactionOrigin = 'input' | 'paste' | 'command' | 'history' | 'api';\n\nexport interface TransactionMetadata {\n\treadonly origin: TransactionOrigin;\n\treadonly timestamp: number;\n\treadonly historyDirection?: 'undo' | 'redo';\n\treadonly readonlyAllowed?: boolean;\n}\n\nexport interface Transaction {\n\treadonly steps: readonly Step[];\n\treadonly selectionBefore: EditorSelection;\n\treadonly selectionAfter: EditorSelection;\n\treadonly storedMarksAfter: readonly Mark[] | null;\n\treadonly metadata: TransactionMetadata;\n}\n\n// --- Step Inversion ---\n\n/** Inverts a single step for undo. */\nexport function invertStep(step: Step): Step {\n\tswitch (step.type) {\n\t\tcase 'insertText':\n\t\t\treturn {\n\t\t\t\ttype: 'deleteText',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\tfrom: step.offset,\n\t\t\t\tto: step.offset + step.text.length,\n\t\t\t\tdeletedText: step.text,\n\t\t\t\tdeletedMarks: step.marks,\n\t\t\t\tdeletedSegments: step.segments ?? [{ text: step.text, marks: [...step.marks] }],\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'deleteText':\n\t\t\treturn {\n\t\t\t\ttype: 'insertText',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\toffset: step.from,\n\t\t\t\ttext: step.deletedText,\n\t\t\t\tmarks: step.deletedMarks,\n\t\t\t\tsegments: step.deletedSegments,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'splitBlock':\n\t\t\treturn {\n\t\t\t\ttype: 'mergeBlocks',\n\t\t\t\ttargetBlockId: step.blockId,\n\t\t\t\tsourceBlockId: step.newBlockId,\n\t\t\t\ttargetLengthBefore: step.offset,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'mergeBlocks':\n\t\t\treturn {\n\t\t\t\ttype: 'splitBlock',\n\t\t\t\tblockId: step.targetBlockId,\n\t\t\t\toffset: step.targetLengthBefore,\n\t\t\t\tnewBlockId: step.sourceBlockId,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'addMark':\n\t\t\treturn {\n\t\t\t\ttype: 'removeMark',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\tfrom: step.from,\n\t\t\t\tto: step.to,\n\t\t\t\tmark: step.mark,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'removeMark':\n\t\t\treturn {\n\t\t\t\ttype: 'addMark',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\tfrom: step.from,\n\t\t\t\tto: step.to,\n\t\t\t\tmark: step.mark,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'setStoredMarks':\n\t\t\treturn {\n\t\t\t\ttype: 'setStoredMarks',\n\t\t\t\tmarks: step.previousMarks,\n\t\t\t\tpreviousMarks: step.marks,\n\t\t\t};\n\t\tcase 'setBlockType':\n\t\t\treturn {\n\t\t\t\ttype: 'setBlockType',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\tnodeType: step.previousNodeType,\n\t\t\t\tattrs: step.previousAttrs,\n\t\t\t\tpreviousNodeType: step.nodeType,\n\t\t\t\tpreviousAttrs: step.attrs,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'insertNode':\n\t\t\treturn {\n\t\t\t\ttype: 'removeNode',\n\t\t\t\tparentPath: step.parentPath,\n\t\t\t\tindex: step.index,\n\t\t\t\tremovedNode: step.node,\n\t\t\t};\n\t\tcase 'removeNode':\n\t\t\treturn {\n\t\t\t\ttype: 'insertNode',\n\t\t\t\tparentPath: step.parentPath,\n\t\t\t\tindex: step.index,\n\t\t\t\tnode: step.removedNode,\n\t\t\t};\n\t\tcase 'setNodeAttr':\n\t\t\treturn {\n\t\t\t\ttype: 'setNodeAttr',\n\t\t\t\tpath: step.path,\n\t\t\t\tattrs: step.previousAttrs,\n\t\t\t\tpreviousAttrs: step.attrs,\n\t\t\t};\n\t\tcase 'insertInlineNode':\n\t\t\treturn {\n\t\t\t\ttype: 'removeInlineNode',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\toffset: step.offset,\n\t\t\t\tremovedNode: step.node,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'removeInlineNode':\n\t\t\treturn {\n\t\t\t\ttype: 'insertInlineNode',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\toffset: step.offset,\n\t\t\t\tnode: step.removedNode,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t\tcase 'setInlineNodeAttr':\n\t\t\treturn {\n\t\t\t\ttype: 'setInlineNodeAttr',\n\t\t\t\tblockId: step.blockId,\n\t\t\t\toffset: step.offset,\n\t\t\t\tattrs: step.previousAttrs,\n\t\t\t\tpreviousAttrs: step.attrs,\n\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t};\n\t}\n}\n\n/** Inverts an entire transaction (reverses step order and swaps selections). */\nexport function invertTransaction(tr: Transaction): Transaction {\n\treturn {\n\t\tsteps: tr.steps.map(invertStep).reverse(),\n\t\tselectionBefore: tr.selectionAfter,\n\t\tselectionAfter: tr.selectionBefore,\n\t\tstoredMarksAfter: null,\n\t\tmetadata: {\n\t\t\torigin: 'history',\n\t\t\ttimestamp: Date.now(),\n\t\t},\n\t};\n}\n\n// --- TransactionBuilder ---\n\n/** Fluent API for building transactions. */\nexport class TransactionBuilder {\n\tprivate readonly steps: Step[] = [];\n\tprivate selection: EditorSelection;\n\tprivate storedMarks: readonly Mark[] | null;\n\tprivate readonly selectionBefore: EditorSelection;\n\tprivate readonly origin: TransactionOrigin;\n\tprivate workingDoc: Document | null;\n\tprivate _readonlyAllowed = false;\n\n\tconstructor(\n\t\tcurrentSelection: EditorSelection,\n\t\tcurrentStoredMarks: readonly Mark[] | null,\n\t\torigin: TransactionOrigin = 'api',\n\t\tdoc?: Document,\n\t) {\n\t\tthis.selection = currentSelection;\n\t\tthis.selectionBefore = currentSelection;\n\t\tthis.storedMarks = currentStoredMarks;\n\t\tthis.origin = origin;\n\t\tthis.workingDoc = doc ?? null;\n\t}\n\n\t/** Adds an insert-text step. Updates workingDoc if available. */\n\tinsertText(\n\t\tblockId: BlockId,\n\t\toffset: number,\n\t\ttext: string,\n\t\tmarks: readonly Mark[],\n\t\tsegments?: readonly TextSegment[],\n\t): this {\n\t\tconst step: InsertTextStep = {\n\t\t\ttype: 'insertText',\n\t\t\tblockId,\n\t\t\toffset,\n\t\t\ttext,\n\t\t\tmarks,\n\t\t\t...(segments ? { segments } : {}),\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Adds a delete-text step with explicit data. Updates workingDoc if available. */\n\tdeleteText(\n\t\tblockId: BlockId,\n\t\tfrom: number,\n\t\tto: number,\n\t\tdeletedText: string,\n\t\tdeletedMarks: readonly Mark[],\n\t\tdeletedSegments?: readonly TextSegment[],\n\t): this {\n\t\tlet segments: readonly TextSegment[];\n\t\tif (deletedSegments) {\n\t\t\tsegments = deletedSegments;\n\t\t} else if (this.workingDoc) {\n\t\t\tconst block = findNode(this.workingDoc, blockId);\n\t\t\tsegments = block\n\t\t\t\t? getBlockSegmentsInRange(block, from, to)\n\t\t\t\t: [{ text: deletedText, marks: [...deletedMarks] }];\n\t\t} else {\n\t\t\tsegments = [{ text: deletedText, marks: [...deletedMarks] }];\n\t\t}\n\t\tconst step: DeleteTextStep = {\n\t\t\ttype: 'deleteText',\n\t\t\tblockId,\n\t\t\tfrom,\n\t\t\tto,\n\t\t\tdeletedText,\n\t\t\tdeletedMarks,\n\t\t\tdeletedSegments: segments,\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Deletes text at the given range, auto-deriving deletedText, deletedMarks, and deletedSegments\n\t * from the working document. Requires a document to be provided at construction.\n\t */\n\tdeleteTextAt(blockId: BlockId, from: number, to: number): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'deleteTextAt requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\n\t\tconst block = findNode(doc, blockId);\n\t\tif (!block) {\n\t\t\tthrow new Error(`Block \"${blockId}\" not found in working document.`);\n\t\t}\n\n\t\tconst text = getBlockText(block);\n\t\tconst deletedText = text.slice(from, to);\n\t\tconst deletedMarks = getBlockMarksAtOffset(block, from);\n\t\tconst deletedSegments = getBlockSegmentsInRange(block, from, to);\n\n\t\treturn this.deleteText(blockId, from, to, deletedText, deletedMarks, deletedSegments);\n\t}\n\n\t/** Adds a split-block step. Updates workingDoc if available. */\n\tsplitBlock(blockId: BlockId, offset: number, newBlockId: BlockId): this {\n\t\tconst step: SplitBlockStep = { type: 'splitBlock', blockId, offset, newBlockId };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Adds a merge-blocks step with explicit targetLengthBefore. Updates workingDoc if available. */\n\tmergeBlocks(targetBlockId: BlockId, sourceBlockId: BlockId, targetLengthBefore: number): this {\n\t\tconst step: MergeBlocksStep = {\n\t\t\ttype: 'mergeBlocks',\n\t\t\ttargetBlockId,\n\t\t\tsourceBlockId,\n\t\t\ttargetLengthBefore,\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Merges two blocks, auto-deriving targetLengthBefore from the working document.\n\t * Requires a document to be provided at construction.\n\t */\n\tmergeBlocksAt(targetBlockId: BlockId, sourceBlockId: BlockId): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'mergeBlocksAt requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\n\t\tconst targetBlock = findNode(doc, targetBlockId);\n\t\tif (!targetBlock) {\n\t\t\tthrow new Error(`Target block \"${targetBlockId}\" not found in working document.`);\n\t\t}\n\n\t\tconst targetLengthBefore = getBlockLength(targetBlock);\n\t\treturn this.mergeBlocks(targetBlockId, sourceBlockId, targetLengthBefore);\n\t}\n\n\t/** Adds an add-mark step. Updates workingDoc if available. */\n\taddMark(blockId: BlockId, from: number, to: number, mark: Mark): this {\n\t\tconst step: AddMarkStep = { type: 'addMark', blockId, from, to, mark };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Adds a remove-mark step. Updates workingDoc if available. */\n\tremoveMark(blockId: BlockId, from: number, to: number, mark: Mark): this {\n\t\tconst step: RemoveMarkStep = { type: 'removeMark', blockId, from, to, mark };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Adds a set-block-type step, changing a block's node type and optionally its attrs. */\n\tsetBlockType(blockId: BlockId, nodeType: NodeTypeName, attrs?: BlockAttrs): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'setBlockType requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\t\tconst block = findNode(doc, blockId);\n\t\tif (!block) {\n\t\t\tthrow new Error(`Block \"${blockId}\" not found in working document.`);\n\t\t}\n\t\tconst step: SetBlockTypeStep = {\n\t\t\ttype: 'setBlockType',\n\t\t\tblockId,\n\t\t\tnodeType,\n\t\t\t...(attrs ? { attrs } : {}),\n\t\t\tpreviousNodeType: block.type,\n\t\t\t...(block.attrs ? { previousAttrs: block.attrs } : {}),\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Inserts a node as a child of the parent at the given path and index. */\n\tinsertNode(parentPath: readonly BlockId[], index: number, node: BlockNode): this {\n\t\tconst step: InsertNodeStep = { type: 'insertNode', parentPath, index, node };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Removes a node at the given index from the parent at the given path. */\n\tremoveNode(parentPath: readonly BlockId[], index: number): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'removeNode requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\n\t\tconst removedNode = resolveRemovedNode(doc, parentPath, index);\n\t\tif (!removedNode) {\n\t\t\tthrow new Error(\n\t\t\t\t`Node at index ${index} not found under parent path [${parentPath.join(', ')}].`,\n\t\t\t);\n\t\t}\n\n\t\tconst step: RemoveNodeStep = { type: 'removeNode', parentPath, index, removedNode };\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Sets attributes on a node at the given path. */\n\tsetNodeAttr(path: readonly BlockId[], attrs: BlockAttrs): this {\n\t\tconst doc = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'setNodeAttr requires a document. Use state.transaction() or provide doc to constructor.',\n\t\t\t);\n\t\t}\n\n\t\tconst node = resolveNodeByPath(doc, path);\n\t\tif (!node) {\n\t\t\tthrow new Error(`Node not found at path [${path.join(', ')}].`);\n\t\t}\n\n\t\tconst step: SetNodeAttrStep = {\n\t\t\ttype: 'setNodeAttr',\n\t\t\tpath,\n\t\t\tattrs,\n\t\t\t...(node.attrs ? { previousAttrs: node.attrs } : {}),\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Inserts an InlineNode at the given offset within a block. */\n\tinsertInlineNode(blockId: BlockId, offset: number, node: InlineNode): this {\n\t\tconst step: InsertInlineNodeStep = {\n\t\t\ttype: 'insertInlineNode',\n\t\t\tblockId,\n\t\t\toffset,\n\t\t\tnode,\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Removes an InlineNode at the given offset, deriving removedNode from workingDoc. */\n\tremoveInlineNode(blockId: BlockId, offset: number): this {\n\t\tconst doc: Document | null = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'removeInlineNode requires a document. Use state.transaction() or provide doc.',\n\t\t\t);\n\t\t}\n\t\tconst block: BlockNode | undefined = findNode(doc, blockId);\n\t\tif (!block) {\n\t\t\tthrow new Error(`Block \"${blockId}\" not found in working document.`);\n\t\t}\n\t\tconst content = getContentAtOffset(block, offset);\n\t\tif (!content || content.kind !== 'inline') {\n\t\t\tthrow new Error(`No InlineNode at offset ${offset} in block \"${blockId}\".`);\n\t\t}\n\t\tconst step: RemoveInlineNodeStep = {\n\t\t\ttype: 'removeInlineNode',\n\t\t\tblockId,\n\t\t\toffset,\n\t\t\tremovedNode: content.node,\n\t\t};\n\t\tthis.steps.push(step);\n\t\tthis.advanceDoc(step);\n\t\treturn this;\n\t}\n\n\t/** Sets attributes on an InlineNode at the given offset. */\n\tsetInlineNodeAttr(\n\t\tblockId: BlockId,\n\t\toffset: number,\n\t\tattrs: Readonly<Record<string, string | number | boolean>>,\n\t): this {\n\t\tconst doc: Document | null = this.workingDoc;\n\t\tif (!doc) {\n\t\t\tthrow new Error(\n\t\t\t\t'setInlineNodeAttr requires a document. Use state.transaction() or provide doc.',\n\t\t\t);\n\t\t}\n\t\tconst block: BlockNode | undefined = findNode(doc, blockId);\n\t\tif (!block) {\n\t\t\tthrow new Error(`Block \"${blockId}\" not found in working document.`);\n\t\t}\n\t\tconst inlineChildren = getInlineChildren(block);\n\t\tlet pos = 0;\n\t\tfor (const child of inlineChildren) {\n\t\t\tif (isInlineNode(child) && pos === offset) {\n\t\t\t\tconst step: SetInlineNodeAttrStep = {\n\t\t\t\t\ttype: 'setInlineNodeAttr',\n\t\t\t\t\tblockId,\n\t\t\t\t\toffset,\n\t\t\t\t\tattrs,\n\t\t\t\t\tpreviousAttrs: child.attrs,\n\t\t\t\t};\n\t\t\t\tthis.steps.push(step);\n\t\t\t\tthis.advanceDoc(step);\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tpos += isInlineNode(child) ? 1 : child.text.length;\n\t\t}\n\t\tthrow new Error(`No InlineNode at offset ${offset} in block \"${blockId}\".`);\n\t}\n\n\t/** Marks this transaction as allowed in readonly mode. */\n\treadonlyAllowed(): this {\n\t\tthis._readonlyAllowed = true;\n\t\treturn this;\n\t}\n\n\t/** Sets the selection for the resulting state. */\n\tsetSelection(selection: EditorSelection): this {\n\t\tthis.selection = selection;\n\t\treturn this;\n\t}\n\n\t/** Sets a NodeSelection for the resulting state. */\n\tsetNodeSelection(nodeId: BlockId, path: readonly BlockId[]): this {\n\t\tthis.selection = createNodeSelection(nodeId, path);\n\t\treturn this;\n\t}\n\n\t/** Sets stored marks for the resulting state. */\n\tsetStoredMarks(marks: readonly Mark[] | null, previousMarks: readonly Mark[] | null): this {\n\t\tthis.steps.push({ type: 'setStoredMarks', marks, previousMarks });\n\t\tthis.storedMarks = marks;\n\t\treturn this;\n\t}\n\n\t/** Builds the final transaction. */\n\tbuild(): Transaction {\n\t\treturn {\n\t\t\tsteps: [...this.steps],\n\t\t\tselectionBefore: this.selectionBefore,\n\t\t\tselectionAfter: this.selection,\n\t\t\tstoredMarksAfter: this.storedMarks,\n\t\t\tmetadata: {\n\t\t\t\torigin: this.origin,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t...(this._readonlyAllowed ? { readonlyAllowed: true } : {}),\n\t\t\t},\n\t\t};\n\t}\n\n\t/** Advances the working document by applying a step. */\n\tprivate advanceDoc(step: Step): void {\n\t\tif (this.workingDoc) {\n\t\t\tthis.workingDoc = applyStep(this.workingDoc, step);\n\t\t}\n\t}\n}\n\n/** Helper to create a TransactionBuilder with input origin. */\nexport function inputTransaction(\n\tselection: EditorSelection,\n\tstoredMarks: readonly Mark[] | null,\n): TransactionBuilder {\n\treturn new TransactionBuilder(selection, storedMarks, 'input');\n}\n\n/** Helper to create a TransactionBuilder with command origin. */\nexport function commandTransaction(\n\tselection: EditorSelection,\n\tstoredMarks: readonly Mark[] | null,\n): TransactionBuilder {\n\treturn new TransactionBuilder(selection, storedMarks, 'command');\n}\n\n/** Resolves the block node to be removed from a parent path and index. */\nfunction resolveRemovedNode(\n\tdoc: Document,\n\tparentPath: readonly BlockId[],\n\tindex: number,\n): BlockNode | undefined {\n\tif (parentPath.length === 0) {\n\t\tconst child = doc.children[index];\n\t\treturn child && isBlockNode(child) ? child : undefined;\n\t}\n\tconst parent = resolveNodeByPath(doc, parentPath);\n\tif (!parent) return undefined;\n\tconst child = parent.children[index];\n\treturn child && isBlockNode(child) ? child : undefined;\n}\n","/**\n * Immutable editor state container.\n * Every mutation produces a new EditorState instance.\n */\n\nimport {\n\ttype BlockNode,\n\ttype Document,\n\ttype Mark,\n\tcreateDocument,\n\tgetBlockLength,\n\tisBlockNode,\n\tisLeafBlock,\n} from '../model/Document.js';\nimport { findNode, findNodePath } from '../model/NodeResolver.js';\nimport type { Schema } from '../model/Schema.js';\nimport { defaultSchema } from '../model/Schema.js';\nimport type { EditorSelection, Position } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreatePosition,\n\tcreateSelection,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport { type BlockId, blockId } from '../model/TypeBrands.js';\nimport { applyStep } from './StepApplication.js';\nimport type { Transaction } from './Transaction.js';\nimport { TransactionBuilder } from './Transaction.js';\n\nexport class EditorState {\n\treadonly doc: Document;\n\treadonly selection: EditorSelection;\n\treadonly storedMarks: readonly Mark[] | null;\n\treadonly schema: Schema;\n\n\tprivate _blockMap: Map<BlockId, BlockNode> | null = null;\n\tprivate _blockOrder: readonly BlockId[] | null = null;\n\n\tprivate constructor(\n\t\tdoc: Document,\n\t\tselection: EditorSelection,\n\t\tstoredMarks: readonly Mark[] | null,\n\t\tschema: Schema,\n\t) {\n\t\tthis.doc = doc;\n\t\tthis.selection = selection;\n\t\tthis.storedMarks = storedMarks;\n\t\tthis.schema = schema;\n\t}\n\n\t/** Creates a new EditorState with default document. */\n\tstatic create(options?: {\n\t\tdoc?: Document;\n\t\tselection?: EditorSelection;\n\t\tschema?: Schema;\n\t}): EditorState {\n\t\tconst schema = options?.schema ?? defaultSchema();\n\t\tconst doc = options?.doc ?? createDocument();\n\t\tconst firstBlock = doc.children[0];\n\t\tconst selection =\n\t\t\toptions?.selection ?? createCollapsedSelection(firstBlock ? firstBlock.id : blockId(''), 0);\n\n\t\treturn new EditorState(doc, selection, null, schema);\n\t}\n\n\t/** Creates a TransactionBuilder from this state. */\n\ttransaction(\n\t\torigin: 'input' | 'paste' | 'command' | 'history' | 'api' = 'api',\n\t): TransactionBuilder {\n\t\treturn new TransactionBuilder(this.selection, this.storedMarks, origin, this.doc);\n\t}\n\n\t/** Applies a transaction and returns a new EditorState. */\n\tapply(tr: Transaction): EditorState {\n\t\tlet doc = this.doc;\n\n\t\tfor (const step of tr.steps) {\n\t\t\tdoc = applyStep(doc, step);\n\t\t}\n\n\t\tconst selection = validateSelection(doc, tr.selectionAfter);\n\t\treturn new EditorState(doc, selection, tr.storedMarksAfter, this.schema);\n\t}\n\n\t/** Finds a block by its ID anywhere in the tree. Uses a lazy-built Map for O(1) lookup. */\n\tgetBlock(blockId: BlockId): BlockNode | undefined {\n\t\tthis._blockMap ??= buildBlockMap(this.doc);\n\t\treturn this._blockMap.get(blockId);\n\t}\n\n\t/** Returns leaf-block IDs in depth-first order. Cached after first call. */\n\tgetBlockOrder(): readonly BlockId[] {\n\t\tthis._blockOrder ??= buildBlockOrder(this.doc);\n\t\treturn this._blockOrder;\n\t}\n\n\t/** Returns the path (array of block IDs) to a node. */\n\tgetNodePath(nodeId: BlockId): BlockId[] | undefined {\n\t\treturn findNodePath(this.doc, nodeId) as BlockId[] | undefined;\n\t}\n\n\t/** Returns the parent BlockNode of a node, or undefined for top-level blocks. */\n\tgetParent(nodeId: BlockId): BlockNode | undefined {\n\t\tconst path = findNodePath(this.doc, nodeId);\n\t\tif (!path || path.length <= 1) return undefined;\n\t\tconst parentId = path[path.length - 2] as BlockId | undefined;\n\t\tif (!parentId) return undefined;\n\t\treturn findNode(this.doc, parentId);\n\t}\n\n\t/** Serializes the state to JSON. */\n\ttoJSON(): { readonly doc: Document; readonly selection: EditorSelection } {\n\t\treturn {\n\t\t\tdoc: this.doc,\n\t\t\tselection: this.selection,\n\t\t};\n\t}\n\n\t/** Deserializes a state from JSON. */\n\tstatic fromJSON(\n\t\tjson: { doc: Document; selection: EditorSelection },\n\t\tschema?: Schema,\n\t): EditorState {\n\t\treturn new EditorState(json.doc, json.selection, null, schema ?? defaultSchema());\n\t}\n}\n\n/** Validates a position against the document, clamping or falling back as needed. */\nfunction validatePosition(doc: Document, pos: Position): Position {\n\tconst block = findNode(doc, pos.blockId);\n\tif (block) {\n\t\tconst length = getBlockLength(block);\n\t\tif (pos.offset > length) {\n\t\t\treturn createPosition(pos.blockId, length, pos.path);\n\t\t}\n\t\treturn pos;\n\t}\n\n\tconst firstBlock = doc.children[0];\n\tif (!firstBlock) return pos;\n\treturn createPosition(firstBlock.id, 0);\n}\n\n/** Validates a selection against the document, ensuring blockIds exist and offsets are in bounds. */\nfunction validateSelection(doc: Document, sel: EditorSelection): EditorSelection {\n\tif (isNodeSelection(sel)) {\n\t\tconst node = findNode(doc, sel.nodeId);\n\t\tif (node) return sel;\n\t\t// Node was deleted — fall back to first leaf block\n\t\treturn fallbackSelection(doc, sel);\n\t}\n\tif (isGapCursor(sel)) {\n\t\tconst node = findNode(doc, sel.blockId);\n\t\tif (node) return sel;\n\t\t// Referenced block was deleted — fall back to first leaf block\n\t\treturn fallbackSelection(doc, sel);\n\t}\n\tconst anchor = validatePosition(doc, sel.anchor);\n\tconst head = validatePosition(doc, sel.head);\n\tif (anchor === sel.anchor && head === sel.head) return sel;\n\treturn createSelection(anchor, head);\n}\n\n/** Returns a collapsed selection on the first leaf block, or the original selection if no blocks exist. */\nfunction fallbackSelection(doc: Document, sel: EditorSelection): EditorSelection {\n\tconst leaf = findFirstLeafBlock(doc.children);\n\tif (!leaf) return sel;\n\treturn createCollapsedSelection(leaf.id, 0);\n}\n\n/** Descends into the first child of each container block to find the first leaf block. */\nfunction findFirstLeafBlock(\n\tchildren: readonly import('../model/Document.js').ChildNode[],\n): BlockNode | null {\n\tfor (const child of children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tif (isLeafBlock(child)) return child;\n\t\tconst nested: BlockNode | null = findFirstLeafBlock(child.children);\n\t\tif (nested) return nested;\n\t}\n\treturn null;\n}\n\n/** Recursively builds a Map of blockId → BlockNode for all nodes in the tree. */\nfunction buildBlockMap(doc: Document): Map<BlockId, BlockNode> {\n\tconst map = new Map<BlockId, BlockNode>();\n\tfunction walk(blocks: readonly import('../model/Document.js').ChildNode[]): void {\n\t\tfor (const child of blocks) {\n\t\t\tif (isBlockNode(child)) {\n\t\t\t\tmap.set(child.id, child);\n\t\t\t\twalk(child.children);\n\t\t\t}\n\t\t}\n\t}\n\twalk(doc.children);\n\treturn map;\n}\n\n/** Returns leaf-block IDs in depth-first order. */\nfunction buildBlockOrder(doc: Document): BlockId[] {\n\tconst order: BlockId[] = [];\n\tfunction walk(blocks: readonly import('../model/Document.js').ChildNode[]): void {\n\t\tfor (const child of blocks) {\n\t\t\tif (isBlockNode(child)) {\n\t\t\t\tif (isLeafBlock(child)) {\n\t\t\t\t\torder.push(child.id);\n\t\t\t\t} else {\n\t\t\t\t\twalk(child.children);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\twalk(doc.children);\n\treturn order;\n}\n","/**\n * Pure guard functions for readonly mode enforcement.\n * Used by the central dispatch guard to determine whether a transaction\n * should be allowed in readonly mode.\n */\n\nimport type { Transaction } from './Transaction.js';\n\n/** Returns true if the transaction contains no document-mutating steps. */\nexport function isSelectionOnlyTransaction(tr: Transaction): boolean {\n\tfor (const step of tr.steps) {\n\t\tif (step.type !== 'setStoredMarks') return false;\n\t}\n\treturn true;\n}\n\n/** Returns true if the transaction is allowed to proceed in readonly mode. */\nexport function isAllowedInReadonly(tr: Transaction): boolean {\n\tif (tr.metadata.readonlyAllowed) return true;\n\treturn isSelectionOnlyTransaction(tr);\n}\n","/**\n * History manager for undo/redo with transaction grouping.\n */\n\nimport type { EditorState } from './EditorState.js';\nimport type { Step, Transaction } from './Transaction.js';\nimport { invertTransaction } from './Transaction.js';\n\nexport interface HistoryResult {\n\treadonly state: EditorState;\n\treadonly transaction: Transaction;\n}\n\ninterface HistoryGroup {\n\treadonly transactions: readonly Transaction[];\n\treadonly timestamp: number;\n}\n\nconst DEFAULT_GROUP_TIMEOUT_MS = 500;\nconst DEFAULT_MAX_DEPTH = 100;\n\nexport class HistoryManager {\n\tprivate undoStack: HistoryGroup[] = [];\n\tprivate redoStack: HistoryGroup[] = [];\n\tprivate readonly groupTimeoutMs: number;\n\tprivate readonly maxDepth: number;\n\tprivate lastOrigin: string | null = null;\n\n\tconstructor(options?: { groupTimeoutMs?: number; maxDepth?: number }) {\n\t\tthis.groupTimeoutMs = options?.groupTimeoutMs ?? DEFAULT_GROUP_TIMEOUT_MS;\n\t\tthis.maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH;\n\t}\n\n\t/**\n\t * Pushes a transaction onto the undo stack.\n\t * Groups consecutive input transactions within the timeout window.\n\t */\n\tpush(tr: Transaction): void {\n\t\t// History and redo transactions are not pushed\n\t\tif (tr.metadata.origin === 'history') return;\n\n\t\t// Skip transactions with no document changes (selection/stored marks only)\n\t\t// but break grouping so the next insertion starts a new undo group.\n\t\tif (!tr.steps.some((step: Step) => step.type !== 'setStoredMarks')) {\n\t\t\tthis.lastOrigin = null;\n\t\t\treturn;\n\t\t}\n\n\t\tconst now = tr.metadata.timestamp;\n\t\tconst lastGroup = this.undoStack[this.undoStack.length - 1];\n\t\tconst shouldGroup =\n\t\t\tlastGroup &&\n\t\t\ttr.metadata.origin === 'input' &&\n\t\t\tthis.lastOrigin === 'input' &&\n\t\t\tnow - lastGroup.timestamp < this.groupTimeoutMs &&\n\t\t\tthis.isSameInputType(lastGroup.transactions, tr);\n\n\t\tif (shouldGroup && lastGroup) {\n\t\t\t// Merge into existing group\n\t\t\tthis.undoStack[this.undoStack.length - 1] = {\n\t\t\t\ttransactions: [...lastGroup.transactions, tr],\n\t\t\t\ttimestamp: now,\n\t\t\t};\n\t\t} else {\n\t\t\t// Start new group\n\t\t\tthis.undoStack.push({\n\t\t\t\ttransactions: [tr],\n\t\t\t\ttimestamp: now,\n\t\t\t});\n\t\t}\n\n\t\tthis.lastOrigin = tr.metadata.origin;\n\n\t\t// Clear redo stack on new input\n\t\tthis.redoStack = [];\n\n\t\t// Enforce max depth\n\t\twhile (this.undoStack.length > this.maxDepth) {\n\t\t\tthis.undoStack.shift();\n\t\t}\n\t}\n\n\t/** Undoes the last group and returns the new state with transaction, or null if nothing to undo. */\n\tundo(state: EditorState): HistoryResult | null {\n\t\tconst group = this.undoStack.pop();\n\t\tif (!group) return null;\n\n\t\tlet currentState = state;\n\t\tconst allSteps: Step[] = [];\n\n\t\t// Apply inverted transactions in reverse order\n\t\tfor (let i = group.transactions.length - 1; i >= 0; i--) {\n\t\t\tconst tr = group.transactions[i];\n\t\t\tif (!tr) continue;\n\t\t\tconst inverted = invertTransaction(tr);\n\t\t\tcurrentState = currentState.apply(inverted);\n\t\t\tallSteps.push(...inverted.steps);\n\t\t}\n\n\t\t// Push to redo stack\n\t\tthis.redoStack.push({\n\t\t\ttransactions: group.transactions,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\n\t\tthis.lastOrigin = null;\n\n\t\tconst transaction: Transaction = {\n\t\t\tsteps: allSteps,\n\t\t\tselectionBefore: state.selection,\n\t\t\tselectionAfter: currentState.selection,\n\t\t\tstoredMarksAfter: currentState.storedMarks,\n\t\t\tmetadata: { origin: 'history', timestamp: Date.now(), historyDirection: 'undo' },\n\t\t};\n\n\t\treturn { state: currentState, transaction };\n\t}\n\n\t/** Redoes the last undone group and returns the new state with transaction, or null if nothing to redo. */\n\tredo(state: EditorState): HistoryResult | null {\n\t\tconst group = this.redoStack.pop();\n\t\tif (!group) return null;\n\n\t\tlet currentState = state;\n\t\tconst allSteps: Step[] = [];\n\n\t\t// Re-apply transactions in original order\n\t\tfor (const tr of group.transactions) {\n\t\t\tcurrentState = currentState.apply(tr);\n\t\t\tallSteps.push(...tr.steps);\n\t\t}\n\n\t\t// Push back to undo stack\n\t\tthis.undoStack.push({\n\t\t\ttransactions: group.transactions,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\n\t\tthis.lastOrigin = null;\n\n\t\tconst transaction: Transaction = {\n\t\t\tsteps: allSteps,\n\t\t\tselectionBefore: state.selection,\n\t\t\tselectionAfter: currentState.selection,\n\t\t\tstoredMarksAfter: currentState.storedMarks,\n\t\t\tmetadata: { origin: 'history', timestamp: Date.now(), historyDirection: 'redo' },\n\t\t};\n\n\t\treturn { state: currentState, transaction };\n\t}\n\n\t/** Returns true if there are entries to undo. */\n\tcanUndo(): boolean {\n\t\treturn this.undoStack.length > 0;\n\t}\n\n\t/** Returns true if there are entries to redo. */\n\tcanRedo(): boolean {\n\t\treturn this.redoStack.length > 0;\n\t}\n\n\t/** Clears all history. */\n\tclear(): void {\n\t\tthis.undoStack = [];\n\t\tthis.redoStack = [];\n\t\tthis.lastOrigin = null;\n\t}\n\n\t/**\n\t * Checks if consecutive transactions are of the same \"type\" for grouping.\n\t * Groups text insertion together, deletion together, but not mixed.\n\t */\n\tprivate isSameInputType(existing: readonly Transaction[], incoming: Transaction): boolean {\n\t\tconst lastTr = existing[existing.length - 1];\n\t\tif (!lastTr) return false;\n\n\t\tconst lastStepType = lastTr.steps[0]?.type;\n\t\tconst incomingStepType = incoming.steps[0]?.type;\n\n\t\t// Group same step types (insertText with insertText, deleteText with deleteText)\n\t\treturn lastStepType === incomingStepType;\n\t}\n}\n","/**\n * Delete commands: character, word, and soft-line deletion in both directions.\n */\n\nimport { type BlockNode, getBlockLength } from '../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { deleteSelectionCommand, mergeBlockBackward, mergeBlockForward } from './Commands.js';\nimport { deleteNodeSelection } from './NodeSelectionCommands.js';\nimport { findWordBoundaryBackward, findWordBoundaryForward } from './WordBoundary.js';\n\ninterface DeleteConfig {\n\treadonly merge: (state: EditorState) => Transaction | null;\n\treadonly range: (block: BlockNode, offset: number) => readonly [number, number] | null;\n}\n\nfunction deleteInDirection(state: EditorState, config: DeleteConfig): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) return deleteNodeSelection(state, sel);\n\tif (isGapCursor(sel)) return null;\n\tif (!isCollapsed(sel)) return deleteSelectionCommand(state);\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\n\tconst range = config.range(block, sel.anchor.offset);\n\tif (!range) return config.merge(state);\n\n\tconst [from, to] = range;\n\treturn state\n\t\t.transaction('input')\n\t\t.deleteTextAt(block.id, from, to)\n\t\t.setSelection(createCollapsedSelection(block.id, from))\n\t\t.build();\n}\n\n/** Handles backspace key. */\nexport function deleteBackward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockBackward,\n\t\trange: (_block, offset) => (offset > 0 ? [offset - 1, offset] : null),\n\t});\n}\n\n/** Handles delete key. */\nexport function deleteForward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockForward,\n\t\trange: (block, offset) => {\n\t\t\tconst len = getBlockLength(block);\n\t\t\treturn offset < len ? [offset, offset + 1] : null;\n\t\t},\n\t});\n}\n\n/** Handles Ctrl+Backspace: delete word backward. */\nexport function deleteWordBackward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockBackward,\n\t\trange: (block, offset) =>\n\t\t\toffset > 0 ? [findWordBoundaryBackward(block, offset), offset] : null,\n\t});\n}\n\n/** Handles Ctrl+Delete: delete word forward. */\nexport function deleteWordForward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockForward,\n\t\trange: (block, offset) => {\n\t\t\tconst len = getBlockLength(block);\n\t\t\treturn offset < len ? [offset, findWordBoundaryForward(block, offset)] : null;\n\t\t},\n\t});\n}\n\n/** Handles Cmd+Backspace: delete to start of line/block. */\nexport function deleteSoftLineBackward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockBackward,\n\t\trange: (_block, offset) => (offset > 0 ? [0, offset] : null),\n\t});\n}\n\n/** Handles Cmd+Delete: delete to end of line/block. */\nexport function deleteSoftLineForward(state: EditorState): Transaction | null {\n\treturn deleteInDirection(state, {\n\t\tmerge: mergeBlockForward,\n\t\trange: (block, offset) => {\n\t\t\tconst len = getBlockLength(block);\n\t\t\treturn offset < len ? [offset, len] : null;\n\t\t},\n\t});\n}\n","/**\n * Keyboard handler: intercepts keydown events for shortcuts.\n * Checks plugin-registered keymaps first, then falls back to built-in\n * structural shortcuts (undo, redo, select all) and NodeSelection navigation.\n *\n * Mark-specific shortcuts (Mod-B, Mod-I, Mod-U) are registered by\n * their respective plugins via keymaps, not hardcoded here.\n */\n\nimport {\n\tdeleteBackwardAtGap,\n\tdeleteForwardAtGap,\n\tdeleteNodeSelection,\n\tinsertTextCommand,\n\tnavigateArrowIntoVoid,\n\tselectAll,\n\tsplitBlockCommand,\n} from '../commands/Commands.js';\nimport { isGapCursor, isNodeSelection, selectionsEqual } from '../model/Selection.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { navigateFromGapCursor } from '../view/CaretNavigation.js';\nimport type { CompositionTracker } from './CompositionTracker.js';\nimport type { DispatchFn, GetStateFn, RedoFn, UndoFn } from './InputHandler.js';\nimport type { KeymapRegistry } from './KeymapRegistry.js';\n\nexport interface KeyboardHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tundo: UndoFn;\n\tredo: RedoFn;\n\tkeymapRegistry?: KeymapRegistry;\n\tisReadOnly?: () => boolean;\n\tcompositionTracker?: CompositionTracker;\n}\n\nexport class KeyboardHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly undo: UndoFn;\n\tprivate readonly redo: RedoFn;\n\tprivate readonly keymapRegistry?: KeymapRegistry;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate readonly compositionTracker?: CompositionTracker;\n\tprivate readonly handleKeydown: (e: KeyboardEvent) => void;\n\n\tconstructor(\n\t\tprivate readonly element: HTMLElement,\n\t\toptions: KeyboardHandlerOptions,\n\t) {\n\t\tthis.getState = options.getState;\n\t\tthis.dispatch = options.dispatch;\n\t\tthis.undo = options.undo;\n\t\tthis.redo = options.redo;\n\t\tthis.keymapRegistry = options.keymapRegistry;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\t\tthis.compositionTracker = options.compositionTracker;\n\n\t\tthis.handleKeydown = this.onKeydown.bind(this);\n\t\telement.addEventListener('keydown', this.handleKeydown);\n\t}\n\n\tprivate onKeydown(e: KeyboardEvent): void {\n\t\t// During IME composition, let the browser handle all keys\n\t\tif (this.compositionTracker?.isComposing) return;\n\n\t\t// Handle NodeSelection keys before plugin keymaps\n\t\tif (this.handleNodeSelectionKeys(e)) return;\n\n\t\t// Handle GapCursor keys (typing, Enter, Backspace, Delete)\n\t\tif (this.handleGapCursorKeys(e)) return;\n\n\t\t// Readonly mode: allow navigation keymaps + escape, block everything else\n\t\tif (this.isReadOnly()) {\n\t\t\tif (this.keymapRegistry) {\n\t\t\t\tconst descriptor: string = normalizeKeyDescriptor(e);\n\t\t\t\tconst navKeymaps = this.keymapRegistry.getKeymapsByPriority().navigation;\n\t\t\t\tfor (let i = navKeymaps.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst handler = navKeymaps[i]?.[descriptor];\n\t\t\t\t\tif (handler?.()) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.handleEscape(e)) return;\n\t\t\treturn;\n\t\t}\n\n\t\t// Normal mode: try plugin keymaps in priority order (context > navigation > default).\n\t\t// Within each priority, iterate in reverse so later-registered keymaps take precedence.\n\t\tif (this.keymapRegistry) {\n\t\t\tconst descriptor: string = normalizeKeyDescriptor(e);\n\t\t\tconst groups = this.keymapRegistry.getKeymapsByPriority();\n\t\t\tfor (const keymaps of [groups.context, groups.navigation, groups.default]) {\n\t\t\t\tfor (let i = keymaps.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst handler = keymaps[i]?.[descriptor];\n\t\t\t\t\tif (handler?.()) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// GapCursor arrow fallback: if no plugin keymap handled the arrow,\n\t\t// provide basic escape from GapCursor state.\n\t\tif (this.handleGapCursorArrowFallback(e)) return;\n\n\t\t// Tab fallback: insert tab character when no plugin handled it\n\t\tif (this.handleTab(e)) return;\n\n\t\t// Escape fallback: exit editor when no plugin handled it (WCAG 2.1.2)\n\t\tif (this.handleEscape(e)) return;\n\n\t\t// Fall back to built-in structural shortcuts\n\t\tconst mod = e.metaKey || e.ctrlKey;\n\t\tif (!mod) return;\n\n\t\tconst key = e.key.toLowerCase();\n\t\tconst state = this.getState();\n\t\tlet tr: Transaction | null = null;\n\n\t\tif (key === 'z' && !e.shiftKey) {\n\t\t\te.preventDefault();\n\t\t\tthis.undo();\n\t\t\treturn;\n\t\t}\n\n\t\tif ((key === 'z' && e.shiftKey) || (key === 'y' && !e.shiftKey)) {\n\t\t\te.preventDefault();\n\t\t\tthis.redo();\n\t\t\treturn;\n\t\t}\n\n\t\tif (key === 'a' && !e.shiftKey) {\n\t\t\te.preventDefault();\n\t\t\ttr = selectAll(state);\n\t\t}\n\n\t\tif (tr) {\n\t\t\tthis.dispatch(tr);\n\t\t}\n\t}\n\n\t/** Handles arrow keys, Enter, Backspace, Delete, Escape when a NodeSelection is active. */\n\tprivate handleNodeSelectionKeys(e: KeyboardEvent): boolean {\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return false;\n\n\t\tconst key = e.key;\n\n\t\t// Arrow keys: navigate away from NodeSelection (only unmodified arrows)\n\t\tif (\n\t\t\t(key === 'ArrowLeft' || key === 'ArrowUp' || key === 'ArrowRight' || key === 'ArrowDown') &&\n\t\t\t!e.shiftKey &&\n\t\t\t!e.metaKey &&\n\t\t\t!e.ctrlKey &&\n\t\t\t!e.altKey\n\t\t) {\n\t\t\tconst direction =\n\t\t\t\tkey === 'ArrowLeft'\n\t\t\t\t\t? 'left'\n\t\t\t\t\t: key === 'ArrowRight'\n\t\t\t\t\t\t? 'right'\n\t\t\t\t\t\t: key === 'ArrowUp'\n\t\t\t\t\t\t\t? 'up'\n\t\t\t\t\t\t\t: 'down';\n\t\t\tconst tr = navigateArrowIntoVoid(state, direction);\n\t\t\tif (tr) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// Backspace / Delete: remove the selected void block\n\t\tif (key === 'Backspace' || key === 'Delete') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr = deleteNodeSelection(state, sel);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Enter: insert paragraph after\n\t\tif (key === 'Enter') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr = splitBlockCommand(state);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Escape: move to start of next block\n\t\tif (key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\tconst tr = navigateArrowIntoVoid(state, 'right');\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Handles keyboard input when a GapCursor is active.\n\t *\n\t * Since the browser has no DOM selection at a GapCursor position,\n\t * no `beforeinput` events fire. This method intercepts printable\n\t * characters, Enter, Backspace, and Delete to dispatch the\n\t * corresponding editor commands.\n\t */\n\tprivate handleGapCursorKeys(e: KeyboardEvent): boolean {\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isGapCursor(sel)) return false;\n\n\t\tconst key: string = e.key;\n\n\t\t// Arrow keys: let GapCursorPlugin keymaps handle them\n\t\tif (key === 'ArrowLeft' || key === 'ArrowRight' || key === 'ArrowUp' || key === 'ArrowDown') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Escape / Tab: pass through\n\t\tif (key === 'Escape' || key === 'Tab') return false;\n\n\t\t// Modifier combos (Ctrl/Meta/Alt): let shortcuts like Ctrl+Z through\n\t\tif (e.ctrlKey || e.metaKey || e.altKey) return false;\n\n\t\t// Enter: insert paragraph at gap\n\t\tif (key === 'Enter') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr: Transaction | null = splitBlockCommand(state);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Backspace: delete backward at gap\n\t\tif (key === 'Backspace') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr: Transaction | null = deleteBackwardAtGap(state, sel);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Delete: delete forward at gap\n\t\tif (key === 'Delete') {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr: Transaction | null = deleteForwardAtGap(state, sel);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Printable characters: insert text in a new paragraph\n\t\tif (key.length === 1) {\n\t\t\tif (this.isReadOnly()) {\n\t\t\t\te.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\tconst tr: Transaction = insertTextCommand(state, key);\n\t\t\tthis.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Fallback arrow handler for GapCursor when no plugin keymap handled the arrow.\n\t * Provides basic escape from GapCursor state even without GapCursorPlugin.\n\t */\n\tprivate handleGapCursorArrowFallback(e: KeyboardEvent): boolean {\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isGapCursor(sel)) return false;\n\n\t\tconst key: string = e.key;\n\t\tif (key !== 'ArrowLeft' && key !== 'ArrowRight' && key !== 'ArrowUp' && key !== 'ArrowDown') {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst direction =\n\t\t\tkey === 'ArrowLeft'\n\t\t\t\t? 'left'\n\t\t\t\t: key === 'ArrowRight'\n\t\t\t\t\t? 'right'\n\t\t\t\t\t: key === 'ArrowUp'\n\t\t\t\t\t\t? 'up'\n\t\t\t\t\t\t: 'down';\n\t\tconst tr: Transaction | null = navigateFromGapCursor(state, direction);\n\t\tif (tr && !selectionsEqual(tr.selectionAfter, sel)) {\n\t\t\te.preventDefault();\n\t\t\tthis.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Inserts a tab character when Tab is pressed and no plugin handled it.\n\t * Shift-Tab is suppressed to prevent focus leaving the editor.\n\t */\n\tprivate handleTab(e: KeyboardEvent): boolean {\n\t\tif (e.key !== 'Tab') return false;\n\t\tif (e.metaKey || e.ctrlKey || e.altKey) return false;\n\n\t\te.preventDefault();\n\n\t\tif (e.shiftKey) return true;\n\n\t\tconst state = this.getState();\n\t\tconst tr: Transaction = insertTextCommand(state, '\\t');\n\t\tthis.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Exits the editor when Escape is pressed and no plugin handled it.\n\t * Satisfies WCAG 2.1.2 \"No Keyboard Trap\" — since Tab is intercepted\n\t * for indent/insert, Escape provides the keyboard exit mechanism.\n\t */\n\tprivate handleEscape(e: KeyboardEvent): boolean {\n\t\tif (e.key !== 'Escape') return false;\n\n\t\tthis.element.blur();\n\t\treturn true;\n\t}\n\n\tdestroy(): void {\n\t\tthis.element.removeEventListener('keydown', this.handleKeydown);\n\t}\n}\n\n/**\n * Normalizes a KeyboardEvent into a consistent key descriptor string.\n * Format: `\"Mod-Shift-Alt-Key\"` where Mod = Ctrl/Cmd.\n */\nexport function normalizeKeyDescriptor(e: KeyboardEvent): string {\n\tconst parts: string[] = [];\n\tif (e.metaKey || e.ctrlKey) parts.push('Mod');\n\tif (e.shiftKey) parts.push('Shift');\n\tif (e.altKey) parts.push('Alt');\n\n\tlet key = e.key;\n\t// Normalize common keys\n\tif (key === ' ') key = 'Space';\n\telse if (key.length === 1) key = key.toUpperCase();\n\t// For special keys like Enter, Tab, Backspace, keep as-is\n\n\tparts.push(key);\n\treturn parts.join('-');\n}\n","/**\n * MarkSerializer: shared mark serialization logic for DocumentSerializer and ClipboardHandler.\n * Separates style-based marks (merged into a single `<span style>`) from tag-based marks\n * (nested wrappers in rank order).\n */\n\nimport type { Mark } from '../model/Document.js';\nimport { escapeHTML } from '../model/HTMLUtils.js';\nimport type { MarkSpec } from '../model/MarkSpec.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { CSSClassCollector } from './CSSClassCollector.js';\n\n/** Builds a map of mark type name to rank from the registry (compute once per pass). */\nexport function buildMarkOrder(registry: SchemaRegistry): Map<string, number> {\n\tconst types: readonly string[] = registry.getMarkTypes();\n\tconst order = new Map<string, number>();\n\tfor (const t of types) {\n\t\tconst spec: MarkSpec | undefined = registry.getMarkSpec(t);\n\t\tif (spec) order.set(t, spec.rank ?? 99);\n\t}\n\treturn order;\n}\n\n/**\n * Serializes text with marks to HTML.\n * Style-based marks (`toHTMLStyle`) are merged into a single `<span style=\"...\">`.\n * Tag-based marks (`toHTMLString`) wrap the content in rank order.\n */\nexport function serializeMarksToHTML(\n\ttext: string,\n\tmarks: readonly Mark[],\n\tregistry: SchemaRegistry,\n\tmarkOrder?: Map<string, number>,\n): string {\n\tif (text === '') return '';\n\n\tlet html: string = escapeHTML(text);\n\n\tif (marks.length === 0) return html;\n\n\tconst order: Map<string, number> = markOrder ?? buildMarkOrder(registry);\n\tconst sortedMarks: Mark[] = [...marks].sort(\n\t\t(a, b) => (order.get(a.type) ?? 99) - (order.get(b.type) ?? 99),\n\t);\n\n\tconst styleParts: string[] = [];\n\tconst tagMarks: Mark[] = [];\n\n\tfor (const mark of sortedMarks) {\n\t\tconst markSpec: MarkSpec | undefined = registry.getMarkSpec(mark.type);\n\t\tif (markSpec?.toHTMLStyle) {\n\t\t\tconst style: string | null = markSpec.toHTMLStyle(mark);\n\t\t\tif (style) {\n\t\t\t\tstyleParts.push(style);\n\t\t\t}\n\t\t} else {\n\t\t\ttagMarks.push(mark);\n\t\t}\n\t}\n\n\t// Wrap with merged style span first (closest to text)\n\tif (styleParts.length > 0) {\n\t\thtml = `<span style=\"${styleParts.join('; ')}\">${html}</span>`;\n\t}\n\n\t// Then wrap with tag-based marks in rank order\n\tfor (const mark of tagMarks) {\n\t\tconst markSpec: MarkSpec | undefined = registry.getMarkSpec(mark.type);\n\t\tif (markSpec?.toHTMLString) {\n\t\t\thtml = markSpec.toHTMLString(mark, html);\n\t\t}\n\t}\n\n\treturn html;\n}\n\n/**\n * Serializes text with marks to HTML using CSS class names instead of inline styles.\n * Style-based marks (`toHTMLStyle`) are collected into a `CSSClassCollector` and emitted\n * as `<span class=\"...\">`. Tag-based marks (`toHTMLString`) wrap identically to the inline path.\n */\nexport function serializeMarksToClassHTML(\n\ttext: string,\n\tmarks: readonly Mark[],\n\tregistry: SchemaRegistry,\n\tcollector: CSSClassCollector,\n\tmarkOrder?: Map<string, number>,\n): string {\n\tif (text === '') return '';\n\n\tlet html: string = escapeHTML(text);\n\n\tif (marks.length === 0) return html;\n\n\tconst order: Map<string, number> = markOrder ?? buildMarkOrder(registry);\n\tconst sortedMarks: Mark[] = [...marks].sort(\n\t\t(a, b) => (order.get(a.type) ?? 99) - (order.get(b.type) ?? 99),\n\t);\n\n\tconst styleParts: string[] = [];\n\tconst tagMarks: Mark[] = [];\n\n\tfor (const mark of sortedMarks) {\n\t\tconst markSpec: MarkSpec | undefined = registry.getMarkSpec(mark.type);\n\t\tif (markSpec?.toHTMLStyle) {\n\t\t\tconst style: string | null = markSpec.toHTMLStyle(mark);\n\t\t\tif (style) {\n\t\t\t\tstyleParts.push(style);\n\t\t\t}\n\t\t} else {\n\t\t\ttagMarks.push(mark);\n\t\t}\n\t}\n\n\t// Wrap with class-based span (closest to text)\n\tif (styleParts.length > 0) {\n\t\tconst declarations: string = styleParts.join('; ');\n\t\tconst className: string = collector.getClassName(declarations);\n\t\thtml = `<span class=\"${className}\">${html}</span>`;\n\t}\n\n\t// Then wrap with tag-based marks in rank order\n\tfor (const mark of tagMarks) {\n\t\tconst markSpec: MarkSpec | undefined = registry.getMarkSpec(mark.type);\n\t\tif (markSpec?.toHTMLString) {\n\t\t\thtml = markSpec.toHTMLString(mark, html);\n\t\t}\n\t}\n\n\treturn html;\n}\n","/**\n * In-memory clipboard for rich block data that cannot survive the system\n * clipboard (which only preserves standard MIME types like text/plain\n * and text/html). This store is keyed by the plain-text content so that\n * a paste event can verify the text matches before using the rich data.\n */\n\n/** A serialized block from a text-selection copy. */\nexport interface RichBlockData {\n\treadonly type: string;\n\treadonly text: string;\n\treadonly attrs?: Record<string, unknown>;\n}\n\ninterface RichClipboardEntry {\n\treadonly plainText: string;\n\treadonly blocks: readonly RichBlockData[];\n}\n\nlet current: RichClipboardEntry | undefined;\n\n/** Stores rich block data alongside its plain-text fingerprint. */\nexport function setRichClipboard(plainText: string, blocks: readonly RichBlockData[]): void {\n\tcurrent = { plainText, blocks };\n}\n\n/**\n * Returns rich block data if the given plain text matches the stored\n * fingerprint (proving it came from our editor, not an external source).\n * Consumes the entry to prevent stale reuse.\n */\nexport function consumeRichClipboard(plainText: string): readonly RichBlockData[] | undefined {\n\tif (!current) return undefined;\n\tif (current.plainText !== plainText) return undefined;\n\tconst blocks = current.blocks;\n\t// Don't clear — allow multiple pastes from same copy\n\treturn blocks;\n}\n\n/** Clears the stored rich clipboard data. */\nexport function clearRichClipboard(): void {\n\tcurrent = undefined;\n}\n","/**\n * Clipboard handler: intercepts copy and cut events, serializes the current\n * selection to clipboard data. Works with both NodeSelection (void blocks)\n * and text selections.\n */\n\nimport { deleteNodeSelection, deleteSelectionCommand } from '../commands/Commands.js';\nimport { buildMarkOrder, serializeMarksToHTML } from '../editor/MarkSerializer.js';\nimport type { BlockNode } from '../model/Document.js';\nimport {\n\tgetBlockLength,\n\tgetBlockText,\n\tgetInlineChildren,\n\tisInlineNode,\n\tisTextNode,\n} from '../model/Document.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport {\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n\tisTextSelection,\n\tselectionRange,\n} from '../model/Selection.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { DispatchFn, GetStateFn } from './InputHandler.js';\nimport { setRichClipboard } from './InternalClipboard.js';\n\nexport interface ClipboardHandlerOptions {\n\treadonly getState: GetStateFn;\n\treadonly dispatch: DispatchFn;\n\treadonly schemaRegistry?: SchemaRegistry;\n\t/** Force-sync DOM selection to state (selectionchange may fire async). */\n\treadonly syncSelection?: () => void;\n\treadonly isReadOnly?: () => boolean;\n}\n\n/** Custom MIME type for internal block copy/paste round-trips (void/NodeSelection). */\nconst BLOCK_MIME = 'application/x-notectl-block';\n\nexport class ClipboardHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate readonly syncSelection?: () => void;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate readonly handleCopy: (e: ClipboardEvent) => void;\n\tprivate readonly handleCut: (e: ClipboardEvent) => void;\n\n\tconstructor(\n\t\tprivate readonly element: HTMLElement,\n\t\toptions: ClipboardHandlerOptions,\n\t) {\n\t\tthis.getState = options.getState;\n\t\tthis.dispatch = options.dispatch;\n\t\tthis.schemaRegistry = options.schemaRegistry;\n\t\tthis.syncSelection = options.syncSelection;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\n\t\tthis.handleCopy = this.onCopy.bind(this);\n\t\tthis.handleCut = this.onCut.bind(this);\n\t\telement.addEventListener('copy', this.handleCopy);\n\t\telement.addEventListener('cut', this.handleCut);\n\t}\n\n\tprivate onCopy(e: ClipboardEvent): void {\n\t\t// Sync DOM selection → state first; selectionchange may lag behind\n\t\tthis.syncSelection?.();\n\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\n\t\t// GapCursor: nothing to copy\n\t\tif (isGapCursor(sel)) return;\n\n\t\t// Collapsed selection: let the browser handle it\n\t\tif (isTextSelection(sel) && isCollapsed(sel)) return;\n\n\t\te.preventDefault();\n\t\tconst clipboardData = e.clipboardData;\n\t\tif (!clipboardData) return;\n\n\t\tif (isNodeSelection(sel)) {\n\t\t\tthis.writeNodeSelectionToClipboard(clipboardData, state);\n\t\t} else {\n\t\t\tthis.writeTextSelectionToClipboard(clipboardData, state);\n\t\t}\n\t}\n\n\tprivate onCut(e: ClipboardEvent): void {\n\t\tif (this.isReadOnly()) return;\n\n\t\t// Sync DOM selection → state first; selectionchange may lag behind\n\t\tthis.syncSelection?.();\n\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\n\t\t// GapCursor: nothing to cut\n\t\tif (isGapCursor(sel)) return;\n\n\t\t// Collapsed selection: nothing to cut\n\t\tif (isTextSelection(sel) && isCollapsed(sel)) return;\n\n\t\te.preventDefault();\n\t\tconst clipboardData = e.clipboardData;\n\t\tif (!clipboardData) return;\n\n\t\t// Write to clipboard first\n\t\tif (isNodeSelection(sel)) {\n\t\t\tthis.writeNodeSelectionToClipboard(clipboardData, state);\n\t\t\tconst tr = deleteNodeSelection(state, sel);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t} else {\n\t\t\tthis.writeTextSelectionToClipboard(clipboardData, state);\n\t\t\tconst tr = deleteSelectionCommand(state);\n\t\t\tif (tr) this.dispatch(tr);\n\t\t}\n\t}\n\n\tprivate writeNodeSelectionToClipboard(clipboardData: DataTransfer, state: EditorState): void {\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\n\t\tconst block = state.getBlock(sel.nodeId);\n\t\tif (!block) return;\n\n\t\t// Internal format: block type + attrs for round-trip paste\n\t\tconst blockData: { readonly type: string; readonly attrs?: Record<string, unknown> } = {\n\t\t\ttype: block.type,\n\t\t\t...(block.attrs ? { attrs: { ...block.attrs } } : {}),\n\t\t};\n\t\tclipboardData.setData(BLOCK_MIME, JSON.stringify(blockData));\n\n\t\t// HTML representation via NodeSpec.toHTML if available\n\t\tconst spec = this.schemaRegistry?.getNodeSpec(block.type);\n\t\tif (spec?.toHTML) {\n\t\t\tclipboardData.setData('text/html', spec.toHTML(block, ''));\n\t\t}\n\n\t\t// Plain text: use alt text for images, empty for other voids\n\t\tconst attrs = block.attrs as Record<string, unknown> | undefined;\n\t\tconst altText: string = typeof attrs?.alt === 'string' ? attrs.alt : '';\n\t\tclipboardData.setData('text/plain', altText);\n\t}\n\n\tprivate writeTextSelectionToClipboard(clipboardData: DataTransfer, state: EditorState): void {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return;\n\t\tif (isGapCursor(sel)) return;\n\t\tif (isCollapsed(sel)) return;\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t\tconst lines: string[] = [];\n\t\tconst richBlocks: Array<{\n\t\t\ttype: string;\n\t\t\ttext: string;\n\t\t\tattrs?: Record<string, unknown>;\n\t\t}> = [];\n\n\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\tconst bid = blockOrder[i];\n\t\t\tif (!bid) continue;\n\t\t\tconst block = state.getBlock(bid);\n\t\t\tif (!block) continue;\n\n\t\t\tconst text = getBlockText(block);\n\t\t\tconst blockLen = getBlockLength(block);\n\t\t\tconst start = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst end = i === toIdx ? range.to.offset : blockLen;\n\t\t\tconst sliced: string = text.slice(start, end);\n\t\t\tlines.push(sliced);\n\n\t\t\trichBlocks.push({\n\t\t\t\ttype: block.type,\n\t\t\t\ttext: sliced,\n\t\t\t\t...(block.attrs ? { attrs: { ...block.attrs } } : {}),\n\t\t\t});\n\t\t}\n\n\t\tconst plainText: string = lines.join('\\n');\n\t\tclipboardData.setData('text/plain', plainText);\n\n\t\t// Write text/html with inline marks so paste preserves formatting\n\t\tif (this.schemaRegistry) {\n\t\t\tconst markOrder: Map<string, number> = buildMarkOrder(this.schemaRegistry);\n\t\t\tconst htmlParts: string[] = [];\n\t\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\t\tconst bid = blockOrder[i];\n\t\t\t\tif (!bid) continue;\n\t\t\t\tconst block = state.getBlock(bid);\n\t\t\t\tif (!block) continue;\n\n\t\t\t\tconst start = i === fromIdx ? range.from.offset : 0;\n\t\t\t\tconst end = i === toIdx ? range.to.offset : getBlockLength(block);\n\t\t\t\thtmlParts.push(this.serializeBlockRangeToHTML(block, start, end, markOrder));\n\t\t\t}\n\t\t\tclipboardData.setData('text/html', htmlParts.join(''));\n\t\t}\n\n\t\t// Store rich block data in memory — system clipboard strips custom MIME\n\t\t// types and rewrites text/html, so we use an in-memory store keyed by\n\t\t// the plain-text fingerprint to verify origin on paste.\n\t\tsetRichClipboard(plainText, richBlocks);\n\t}\n\n\t/** Serializes a range of inline content within a block to an HTML string. */\n\tprivate serializeBlockRangeToHTML(\n\t\tblock: BlockNode,\n\t\tstart: number,\n\t\tend: number,\n\t\tmarkOrder?: Map<string, number>,\n\t): string {\n\t\tconst children = getInlineChildren(block);\n\t\tconst parts: string[] = [];\n\t\tlet pos = 0;\n\n\t\tfor (const child of children) {\n\t\t\tconst width: number = isInlineNode(child) ? 1 : child.text.length;\n\t\t\tconst childEnd: number = pos + width;\n\n\t\t\tif (childEnd <= start || pos >= end) {\n\t\t\t\tpos = childEnd;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (isTextNode(child)) {\n\t\t\t\tconst sliceFrom: number = Math.max(0, start - pos);\n\t\t\t\tconst sliceTo: number = Math.min(child.text.length, end - pos);\n\t\t\t\tconst text: string = child.text.slice(sliceFrom, sliceTo);\n\t\t\t\tif (text.length > 0 && this.schemaRegistry) {\n\t\t\t\t\tparts.push(serializeMarksToHTML(text, child.marks, this.schemaRegistry, markOrder));\n\t\t\t\t}\n\t\t\t} else if (isInlineNode(child)) {\n\t\t\t\tconst spec = this.schemaRegistry?.getInlineNodeSpec(child.inlineType);\n\t\t\t\tif (spec?.toHTMLString) {\n\t\t\t\t\tparts.push(spec.toHTMLString(child));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpos = childEnd;\n\t\t}\n\n\t\treturn parts.join('');\n\t}\n\n\tdestroy(): void {\n\t\tthis.element.removeEventListener('copy', this.handleCopy);\n\t\tthis.element.removeEventListener('cut', this.handleCut);\n\t}\n}\n","/**\n * Centralized composition state tracker.\n * Exposes the current IME composition status so that KeyboardHandler,\n * SelectionSync, and Reconciler can guard against DOM mutations\n * that would break an active browser composition session.\n */\n\nimport type { BlockId } from '../model/TypeBrands.js';\n\nexport class CompositionTracker {\n\tprivate _composing = false;\n\tprivate _activeBlockId: BlockId | null = null;\n\n\t/** Whether an IME composition session is currently active. */\n\tget isComposing(): boolean {\n\t\treturn this._composing;\n\t}\n\n\t/** The block in which the composition is happening, or null if idle. */\n\tget activeBlockId(): BlockId | null {\n\t\treturn this._activeBlockId;\n\t}\n\n\t/** Marks the start of a composition session in the given block. */\n\tstart(blockId: BlockId): void {\n\t\tthis._composing = true;\n\t\tthis._activeBlockId = blockId;\n\t}\n\n\t/** Marks the end of a composition session. */\n\tend(): void {\n\t\tthis._composing = false;\n\t\tthis._activeBlockId = null;\n\t}\n}\n","/**\n * KeymapRegistry: manages plugin-registered keyboard shortcuts\n * with a 3-priority system (context > navigation > default).\n */\n\nimport type { Keymap, KeymapOptions, KeymapPriority } from './Keymap.js';\n\nexport class KeymapRegistry {\n\tprivate readonly _contextKeymaps: Keymap[] = [];\n\tprivate readonly _navigationKeymaps: Keymap[] = [];\n\tprivate readonly _defaultKeymaps: Keymap[] = [];\n\n\tregisterKeymap(keymap: Keymap, options?: KeymapOptions): void {\n\t\tconst allKeymaps: Keymap[] = [\n\t\t\t...this._contextKeymaps,\n\t\t\t...this._navigationKeymaps,\n\t\t\t...this._defaultKeymaps,\n\t\t];\n\t\tfor (const key of Object.keys(keymap)) {\n\t\t\tfor (const existing of allKeymaps) {\n\t\t\t\tif (key in existing) {\n\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t`[notectl] Keymap shortcut \"${key}\" is already registered and will be overridden.`,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.keymapArrayForPriority(options?.priority ?? 'default').push(keymap);\n\t}\n\n\t/** Returns all keymaps in priority order: context > navigation > default. */\n\tgetKeymaps(): readonly Keymap[] {\n\t\treturn [...this._contextKeymaps, ...this._navigationKeymaps, ...this._defaultKeymaps];\n\t}\n\n\t/** Returns keymaps grouped by priority level (defensive copies). */\n\tgetKeymapsByPriority(): {\n\t\treadonly context: readonly Keymap[];\n\t\treadonly navigation: readonly Keymap[];\n\t\treadonly default: readonly Keymap[];\n\t} {\n\t\treturn {\n\t\t\tcontext: [...this._contextKeymaps],\n\t\t\tnavigation: [...this._navigationKeymaps],\n\t\t\tdefault: [...this._defaultKeymaps],\n\t\t};\n\t}\n\n\tremoveKeymap(keymap: Keymap): void {\n\t\tfor (const arr of [this._contextKeymaps, this._navigationKeymaps, this._defaultKeymaps]) {\n\t\t\tconst idx: number = arr.indexOf(keymap);\n\t\t\tif (idx !== -1) {\n\t\t\t\tarr.splice(idx, 1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis._contextKeymaps.length = 0;\n\t\tthis._navigationKeymaps.length = 0;\n\t\tthis._defaultKeymaps.length = 0;\n\t}\n\n\tprivate keymapArrayForPriority(priority: KeymapPriority): Keymap[] {\n\t\tswitch (priority) {\n\t\t\tcase 'context':\n\t\t\t\treturn this._contextKeymaps;\n\t\t\tcase 'navigation':\n\t\t\t\treturn this._navigationKeymaps;\n\t\t\tcase 'default':\n\t\t\t\treturn this._defaultKeymaps;\n\t\t}\n\t}\n}\n","/**\n * InputRuleRegistry: manages plugin-registered input rules\n * (pattern-based text transformations triggered on text input).\n */\n\nimport type { InputRule } from './InputRule.js';\n\nexport class InputRuleRegistry {\n\tprivate readonly _inputRules: InputRule[] = [];\n\n\tregisterInputRule(rule: InputRule): void {\n\t\tthis._inputRules.push(rule);\n\t}\n\n\tgetInputRules(): readonly InputRule[] {\n\t\treturn this._inputRules;\n\t}\n\n\tremoveInputRule(rule: InputRule): void {\n\t\tconst idx = this._inputRules.indexOf(rule);\n\t\tif (idx !== -1) this._inputRules.splice(idx, 1);\n\t}\n\n\tclear(): void {\n\t\tthis._inputRules.length = 0;\n\t}\n}\n","/**\n * FileHandlerRegistry: manages plugin-registered file handlers\n * for paste and drop operations, with MIME pattern matching.\n */\n\nimport type { Position } from '../model/Selection.js';\n\n/** Handler for a single file pasted or dropped into the editor. */\nexport type FileHandler = (file: File, position: Position | null) => boolean | Promise<boolean>;\n\nexport interface FileHandlerEntry {\n\treadonly pattern: string;\n\treadonly handler: FileHandler;\n}\n\nexport class FileHandlerRegistry {\n\tprivate readonly _fileHandlers: FileHandlerEntry[] = [];\n\n\tregisterFileHandler(pattern: string, handler: FileHandler): void {\n\t\tthis._fileHandlers.push({ pattern, handler });\n\t}\n\n\tgetFileHandlers(): readonly FileHandlerEntry[] {\n\t\treturn this._fileHandlers;\n\t}\n\n\tmatchFileHandlers(mimeType: string): FileHandler[] {\n\t\tconst handlers: FileHandler[] = [];\n\t\tfor (const entry of this._fileHandlers) {\n\t\t\tif (matchMimePattern(entry.pattern, mimeType)) {\n\t\t\t\thandlers.push(entry.handler);\n\t\t\t}\n\t\t}\n\t\treturn handlers;\n\t}\n\n\tremoveFileHandler(handler: FileHandler): void {\n\t\tconst idx = this._fileHandlers.findIndex((e) => e.handler === handler);\n\t\tif (idx !== -1) this._fileHandlers.splice(idx, 1);\n\t}\n\n\tclear(): void {\n\t\tthis._fileHandlers.length = 0;\n\t}\n}\n\n/** Matches a MIME pattern (e.g. 'image/*') against a concrete MIME type. */\nfunction matchMimePattern(pattern: string, mimeType: string): boolean {\n\tif (pattern === '*' || pattern === '*/*') return true;\n\tif (pattern === mimeType) return true;\n\tif (pattern.endsWith('/*')) {\n\t\tconst prefix = pattern.slice(0, -1);\n\t\treturn mimeType.startsWith(prefix);\n\t}\n\treturn false;\n}\n","/**\n * NodeViewRegistry: manages plugin-registered custom NodeView factories\n * for block-level rendering.\n */\n\nimport type { NodeViewFactory } from './NodeView.js';\n\nexport class NodeViewRegistry {\n\tprivate readonly _nodeViews = new Map<string, NodeViewFactory>();\n\n\tregisterNodeView(type: string, factory: NodeViewFactory): void {\n\t\tif (this._nodeViews.has(type)) {\n\t\t\tthrow new Error(`NodeView for type \"${type}\" is already registered.`);\n\t\t}\n\t\tthis._nodeViews.set(type, factory);\n\t}\n\n\tgetNodeViewFactory(type: string): NodeViewFactory | undefined {\n\t\treturn this._nodeViews.get(type);\n\t}\n\n\tremoveNodeView(type: string): void {\n\t\tthis._nodeViews.delete(type);\n\t}\n\n\tclear(): void {\n\t\tthis._nodeViews.clear();\n\t}\n}\n","/**\n * ToolbarRegistry: manages plugin-registered toolbar items\n * with per-plugin tracking for clean teardown.\n */\n\nimport type { ToolbarItem } from './ToolbarItem.js';\n\nexport class ToolbarRegistry {\n\tprivate readonly _toolbarItems = new Map<string, ToolbarItem>();\n\tprivate readonly _toolbarItemPluginMap = new Map<string, string[]>();\n\n\tregisterToolbarItem(item: ToolbarItem, pluginId?: string): void {\n\t\tif (this._toolbarItems.has(item.id)) {\n\t\t\tthrow new Error(`ToolbarItem with id \"${item.id}\" is already registered.`);\n\t\t}\n\t\tthis._toolbarItems.set(item.id, item);\n\t\tif (pluginId) {\n\t\t\tconst ids = this._toolbarItemPluginMap.get(pluginId) ?? [];\n\t\t\tids.push(item.id);\n\t\t\tthis._toolbarItemPluginMap.set(pluginId, ids);\n\t\t}\n\t}\n\n\tgetToolbarItemsByPlugin(pluginId: string): ToolbarItem[] {\n\t\tconst ids = this._toolbarItemPluginMap.get(pluginId) ?? [];\n\t\tconst items: ToolbarItem[] = [];\n\t\tfor (const id of ids) {\n\t\t\tconst item = this._toolbarItems.get(id);\n\t\t\tif (item) items.push(item);\n\t\t}\n\t\treturn items;\n\t}\n\n\tgetToolbarItem(id: string): ToolbarItem | undefined {\n\t\treturn this._toolbarItems.get(id);\n\t}\n\n\tgetToolbarItems(): ToolbarItem[] {\n\t\treturn [...this._toolbarItems.values()];\n\t}\n\n\tremoveToolbarItem(id: string): void {\n\t\tthis._toolbarItems.delete(id);\n\t\tfor (const [pluginId, ids] of this._toolbarItemPluginMap) {\n\t\t\tconst idx = ids.indexOf(id);\n\t\t\tif (idx !== -1) {\n\t\t\t\tids.splice(idx, 1);\n\t\t\t\tif (ids.length === 0) this._toolbarItemPluginMap.delete(pluginId);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis._toolbarItems.clear();\n\t\tthis._toolbarItemPluginMap.clear();\n\t}\n}\n","/**\n * BlockTypePickerRegistry: manages plugin-registered block type picker entries\n * displayed in the heading/block type dropdown, sorted by priority.\n */\n\nimport type { BlockTypePickerEntry } from './BlockTypePickerEntry.js';\n\nexport class BlockTypePickerRegistry {\n\tprivate readonly _entries = new Map<string, BlockTypePickerEntry>();\n\n\tregisterBlockTypePickerEntry(entry: BlockTypePickerEntry): void {\n\t\tif (this._entries.has(entry.id)) {\n\t\t\tthrow new Error(`BlockTypePickerEntry with id \"${entry.id}\" is already registered.`);\n\t\t}\n\t\tthis._entries.set(entry.id, entry);\n\t}\n\n\tgetBlockTypePickerEntries(): readonly BlockTypePickerEntry[] {\n\t\treturn [...this._entries.values()].sort((a, b) => a.priority - b.priority);\n\t}\n\n\tremoveBlockTypePickerEntry(id: string): void {\n\t\tthis._entries.delete(id);\n\t}\n\n\tclear(): void {\n\t\tthis._entries.clear();\n\t}\n}\n","/**\n * Shared mark rendering utilities used by Reconciler and CursorWrapper.\n *\n * Provides mark rank ordering and DOM element creation for marks,\n * using the SchemaRegistry when available and falling back to\n * built-in defaults.\n */\n\nimport type { MarkAttrsFor } from '../model/AttrRegistry.js';\nimport type { Mark } from '../model/Document.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\n\n/** Returns the rank for a mark (lower = outermost in the DOM nesting). */\nexport function getMarkRank(mark: Mark, registry?: SchemaRegistry): number {\n\tif (registry) {\n\t\tconst spec = registry.getMarkSpec(mark.type);\n\t\tif (spec) return spec.rank ?? 100;\n\t}\n\tswitch (mark.type) {\n\t\tcase 'bold':\n\t\t\treturn 0;\n\t\tcase 'italic':\n\t\t\treturn 1;\n\t\tcase 'underline':\n\t\t\treturn 2;\n\t\tdefault:\n\t\t\treturn 100;\n\t}\n}\n\n/** Creates a DOM element for a mark, using the registry spec or a built-in fallback. */\nexport function createMarkElement(mark: Mark, registry?: SchemaRegistry): HTMLElement {\n\tif (registry) {\n\t\tconst spec = registry.getMarkSpec(mark.type);\n\t\tif (spec) {\n\t\t\treturn spec.toDOM(mark as Omit<Mark, 'attrs'> & { readonly attrs: MarkAttrsFor<string> });\n\t\t}\n\t}\n\tswitch (mark.type) {\n\t\tcase 'bold':\n\t\t\treturn document.createElement('strong');\n\t\tcase 'italic':\n\t\t\treturn document.createElement('em');\n\t\tcase 'underline':\n\t\t\treturn document.createElement('u');\n\t\tdefault:\n\t\t\treturn document.createElement('span');\n\t}\n}\n","/**\n * CursorWrapper: creates a temporary mark-wrapped DOM element during IME\n * composition so that composed text inherits the stored marks (e.g. bold).\n *\n * Without this, toggling Bold with a collapsed cursor and then starting an\n * IME composition would produce unformatted text because the browser has no\n * formatted DOM node to compose into.\n *\n * The wrapper is a `<span data-cursor-wrapper>` containing a zero-width space\n * (`\\u200B`), nested inside mark elements matching the stored marks.\n */\n\nimport type { Mark } from '../model/Document.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { isCollapsed, isGapCursor, isNodeSelection } from '../model/Selection.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport { createMarkElement, getMarkRank } from './MarkRendering.js';\nimport { getSelection } from './SelectionSync.js';\n\nconst ZWS = '\\u200B';\nconst CURSOR_WRAPPER_ATTR = 'data-cursor-wrapper';\n\nexport class CursorWrapper {\n\tprivate wrapperElement: HTMLElement | null = null;\n\tprivate readonly container: HTMLElement;\n\tprivate readonly registry: SchemaRegistry | undefined;\n\n\tconstructor(container: HTMLElement, registry?: SchemaRegistry) {\n\t\tthis.container = container;\n\t\tthis.registry = registry;\n\t}\n\n\t/** Whether a cursor wrapper is currently in the DOM. */\n\tget isActive(): boolean {\n\t\treturn this.wrapperElement !== null;\n\t}\n\n\t/**\n\t * Creates a mark-wrapped cursor element if storedMarks are present.\n\t * Places the browser cursor inside the ZWS text node so that IME\n\t * composition inherits the mark formatting.\n\t */\n\tonCompositionStart(state: EditorState): void {\n\t\tthis.cleanup();\n\n\t\tconst marks: readonly Mark[] | null = state.storedMarks;\n\t\tif (!marks || marks.length === 0) return;\n\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return;\n\t\tif (!isCollapsed(sel)) return;\n\n\t\t// Build the wrapper: <span data-cursor-wrapper>ZWS</span>\n\t\tconst wrapper: HTMLElement = document.createElement('span');\n\t\twrapper.setAttribute(CURSOR_WRAPPER_ATTR, '');\n\t\tconst textNode: Text = document.createTextNode(ZWS);\n\n\t\t// Wrap the text node in sorted mark elements (innermost → outermost)\n\t\tlet current: Node = textNode;\n\t\tconst sortedMarks: readonly Mark[] = [...marks].sort(\n\t\t\t(a, b) => getMarkRank(a, this.registry) - getMarkRank(b, this.registry),\n\t\t);\n\n\t\tfor (let i: number = sortedMarks.length - 1; i >= 0; i--) {\n\t\t\tconst mark: Mark | undefined = sortedMarks[i];\n\t\t\tif (!mark) continue;\n\t\t\tconst el: HTMLElement = createMarkElement(mark, this.registry);\n\t\t\tel.appendChild(current);\n\t\t\tcurrent = el;\n\t\t}\n\n\t\twrapper.appendChild(current);\n\n\t\t// Insert at the current DOM cursor position\n\t\tconst domSel: globalThis.Selection | null = getSelection(this.container);\n\t\tif (!domSel || domSel.rangeCount === 0) return;\n\n\t\tconst range: Range = domSel.getRangeAt(0);\n\t\trange.insertNode(wrapper);\n\n\t\t// Place browser cursor inside the ZWS text node\n\t\ttry {\n\t\t\tdomSel.collapse(textNode, textNode.length);\n\t\t} catch {\n\t\t\t// May fail in test environments\n\t\t}\n\n\t\tthis.wrapperElement = wrapper;\n\t}\n\n\t/** Removes the wrapper element from the DOM. */\n\tcleanup(): void {\n\t\tif (!this.wrapperElement) return;\n\t\tthis.wrapperElement.remove();\n\t\tthis.wrapperElement = null;\n\t}\n}\n","/**\n * Pure functions that attach WAI-ARIA keyboard patterns to popup containers.\n * Supports menu, listbox, and grid navigation patterns.\n * Delegates to ToolbarKeyboardNav for shared navigation logic.\n */\n\nimport {\n\tapplyRovingTabindex,\n\tfindNextDropdownItem,\n\tnavigateGrid,\n} from '../toolbar/ToolbarKeyboardNav.js';\n\n// --- Types ---\n\nexport interface MenuKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly itemSelector: string;\n\treadonly onActivate: (item: HTMLElement) => void;\n\treadonly onClose: () => void;\n\treadonly getActiveElement: () => Element | null;\n}\n\nexport interface ListboxKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly itemSelector: string;\n\treadonly onSelect: (item: HTMLElement) => void;\n\treadonly onClose: () => void;\n}\n\nexport interface GridKeyboardConfig {\n\treadonly container: HTMLElement;\n\treadonly cellSelector: string;\n\treadonly columns: number;\n\treadonly totalCells: number;\n\treadonly onSelect: (cell: HTMLElement) => void;\n\treadonly onClose: () => void;\n\treadonly onNavigate?: (index: number) => void;\n}\n\n// --- Constants ---\n\nconst GRID_NAV_KEYS: ReadonlySet<string> = new Set([\n\t'ArrowUp',\n\t'ArrowDown',\n\t'ArrowLeft',\n\t'ArrowRight',\n]);\n\n// --- Menu Keyboard ---\n\n/**\n * Attaches menu keyboard navigation (ArrowUp/Down, Enter/Space, Home/End, Escape).\n * Returns a cleanup function that removes the event listener.\n */\nexport function attachMenuKeyboard(config: MenuKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\te.stopPropagation();\n\t\tconst items: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.itemSelector),\n\t\t) as HTMLElement[];\n\t\tif (items.length === 0) return;\n\n\t\tswitch (e.key) {\n\t\t\tcase 'Escape': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconfig.onClose();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, 1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, -1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst item: HTMLElement | undefined = items[focusedIndex];\n\t\t\t\tif (item) config.onActivate(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Home': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = 0;\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'End': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = items.length - 1;\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n\n// --- Listbox Keyboard ---\n\n/**\n * Attaches listbox keyboard navigation (ArrowUp/Down, Enter/Space, Escape).\n * Returns a cleanup function.\n */\nexport function attachListboxKeyboard(config: ListboxKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\tconst items: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.itemSelector),\n\t\t) as HTMLElement[];\n\t\tif (items.length === 0) return;\n\n\t\tswitch (e.key) {\n\t\t\tcase 'Escape': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconfig.onClose();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, 1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tfocusedIndex = findNextDropdownItem(items, focusedIndex, -1);\n\t\t\t\tapplyRovingTabindex(items as HTMLButtonElement[], focusedIndex);\n\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst item: HTMLElement | undefined = items[focusedIndex];\n\t\t\t\tif (item) config.onSelect(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n\n// --- Grid Keyboard ---\n\n/**\n * Attaches grid keyboard navigation (2D arrows, Home/End per row, Enter/Space, Escape).\n * Returns a cleanup function.\n */\nexport function attachGridKeyboard(config: GridKeyboardConfig): () => void {\n\tlet focusedIndex = 0;\n\tconst columns: number = config.columns;\n\tconst totalCells: number = config.totalCells;\n\tconst totalRows: number = Math.ceil(totalCells / columns);\n\n\tconst handler = (e: KeyboardEvent): void => {\n\t\tconst cells: HTMLElement[] = Array.from(\n\t\t\tconfig.container.querySelectorAll(config.cellSelector),\n\t\t) as HTMLElement[];\n\t\tif (cells.length === 0) return;\n\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\tconfig.onClose();\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\te.preventDefault();\n\t\t\tconst cell: HTMLElement | undefined = cells[focusedIndex];\n\t\t\tif (cell) config.onSelect(cell);\n\t\t\treturn;\n\t\t}\n\n\t\tif (GRID_NAV_KEYS.has(e.key)) {\n\t\t\te.preventDefault();\n\t\t\tconst currentRow: number = Math.floor(focusedIndex / columns) + 1;\n\t\t\tconst currentCol: number = (focusedIndex % columns) + 1;\n\n\t\t\tconst [newRow, newCol] = navigateGrid(\n\t\t\t\tcurrentRow,\n\t\t\t\tcurrentCol,\n\t\t\t\ttotalRows,\n\t\t\t\tcolumns,\n\t\t\t\te.key as 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight',\n\t\t\t);\n\n\t\t\tlet newIdx: number = (newRow - 1) * columns + (newCol - 1);\n\t\t\tif (newIdx >= totalCells) {\n\t\t\t\tnewIdx = totalCells - 1;\n\t\t\t}\n\n\t\t\tfocusedIndex = newIdx;\n\t\t\tapplyRovingTabindex(cells as HTMLButtonElement[], focusedIndex);\n\t\t\tcells[focusedIndex]?.focus();\n\t\t\tconfig.onNavigate?.(focusedIndex);\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Home' || e.key === 'End') {\n\t\t\te.preventDefault();\n\t\t\tconst currentRow: number = Math.floor(focusedIndex / columns);\n\t\t\tconst rowStart: number = currentRow * columns;\n\t\t\tconst rowEnd: number = Math.min(rowStart + columns - 1, totalCells - 1);\n\n\t\t\tfocusedIndex = e.key === 'Home' ? rowStart : rowEnd;\n\t\t\tapplyRovingTabindex(cells as HTMLButtonElement[], focusedIndex);\n\t\t\tcells[focusedIndex]?.focus();\n\t\t\tconfig.onNavigate?.(focusedIndex);\n\t\t}\n\t};\n\n\tconfig.container.addEventListener('keydown', handler);\n\treturn () => config.container.removeEventListener('keydown', handler);\n}\n","/**\n * Standalone event bus with error isolation and type-safe event keys.\n * Each listener is wrapped in try/catch — a failing listener never affects others.\n */\n\nimport type { EventKey, PluginEventCallback } from './Plugin.js';\n\nexport class EventBus {\n\tprivate readonly listeners = new Map<string, Set<PluginEventCallback>>();\n\n\t/** Emits an event to all registered listeners. Errors are caught per listener. */\n\temit<T>(key: EventKey<T>, payload: T): void {\n\t\tconst set = this.listeners.get(key.id);\n\t\tif (!set) return;\n\n\t\tfor (const listener of set) {\n\t\t\ttry {\n\t\t\t\tlistener(payload);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[EventBus] Listener error on \"${key.id}\":`, err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Subscribes to an event. Returns an unsubscribe function. */\n\ton<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void {\n\t\tconst id = key.id;\n\t\tif (!this.listeners.has(id)) {\n\t\t\tthis.listeners.set(id, new Set());\n\t\t}\n\t\tconst set = this.listeners.get(id) ?? new Set();\n\t\tset.add(callback as PluginEventCallback);\n\n\t\treturn () => {\n\t\t\tset.delete(callback as PluginEventCallback);\n\t\t\tif (set.size === 0) this.listeners.delete(id);\n\t\t};\n\t}\n\n\t/** Removes a specific listener from an event. */\n\toff<T>(key: EventKey<T>, callback: PluginEventCallback<T>): void {\n\t\tconst set = this.listeners.get(key.id);\n\t\tif (!set) return;\n\t\tset.delete(callback as PluginEventCallback);\n\t\tif (set.size === 0) this.listeners.delete(key.id);\n\t}\n\n\t/** Removes all listeners for all events. */\n\tclear(): void {\n\t\tthis.listeners.clear();\n\t}\n}\n","/**\n * Plugin manager: handles plugin lifecycle, dependency resolution,\n * middleware chain, command/service registries, and error isolation.\n *\n * Per-plugin registration tracking ensures clean teardown —\n * commands, services, middleware, event subscriptions, and schema\n * registrations are automatically cleaned up when a plugin is destroyed.\n */\n\nimport { DecorationSet } from '../decorations/Decoration.js';\nimport { type FileHandler, FileHandlerRegistry } from '../input/FileHandlerRegistry.js';\nimport type { InputRule } from '../input/InputRule.js';\nimport { InputRuleRegistry } from '../input/InputRuleRegistry.js';\nimport type { Keymap, KeymapOptions } from '../input/Keymap.js';\nimport { KeymapRegistry } from '../input/KeymapRegistry.js';\nimport { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { NodeViewRegistry } from '../view/NodeViewRegistry.js';\nimport { EventBus } from './EventBus.js';\nimport type {\n\tCommandEntry,\n\tCommandHandler,\n\tCommandOptions,\n\tEventKey,\n\tMiddlewareNext,\n\tMiddlewareOptions,\n\tPlugin,\n\tPluginConfig,\n\tPluginContext,\n\tPluginEventBus,\n\tPluginEventCallback,\n\tServiceKey,\n\tTransactionMiddleware,\n} from './Plugin.js';\nimport { BlockTypePickerRegistry } from './heading/BlockTypePickerRegistry.js';\nimport { ToolbarRegistry } from './toolbar/ToolbarRegistry.js';\n\nconst DEFAULT_PRIORITY = 100;\n\ninterface MiddlewareEntry {\n\treadonly name: string;\n\treadonly pluginId: string;\n\treadonly middleware: TransactionMiddleware;\n\treadonly priority: number;\n}\n\n/** Describes a registered middleware for introspection. */\nexport interface MiddlewareInfo {\n\treadonly name: string;\n\treadonly priority: number;\n\treadonly pluginId: string;\n}\n\ninterface PluginRegistrations {\n\tcommands: string[];\n\tservices: string[];\n\tmiddlewares: MiddlewareEntry[];\n\tunsubscribers: (() => void)[];\n\tnodeSpecs: string[];\n\tmarkSpecs: string[];\n\tinlineNodeSpecs: string[];\n\tnodeViews: string[];\n\tkeymaps: Keymap[];\n\tinputRules: InputRule[];\n\ttoolbarItems: string[];\n\tfileHandlers: FileHandler[];\n\tblockTypePickerEntries: string[];\n\tstylesheets: CSSStyleSheet[];\n}\n\nexport interface PluginManagerInitOptions {\n\tgetState(): EditorState;\n\tdispatch(transaction: Transaction): void;\n\tgetContainer(): HTMLElement;\n\tgetPluginContainer(position: 'top' | 'bottom'): HTMLElement;\n\t/** Pushes a screen reader announcement via the editor's aria-live region. */\n\tannounce?(text: string): void;\n\t/** Returns whether the announcer live region currently has content. */\n\thasAnnouncement?(): boolean;\n\t/** Called after all plugin init() calls complete, before onReady(). */\n\tonBeforeReady?(): void | Promise<void>;\n}\n\nexport class PluginManager {\n\tprivate readonly plugins = new Map<string, Plugin>();\n\tprivate readonly commands = new Map<string, CommandEntry>();\n\tprivate readonly services = new Map<string, unknown>();\n\tprivate readonly middlewares: MiddlewareEntry[] = [];\n\tprivate readonly registrations = new Map<string, PluginRegistrations>();\n\tprivate readonly eventBus = new EventBus();\n\tprivate readonly pluginStyleSheets: CSSStyleSheet[] = [];\n\treadonly schemaRegistry = new SchemaRegistry();\n\treadonly keymapRegistry = new KeymapRegistry();\n\treadonly inputRuleRegistry = new InputRuleRegistry();\n\treadonly fileHandlerRegistry = new FileHandlerRegistry();\n\treadonly nodeViewRegistry = new NodeViewRegistry();\n\treadonly toolbarRegistry = new ToolbarRegistry();\n\treadonly blockTypePickerRegistry = new BlockTypePickerRegistry();\n\tprivate middlewareSorted: MiddlewareEntry[] | null = null;\n\tprivate initOrder: string[] = [];\n\tprivate initialized = false;\n\tprivate initializing = false;\n\tprivate readOnly = false;\n\tprivate readonlyBypassActive = false;\n\n\t/**\n\t * Registers a system-level service before plugin init.\n\t * Used by the editor to provide global services (e.g. LocaleService).\n\t */\n\tregisterService<T>(key: ServiceKey<T>, service: T): void {\n\t\tif (this.services.has(key.id)) {\n\t\t\tthrow new Error(`Service \"${key.id}\" is already registered.`);\n\t\t}\n\t\tthis.services.set(key.id, service);\n\t}\n\n\t/** Registers a plugin. Must be called before init(). */\n\tregister(plugin: Plugin): void {\n\t\tif (this.initialized || this.initializing) {\n\t\t\tthrow new Error(`Cannot register plugin \"${plugin.id}\" after initialization.`);\n\t\t}\n\t\tif (this.plugins.has(plugin.id)) {\n\t\t\tthrow new Error(`Plugin \"${plugin.id}\" is already registered.`);\n\t\t}\n\t\tthis.plugins.set(plugin.id, plugin);\n\t}\n\n\t/** Initializes all registered plugins in dependency/priority order. */\n\tasync init(options: PluginManagerInitOptions): Promise<void> {\n\t\tif (this.initialized || this.initializing) return;\n\t\tthis.initializing = true;\n\n\t\tthis.initOrder = this.resolveOrder();\n\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin) continue;\n\t\t\tconst context = this.createContext(id, options);\n\t\t\ttry {\n\t\t\t\tawait plugin.init(context);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" failed to initialize:`, err);\n\t\t\t}\n\t\t}\n\n\t\t// Hook between init and onReady — lets the host rebuild schema/state\n\t\t// after all plugins have registered their specs but before plugins render.\n\t\tif (options.onBeforeReady) {\n\t\t\tawait options.onBeforeReady();\n\t\t}\n\n\t\t// Call onReady on all plugins after all init() calls have completed\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin?.onReady) continue;\n\t\t\ttry {\n\t\t\t\tawait plugin.onReady();\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in onReady:`, err);\n\t\t\t}\n\t\t}\n\n\t\tthis.initialized = true;\n\t\tthis.initializing = false;\n\t}\n\n\t/** Notifies all plugins of a state change, in init order. */\n\tnotifyStateChange(oldState: EditorState, newState: EditorState, tr: Transaction): void {\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin?.onStateChange) continue;\n\t\t\ttry {\n\t\t\t\tplugin.onStateChange(oldState, newState, tr);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in onStateChange:`, err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Collects and merges decorations from all plugins. */\n\tcollectDecorations(state: EditorState, tr?: Transaction): DecorationSet {\n\t\tlet result: DecorationSet = DecorationSet.empty;\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin?.decorations) continue;\n\t\t\ttry {\n\t\t\t\tconst decos = plugin.decorations(state, tr);\n\t\t\t\tif (!decos.isEmpty) {\n\t\t\t\t\tresult = result.merge(decos);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in decorations():`, err);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Dispatches a transaction through the middleware chain, then calls the final dispatch.\n\t * If no middleware is registered, calls finalDispatch directly.\n\t */\n\tdispatchWithMiddleware(\n\t\ttr: Transaction,\n\t\tstate: EditorState,\n\t\tfinalDispatch: (tr: Transaction) => void,\n\t): void {\n\t\tif (this.middlewares.length === 0) {\n\t\t\tfinalDispatch(tr);\n\t\t\treturn;\n\t\t}\n\n\t\tconst sorted = this.getSortedMiddleware();\n\t\tlet index = 0;\n\t\tlet dispatched = false;\n\n\t\tconst next: MiddlewareNext = (currentTr) => {\n\t\t\tif (index < sorted.length) {\n\t\t\t\tconst entry = sorted[index++];\n\t\t\t\tif (!entry) return;\n\t\t\t\tlet called = false;\n\t\t\t\tconst guardedNext: MiddlewareNext = (tr) => {\n\t\t\t\t\tif (called) return;\n\t\t\t\t\tcalled = true;\n\t\t\t\t\tnext(tr);\n\t\t\t\t};\n\t\t\t\ttry {\n\t\t\t\t\tentry.middleware(currentTr, state, guardedNext);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(`[PluginManager] Middleware \"${entry.name}\" error:`, err);\n\t\t\t\t\tguardedNext(currentTr);\n\t\t\t\t}\n\t\t\t} else if (!dispatched) {\n\t\t\t\tdispatched = true;\n\t\t\t\tfinalDispatch(currentTr);\n\t\t\t}\n\t\t};\n\n\t\tnext(tr);\n\t}\n\n\t/** Returns whether a named command can be executed (registered and not blocked by readonly). */\n\tcanExecuteCommand(name: string): boolean {\n\t\tconst entry = this.commands.get(name);\n\t\tif (!entry) return false;\n\t\tif (this.readOnly && !entry.readonlyAllowed) return false;\n\t\treturn true;\n\t}\n\n\t/** Executes a named command. Returns false if command not found or editor is read-only. */\n\texecuteCommand(name: string): boolean {\n\t\tconst entry = this.commands.get(name);\n\t\tif (!entry) return false;\n\t\tif (this.readOnly && !entry.readonlyAllowed) return false;\n\n\t\tconst enableBypass: boolean = this.readOnly && entry.readonlyAllowed;\n\t\tif (enableBypass) this.readonlyBypassActive = true;\n\t\ttry {\n\t\t\treturn entry.handler();\n\t\t} catch (err) {\n\t\t\tconsole.error(`[PluginManager] Command \"${name}\" error:`, err);\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tif (enableBypass) this.readonlyBypassActive = false;\n\t\t}\n\t}\n\n\t/** Returns true when a readonlyAllowed command is currently executing. */\n\tisReadonlyBypassed(): boolean {\n\t\treturn this.readonlyBypassActive;\n\t}\n\n\t/** Configures a plugin at runtime via onConfigure(). */\n\tconfigurePlugin(pluginId: string, config: PluginConfig): void {\n\t\tconst plugin = this.plugins.get(pluginId);\n\t\tif (!plugin) {\n\t\t\tthrow new Error(`Plugin \"${pluginId}\" not found.`);\n\t\t}\n\t\tif (!plugin.onConfigure) return;\n\t\ttry {\n\t\t\tplugin.onConfigure(config);\n\t\t} catch (err) {\n\t\t\tconsole.error(`[PluginManager] Plugin \"${pluginId}\" error in onConfigure:`, err);\n\t\t}\n\t}\n\n\t/** Returns the current read-only state. */\n\tisReadOnly(): boolean {\n\t\treturn this.readOnly;\n\t}\n\n\t/** Updates read-only state and notifies all plugins. */\n\tsetReadOnly(readonly: boolean): void {\n\t\tif (this.readOnly === readonly) return;\n\t\tthis.readOnly = readonly;\n\t\tfor (const id of this.initOrder) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin?.onReadOnlyChange) continue;\n\t\t\ttry {\n\t\t\t\tplugin.onReadOnlyChange(readonly);\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in onReadOnlyChange:`, err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Returns all registered plugin IDs. */\n\tgetPluginIds(): string[] {\n\t\treturn [...this.plugins.keys()];\n\t}\n\n\t/** Returns the middleware chain in execution order, for debugging and introspection. */\n\tgetMiddlewareChain(): readonly MiddlewareInfo[] {\n\t\treturn this.getSortedMiddleware().map((entry) => ({\n\t\t\tname: entry.name,\n\t\t\tpriority: entry.priority,\n\t\t\tpluginId: entry.pluginId,\n\t\t}));\n\t}\n\n\t/** Gets a plugin by ID. */\n\tget(id: string): Plugin | undefined {\n\t\treturn this.plugins.get(id);\n\t}\n\n\t/** Gets a registered service by typed key. */\n\tgetService<T>(key: ServiceKey<T>): T | undefined {\n\t\treturn this.services.get(key.id) as T | undefined;\n\t}\n\n\t/** Subscribes to a plugin event from outside the plugin system. Returns an unsubscribe function. */\n\tonEvent<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void {\n\t\treturn this.eventBus.on(key, callback);\n\t}\n\n\t/** Returns all plugin-registered stylesheets. */\n\tgetPluginStyleSheets(): readonly CSSStyleSheet[] {\n\t\treturn this.pluginStyleSheets;\n\t}\n\n\t/** Destroys all plugins in reverse init order. */\n\tasync destroy(): Promise<void> {\n\t\tconst reversed = [...this.initOrder].reverse();\n\t\tfor (const id of reversed) {\n\t\t\tawait this.destroyPlugin(id);\n\t\t}\n\t\tthis.plugins.clear();\n\t\tthis.commands.clear();\n\t\tthis.services.clear();\n\t\tthis.middlewares.length = 0;\n\t\tthis.middlewareSorted = null;\n\t\tthis.pluginStyleSheets.length = 0;\n\t\tthis.eventBus.clear();\n\t\tthis.registrations.clear();\n\t\tthis.schemaRegistry.clear();\n\t\tthis.keymapRegistry.clear();\n\t\tthis.inputRuleRegistry.clear();\n\t\tthis.fileHandlerRegistry.clear();\n\t\tthis.nodeViewRegistry.clear();\n\t\tthis.toolbarRegistry.clear();\n\t\tthis.blockTypePickerRegistry.clear();\n\t\tthis.initOrder = [];\n\t\tthis.initialized = false;\n\t}\n\n\t// --- Private ---\n\n\tprivate async destroyPlugin(id: string): Promise<void> {\n\t\tconst plugin = this.plugins.get(id);\n\t\tif (plugin?.destroy) {\n\t\t\ttry {\n\t\t\t\tawait plugin.destroy();\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(`[PluginManager] Plugin \"${id}\" error in destroy:`, err);\n\t\t\t}\n\t\t}\n\t\tthis.cleanupRegistrations(id);\n\t}\n\n\tprivate cleanupRegistrations(id: string): void {\n\t\tconst reg = this.registrations.get(id);\n\t\tif (!reg) return;\n\n\t\tfor (const name of reg.commands) this.commands.delete(name);\n\t\tfor (const serviceId of reg.services) this.services.delete(serviceId);\n\t\tfor (const entry of reg.middlewares) {\n\t\t\tconst idx = this.middlewares.indexOf(entry);\n\t\t\tif (idx !== -1) this.middlewares.splice(idx, 1);\n\t\t}\n\t\tfor (const unsub of reg.unsubscribers) unsub();\n\n\t\t// Clean up schema registrations\n\t\tfor (const type of reg.nodeSpecs) this.schemaRegistry.removeNodeSpec(type);\n\t\tfor (const type of reg.markSpecs) this.schemaRegistry.removeMarkSpec(type);\n\t\tfor (const type of reg.inlineNodeSpecs) {\n\t\t\tthis.schemaRegistry.removeInlineNodeSpec(type);\n\t\t}\n\n\t\t// Clean up focused registries\n\t\tfor (const type of reg.nodeViews) this.nodeViewRegistry.removeNodeView(type);\n\t\tfor (const keymap of reg.keymaps) this.keymapRegistry.removeKeymap(keymap);\n\t\tfor (const rule of reg.inputRules) this.inputRuleRegistry.removeInputRule(rule);\n\t\tfor (const itemId of reg.toolbarItems) this.toolbarRegistry.removeToolbarItem(itemId);\n\t\tfor (const handler of reg.fileHandlers) {\n\t\t\tthis.fileHandlerRegistry.removeFileHandler(handler);\n\t\t}\n\t\tfor (const entryId of reg.blockTypePickerEntries) {\n\t\t\tthis.blockTypePickerRegistry.removeBlockTypePickerEntry(entryId);\n\t\t}\n\t\tfor (const sheet of reg.stylesheets) {\n\t\t\tconst idx = this.pluginStyleSheets.indexOf(sheet);\n\t\t\tif (idx !== -1) this.pluginStyleSheets.splice(idx, 1);\n\t\t}\n\n\t\tthis.middlewareSorted = null;\n\t\tthis.registrations.delete(id);\n\t}\n\n\tprivate getSortedMiddleware(): MiddlewareEntry[] {\n\t\tif (!this.middlewareSorted) {\n\t\t\tthis.middlewareSorted = [...this.middlewares].sort((a, b) => a.priority - b.priority);\n\t\t}\n\t\treturn this.middlewareSorted;\n\t}\n\n\tprivate createContext(pluginId: string, options: PluginManagerInitOptions): PluginContext {\n\t\tconst reg: PluginRegistrations = {\n\t\t\tcommands: [],\n\t\t\tservices: [],\n\t\t\tmiddlewares: [],\n\t\t\tunsubscribers: [],\n\t\t\tnodeSpecs: [],\n\t\t\tmarkSpecs: [],\n\t\t\tinlineNodeSpecs: [],\n\t\t\tnodeViews: [],\n\t\t\tkeymaps: [],\n\t\t\tinputRules: [],\n\t\t\ttoolbarItems: [],\n\t\t\tfileHandlers: [],\n\t\t\tblockTypePickerEntries: [],\n\t\t\tstylesheets: [],\n\t\t};\n\t\tthis.registrations.set(pluginId, reg);\n\n\t\tconst pluginEventBus: PluginEventBus = {\n\t\t\temit: (key, payload) => this.eventBus.emit(key, payload),\n\t\t\ton: (key, callback) => {\n\t\t\t\tconst unsub = this.eventBus.on(key, callback);\n\t\t\t\treg.unsubscribers.push(unsub);\n\t\t\t\treturn unsub;\n\t\t\t},\n\t\t\toff: (key, callback) => this.eventBus.off(key, callback),\n\t\t};\n\n\t\treturn {\n\t\t\tgetState: options.getState,\n\t\t\tdispatch: options.dispatch,\n\t\t\tgetContainer: options.getContainer,\n\t\t\tgetPluginContainer: options.getPluginContainer,\n\t\t\tisReadOnly: () => this.readOnly,\n\n\t\t\tregisterCommand: (name: string, handler: CommandHandler, options?: CommandOptions) => {\n\t\t\t\tif (this.commands.has(name)) {\n\t\t\t\t\tconst existing = this.commands.get(name);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Command \"${name}\" is already registered by plugin \"${existing?.pluginId}\".`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst readonlyAllowed: boolean = options?.readonlyAllowed ?? false;\n\t\t\t\tthis.commands.set(name, { name, handler, pluginId, readonlyAllowed });\n\t\t\t\treg.commands.push(name);\n\t\t\t},\n\n\t\t\texecuteCommand: (name: string) => this.executeCommand(name),\n\n\t\t\tgetEventBus: () => pluginEventBus,\n\n\t\t\tregisterMiddleware: (middleware: TransactionMiddleware, options?: MiddlewareOptions) => {\n\t\t\t\tconst name: string = options?.name ?? (middleware.name || 'anonymous');\n\t\t\t\tconst priority: number = options?.priority ?? DEFAULT_PRIORITY;\n\t\t\t\tconst entry: MiddlewareEntry = { name, pluginId, middleware, priority };\n\t\t\t\tthis.middlewares.push(entry);\n\t\t\t\treg.middlewares.push(entry);\n\t\t\t\tthis.middlewareSorted = null;\n\t\t\t},\n\n\t\t\tregisterService: <T>(key: ServiceKey<T>, service: T) => {\n\t\t\t\tif (this.services.has(key.id)) {\n\t\t\t\t\tthrow new Error(`Service \"${key.id}\" is already registered by another plugin.`);\n\t\t\t\t}\n\t\t\t\tthis.services.set(key.id, service);\n\t\t\t\treg.services.push(key.id);\n\t\t\t},\n\n\t\t\tgetService: <T>(key: ServiceKey<T>) => this.services.get(key.id) as T | undefined,\n\n\t\t\tupdateConfig: (config: PluginConfig) => {\n\t\t\t\tconst plugin = this.plugins.get(pluginId);\n\t\t\t\tif (plugin?.onConfigure) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tplugin.onConfigure(config);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.error(`[PluginManager] Plugin \"${pluginId}\" error in onConfigure:`, err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// --- Schema Extension Methods ---\n\n\t\t\tregisterNodeSpec: (spec) => {\n\t\t\t\tthis.schemaRegistry.registerNodeSpec(spec);\n\t\t\t\treg.nodeSpecs.push(spec.type);\n\t\t\t},\n\n\t\t\tregisterMarkSpec: (spec) => {\n\t\t\t\tthis.schemaRegistry.registerMarkSpec(spec);\n\t\t\t\treg.markSpecs.push(spec.type);\n\t\t\t},\n\n\t\t\tregisterNodeView: (type, factory) => {\n\t\t\t\tthis.nodeViewRegistry.registerNodeView(type, factory);\n\t\t\t\treg.nodeViews.push(type);\n\t\t\t},\n\n\t\t\tregisterKeymap: (keymap: Keymap, options?: KeymapOptions) => {\n\t\t\t\tthis.keymapRegistry.registerKeymap(keymap, options);\n\t\t\t\treg.keymaps.push(keymap);\n\t\t\t},\n\n\t\t\tregisterInputRule: (rule) => {\n\t\t\t\tthis.inputRuleRegistry.registerInputRule(rule);\n\t\t\t\treg.inputRules.push(rule);\n\t\t\t},\n\n\t\t\tregisterToolbarItem: (item) => {\n\t\t\t\tthis.toolbarRegistry.registerToolbarItem(item, pluginId);\n\t\t\t\treg.toolbarItems.push(item.id);\n\t\t\t},\n\n\t\t\tregisterInlineNodeSpec: (spec) => {\n\t\t\t\tthis.schemaRegistry.registerInlineNodeSpec(spec);\n\t\t\t\treg.inlineNodeSpecs.push(spec.type);\n\t\t\t},\n\n\t\t\tregisterFileHandler: (pattern, handler) => {\n\t\t\t\tthis.fileHandlerRegistry.registerFileHandler(pattern, handler);\n\t\t\t\treg.fileHandlers.push(handler);\n\t\t\t},\n\n\t\t\tregisterBlockTypePickerEntry: (entry) => {\n\t\t\t\tthis.blockTypePickerRegistry.registerBlockTypePickerEntry(entry);\n\t\t\t\treg.blockTypePickerEntries.push(entry.id);\n\t\t\t},\n\n\t\t\tgetSchemaRegistry: () => this.schemaRegistry,\n\t\t\tgetKeymapRegistry: () => this.keymapRegistry,\n\t\t\tgetInputRuleRegistry: () => this.inputRuleRegistry,\n\t\t\tgetFileHandlerRegistry: () => this.fileHandlerRegistry,\n\t\t\tgetNodeViewRegistry: () => this.nodeViewRegistry,\n\t\t\tgetToolbarRegistry: () => this.toolbarRegistry,\n\t\t\tgetBlockTypePickerRegistry: () => this.blockTypePickerRegistry,\n\n\t\t\tregisterStyleSheet: (css: string) => {\n\t\t\t\tconst sheet: CSSStyleSheet = new CSSStyleSheet();\n\t\t\t\tsheet.replaceSync(css);\n\t\t\t\tthis.pluginStyleSheets.push(sheet);\n\t\t\t\treg.stylesheets.push(sheet);\n\t\t\t},\n\n\t\t\tannounce: (text: string) => {\n\t\t\t\toptions.announce?.(text);\n\t\t\t},\n\n\t\t\thasAnnouncement: () => options.hasAnnouncement?.() ?? false,\n\t\t};\n\t}\n\n\t/**\n\t * Resolves plugin initialization order via topological sort + priority.\n\t * Throws on dependency cycles or missing dependencies.\n\t */\n\tprivate resolveOrder(): string[] {\n\t\tconst ids = [...this.plugins.keys()];\n\n\t\t// Validate dependencies exist\n\t\tfor (const id of ids) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tif (!plugin) continue;\n\t\t\tfor (const dep of plugin.dependencies ?? []) {\n\t\t\t\tif (!this.plugins.has(dep)) {\n\t\t\t\t\tthrow new Error(`Plugin \"${id}\" depends on \"${dep}\", which is not registered.`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Topological sort (Kahn's algorithm)\n\t\tconst inDegree = new Map<string, number>();\n\t\tconst dependents = new Map<string, string[]>();\n\n\t\tfor (const id of ids) {\n\t\t\tinDegree.set(id, 0);\n\t\t\tdependents.set(id, []);\n\t\t}\n\n\t\tfor (const id of ids) {\n\t\t\tconst plugin = this.plugins.get(id);\n\t\t\tconst deps = plugin?.dependencies ?? [];\n\t\t\tinDegree.set(id, deps.length);\n\t\t\tfor (const dep of deps) {\n\t\t\t\tconst depList = dependents.get(dep);\n\t\t\t\tif (depList) depList.push(id);\n\t\t\t}\n\t\t}\n\n\t\tconst queue: string[] = [];\n\t\tfor (const [id, deg] of inDegree) {\n\t\t\tif (deg === 0) queue.push(id);\n\t\t}\n\n\t\tconst sorted: string[] = [];\n\t\twhile (queue.length > 0) {\n\t\t\tqueue.sort((a, b) => {\n\t\t\t\tconst pa = this.plugins.get(a)?.priority ?? DEFAULT_PRIORITY;\n\t\t\t\tconst pb = this.plugins.get(b)?.priority ?? DEFAULT_PRIORITY;\n\t\t\t\treturn pa - pb;\n\t\t\t});\n\n\t\t\tconst id = queue.shift();\n\t\t\tif (!id) break;\n\t\t\tsorted.push(id);\n\n\t\t\tfor (const dep of dependents.get(id) ?? []) {\n\t\t\t\tconst newDeg = (inDegree.get(dep) ?? 0) - 1;\n\t\t\t\tinDegree.set(dep, newDeg);\n\t\t\t\tif (newDeg === 0) queue.push(dep);\n\t\t\t}\n\t\t}\n\n\t\tif (sorted.length !== ids.length) {\n\t\t\tconst missing = ids.filter((id) => !sorted.includes(id));\n\t\t\tthrow new Error(`Circular dependency detected among plugins: ${missing.join(', ')}`);\n\t\t}\n\n\t\treturn sorted;\n\t}\n}\n","/** Locale interface and default English locale for the PrintPlugin. */\n\n// --- Locale Interface ---\n\nexport interface PrintLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n\treadonly printingAnnouncement: string;\n}\n\n// --- Default English Locale ---\n\nexport const PRINT_LOCALE_EN: PrintLocale = {\n\tlabel: 'Print',\n\ttooltip: (shortcut: string) => `Print (${shortcut})`,\n\tprintingAnnouncement: 'Printing',\n};\n\n// --- German Locale ---\n\nexport const PRINT_LOCALE_DE: PrintLocale = {\n\tlabel: 'Drucken',\n\ttooltip: (shortcut: string) => `Drucken (${shortcut})`,\n\tprintingAnnouncement: 'Druckvorgang',\n};\n\n// --- Spanish Locale ---\n\nexport const PRINT_LOCALE_ES: PrintLocale = {\n\tlabel: 'Imprimir',\n\ttooltip: (shortcut: string) => `Imprimir (${shortcut})`,\n\tprintingAnnouncement: 'Imprimiendo',\n};\n\n// --- French Locale ---\n\nexport const PRINT_LOCALE_FR: PrintLocale = {\n\tlabel: 'Imprimer',\n\ttooltip: (shortcut: string) => `Imprimer (${shortcut})`,\n\tprintingAnnouncement: 'Impression',\n};\n\n// --- Chinese (Simplified) Locale ---\n\nexport const PRINT_LOCALE_ZH: PrintLocale = {\n\tlabel: '打印',\n\ttooltip: (shortcut: string) => `打印 (${shortcut})`,\n\tprintingAnnouncement: '正在打印',\n};\n\n// --- Russian Locale ---\n\nexport const PRINT_LOCALE_RU: PrintLocale = {\n\tlabel: 'Печать',\n\ttooltip: (shortcut: string) => `Печать (${shortcut})`,\n\tprintingAnnouncement: 'Печать',\n};\n\n// --- Arabic Locale ---\n\nexport const PRINT_LOCALE_AR: PrintLocale = {\n\tlabel: 'طباعة',\n\ttooltip: (shortcut: string) => `طباعة (${shortcut})`,\n\tprintingAnnouncement: 'جارٍ الطباعة',\n};\n\n// --- Hindi Locale ---\n\nexport const PRINT_LOCALE_HI: PrintLocale = {\n\tlabel: 'प्रिंट',\n\ttooltip: (shortcut: string) => `प्रिंट (${shortcut})`,\n\tprintingAnnouncement: 'प्रिंट हो रहा है',\n};\n\n// --- Locale Map ---\n\nexport const PRINT_LOCALES: Record<string, PrintLocale> = {\n\ten: PRINT_LOCALE_EN,\n\tde: PRINT_LOCALE_DE,\n\tes: PRINT_LOCALE_ES,\n\tfr: PRINT_LOCALE_FR,\n\tzh: PRINT_LOCALE_ZH,\n\tru: PRINT_LOCALE_RU,\n\tar: PRINT_LOCALE_AR,\n\thi: PRINT_LOCALE_HI,\n};\n","/**\n * Prepares editor content for print output.\n * Clones the DOM, sanitizes interactive attributes, applies block filters,\n * and inserts header/footer elements.\n */\n\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Deep-clones the .notectl-content element from the editor container. */\nexport function cloneContent(container: HTMLElement): HTMLElement {\n\tconst content: HTMLElement | null = container.querySelector('.notectl-content');\n\tconst source: HTMLElement = content ?? container;\n\treturn source.cloneNode(true) as HTMLElement;\n}\n\n/** Sanitizes the cloned content for print: removes interactive attributes and selection styling. */\nexport function sanitize(clone: HTMLElement): void {\n\t// Remove contenteditable from the root\n\tclone.removeAttribute('contenteditable');\n\n\t// Remove selection-related CSS classes\n\tconst selectionClasses: readonly string[] = ['notectl-node-selected', 'notectl-content--empty'];\n\tfor (const cls of selectionClasses) {\n\t\tclone.classList.remove(cls);\n\t\tfor (const el of clone.querySelectorAll(`.${cls}`)) {\n\t\t\tel.classList.remove(cls);\n\t\t}\n\t}\n\n\t// Remove data-placeholder to avoid showing placeholder in print\n\tclone.removeAttribute('data-placeholder');\n}\n\n/** Removes excluded block types and applies page-break-before to configured block types. */\nexport function applyBlockFilters(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.excludeBlockTypes) {\n\t\tfor (const type of options.excludeBlockTypes) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tel.remove();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (options.pageBreakBefore) {\n\t\tfor (const type of options.pageBreakBefore) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tsetStyleProperties(el as HTMLElement, {\n\t\t\t\t\tbreakBefore: 'page',\n\t\t\t\t\tpageBreakBefore: 'always',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Resolves a header/footer value to an HTML string. */\nfunction resolveContent(value: string | (() => string)): string {\n\treturn typeof value === 'function' ? value() : value;\n}\n\n/** Inserts header and footer elements into the cloned content. */\nexport function insertHeaderFooter(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.header) {\n\t\tconst headerEl: HTMLDivElement = document.createElement('div');\n\t\theaderEl.className = 'notectl-print-header';\n\t\theaderEl.innerHTML = resolveContent(options.header);\n\t\tclone.insertBefore(headerEl, clone.firstChild);\n\t}\n\n\tif (options.footer) {\n\t\tconst footerEl: HTMLDivElement = document.createElement('div');\n\t\tfooterEl.className = 'notectl-print-footer';\n\t\tfooterEl.innerHTML = resolveContent(options.footer);\n\t\tclone.appendChild(footerEl);\n\t}\n}\n\n/** Orchestrates all content preparation steps. Returns a ready-to-print DOM element. */\nexport function prepare(container: HTMLElement, options: PrintOptions): HTMLElement {\n\tconst clone: HTMLElement = cloneContent(container);\n\tsanitize(clone);\n\tapplyBlockFilters(clone, options);\n\tinsertHeaderFooter(clone, options);\n\treturn clone;\n}\n","/**\n * Paper size definitions and dimension helpers.\n * Used by PaperLayoutController for WYSIWYG page layout\n * and by PrintStyleCollector for @page CSS rules.\n */\n\n/** Conversion factor: 1mm = 96/25.4 px at CSS reference pixel (96 DPI). */\nconst MM_TO_PX: number = 96 / 25.4;\n\n/** Physical dimensions of a paper size. */\nexport interface PaperDimensions {\n\treadonly widthMm: number;\n\treadonly heightMm: number;\n\treadonly widthPx: number;\n\treadonly heightPx: number;\n}\n\n/** Available paper size presets. */\nexport const PaperSize = {\n\tDINA4: 'din-a4',\n\tDINA5: 'din-a5',\n\tUSLetter: 'us-letter',\n\tUSLegal: 'us-legal',\n} as const;\nexport type PaperSize = (typeof PaperSize)[keyof typeof PaperSize];\n\n/** Rounds to nearest integer for pixel dimensions. */\nfunction mmToPx(mm: number): number {\n\treturn Math.round(mm * MM_TO_PX);\n}\n\n/** Lookup table for paper dimensions. */\nconst PAPER_DIMENSIONS: ReadonlyMap<PaperSize, PaperDimensions> = new Map<\n\tPaperSize,\n\tPaperDimensions\n>([\n\t[PaperSize.DINA4, { widthMm: 210, heightMm: 297, widthPx: mmToPx(210), heightPx: mmToPx(297) }],\n\t[PaperSize.DINA5, { widthMm: 148, heightMm: 210, widthPx: mmToPx(148), heightPx: mmToPx(210) }],\n\t[\n\t\tPaperSize.USLetter,\n\t\t{ widthMm: 215.9, heightMm: 279.4, widthPx: mmToPx(215.9), heightPx: mmToPx(279.4) },\n\t],\n\t[\n\t\tPaperSize.USLegal,\n\t\t{ widthMm: 215.9, heightMm: 355.6, widthPx: mmToPx(215.9), heightPx: mmToPx(355.6) },\n\t],\n]);\n\n/** CSS @page size keywords for each paper size. */\nconst CSS_SIZE_KEYWORDS: ReadonlyMap<PaperSize, string> = new Map<PaperSize, string>([\n\t[PaperSize.DINA4, 'A4'],\n\t[PaperSize.DINA5, 'A5'],\n\t[PaperSize.USLetter, 'letter'],\n\t[PaperSize.USLegal, 'legal'],\n]);\n\n/** Returns the physical and pixel dimensions for a paper size. */\nexport function getPaperDimensions(size: PaperSize): PaperDimensions {\n\tconst dims: PaperDimensions | undefined = PAPER_DIMENSIONS.get(size);\n\tif (!dims) {\n\t\tthrow new Error(`Unknown paper size: ${size}`);\n\t}\n\treturn dims;\n}\n\n/**\n * Document margin constants for paper mode (in px).\n * These define the content padding inside the paper surface in the editor,\n * and become @page margins in print output to ensure WYSIWYG fidelity.\n */\nexport const PAPER_MARGIN_TOP_PX: number = 48;\nexport const PAPER_MARGIN_HORIZONTAL_PX: number = 56;\nexport const PAPER_VIEWPORT_PADDING_PX: number = 24;\n\n/** Type guard: returns true if the value is a valid PaperSize string. */\nexport function isValidPaperSize(value: string): value is PaperSize {\n\treturn (Object.values(PaperSize) as string[]).includes(value);\n}\n\n/** Returns the CSS @page size keyword (e.g. 'A4', 'letter') for a paper size. */\nexport function getPaperCSSSize(size: PaperSize): string {\n\tconst keyword: string | undefined = CSS_SIZE_KEYWORDS.get(size);\n\tif (!keyword) {\n\t\tthrow new Error(`Unknown paper size: ${size}`);\n\t}\n\treturn keyword;\n}\n","/**\n * Type definitions, service keys, and event keys for the PrintPlugin.\n */\n\nimport type { PaperSize } from '../../editor/PaperSize.js';\nimport type { NodeTypeName } from '../../model/TypeBrands.js';\nimport { EventKey, ServiceKey } from '../Plugin.js';\n\n// --- Print Options ---\n\nexport interface PrintOptions {\n\t/** Page title shown in the browser print header. */\n\treadonly title?: string;\n\n\t/** Additional CSS appended to the print stylesheet. */\n\treadonly customCSS?: string;\n\n\t/**\n\t * Header HTML inserted once at the top of the print document.\n\t * For repeating per-page headers, use toHTML() with server-side PDF generation.\n\t */\n\treadonly header?: string | (() => string);\n\n\t/**\n\t * Footer HTML inserted once at the bottom of the print document.\n\t * For repeating per-page footers, use toHTML() with server-side PDF generation.\n\t */\n\treadonly footer?: string | (() => string);\n\n\t/** Page margins as CSS value (e.g. '2cm'). */\n\treadonly margin?: string;\n\n\t/** Force page break before these block types. */\n\treadonly pageBreakBefore?: readonly NodeTypeName[];\n\n\t/** Exclude these block types from print output. */\n\treadonly excludeBlockTypes?: readonly NodeTypeName[];\n\n\t/**\n\t * Whether to preserve background colors and images in print output.\n\t * Defaults to `true` (WYSIWYG). Set to `false` to let the browser strip\n\t * backgrounds (e.g. to save ink).\n\t */\n\treadonly printBackground?: boolean;\n\n\t/** Page orientation. */\n\treadonly orientation?: 'portrait' | 'landscape';\n\n\t/** Paper size for @page CSS rule. When set, overrides the default A4 page size. */\n\treadonly paperSize?: PaperSize;\n}\n\n// --- Plugin Configuration ---\n\nexport interface PrintPluginConfig {\n\t/** Default options applied to every print() call. */\n\treadonly defaults?: PrintOptions;\n\n\t/** Keyboard shortcut (default: 'Mod-P'). */\n\treadonly keyBinding?: string;\n\n\t/** Show toolbar button (default: true). */\n\treadonly showToolbarItem?: boolean;\n\n\t/** Locale override for user-facing strings. */\n\treadonly locale?: import('./PrintLocale.js').PrintLocale;\n}\n\n// --- Service Interface ---\n\nexport interface PrintService {\n\t/** Prints the editor content with optional configuration. */\n\tprint(options?: PrintOptions): void;\n\n\t/** Generates print-ready HTML as a complete document string. */\n\ttoHTML(options?: PrintOptions): string;\n}\n\n// --- Service & Event Keys ---\n\nexport const PRINT_SERVICE_KEY: ServiceKey<PrintService> = new ServiceKey<PrintService>('print');\n\nexport const BEFORE_PRINT: EventKey<BeforePrintEvent> = new EventKey<BeforePrintEvent>(\n\t'print:before',\n);\n\nexport const AFTER_PRINT: EventKey<AfterPrintEvent> = new EventKey<AfterPrintEvent>('print:after');\n\n// --- Event Payloads ---\n\nexport interface BeforePrintEvent {\n\t/** Options can be mutated — EventBus passes by reference. */\n\toptions: PrintOptions;\n\t/** Set to true to cancel the print. */\n\tcancelled: boolean;\n}\n\nexport interface AfterPrintEvent {\n\t/** The generated HTML (read-only). */\n\treadonly html: string;\n}\n","/**\n * PrintPlugin: provides print functionality for the notectl editor.\n * Registers a command, keymap, toolbar item, and exposes a PrintService.\n * Orchestrator only — delegates all logic to PrintServiceImpl, PrintStyleCollector,\n * and PrintContentPreparer.\n */\n\nimport { resolvePluginLocale } from '../../i18n/resolvePluginLocale.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\nimport { PRINT_LOCALES, type PrintLocale } from './PrintLocale.js';\nimport { createPrintService } from './PrintServiceImpl.js';\nimport type { PrintOptions, PrintPluginConfig, PrintService } from './PrintTypes.js';\nimport { PRINT_SERVICE_KEY } from './PrintTypes.js';\n\nconst PRINT_ICON: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\">' +\n\t'<path d=\"M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3' +\n\t' 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z\"/>' +\n\t'</svg>';\n\n/** No-op fallback service for environments without ShadowRoot. */\nconst NOOP_SERVICE: PrintService = {\n\tprint(): void {},\n\ttoHTML(): string {\n\t\treturn '';\n\t},\n};\n\nexport class PrintPlugin implements Plugin {\n\treadonly id = 'print';\n\treadonly name = 'Print';\n\n\tprivate readonly config: PrintPluginConfig;\n\tprivate service: PrintService | null = null;\n\tprivate locale!: PrintLocale;\n\n\tconstructor(config?: PrintPluginConfig) {\n\t\tthis.config = config ?? {};\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.locale = resolvePluginLocale(PRINT_LOCALES, context, this.config.locale);\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tconst rootNode: Node = container.getRootNode();\n\n\t\tif (rootNode instanceof ShadowRoot) {\n\t\t\tconst host: HTMLElement = rootNode.host as HTMLElement;\n\t\t\tconst eventBus = context.getEventBus();\n\t\t\tthis.service = createPrintService(rootNode, host, container, eventBus);\n\t\t} else {\n\t\t\tthis.service = NOOP_SERVICE;\n\t\t}\n\n\t\tcontext.registerService(PRINT_SERVICE_KEY, this.service);\n\n\t\tconst defaults: PrintOptions = this.config.defaults ?? {};\n\t\tconst service: PrintService = this.service;\n\n\t\tconst printLocale = this.locale;\n\t\tcontext.registerCommand('print', () => {\n\t\t\tcontext.announce(printLocale.printingAnnouncement);\n\t\t\tservice.print(defaults);\n\t\t\treturn true;\n\t\t});\n\n\t\tconst keyBinding: string = this.config.keyBinding ?? 'Mod-P';\n\t\tcontext.registerKeymap({\n\t\t\t[keyBinding]: () => {\n\t\t\t\tcontext.executeCommand('print');\n\t\t\t\treturn true;\n\t\t\t},\n\t\t});\n\n\t\tif (this.config.showToolbarItem !== false) {\n\t\t\tconst shortcut: string = formatShortcut(keyBinding);\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: 'print',\n\t\t\t\tgroup: 'actions',\n\t\t\t\tlabel: this.locale.label,\n\t\t\t\ttooltip: this.locale.tooltip(shortcut),\n\t\t\t\ticon: PRINT_ICON,\n\t\t\t\tcommand: 'print',\n\t\t\t\tpriority: 900,\n\t\t\t});\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.service = null;\n\t}\n}\n","/**\n * PrintService implementation.\n * Handles the synchronous print flow: event emission, style collection,\n * content preparation, iframe creation, and cleanup.\n */\n\nimport type { PluginEventBus } from '../Plugin.js';\nimport { prepare } from './PrintContentPreparer.js';\nimport { collectAll } from './PrintStyleCollector.js';\nimport {\n\tAFTER_PRINT,\n\ttype AfterPrintEvent,\n\tBEFORE_PRINT,\n\ttype BeforePrintEvent,\n\ttype PrintOptions,\n\ttype PrintService,\n} from './PrintTypes.js';\n\n/** Escapes HTML special characters in a plain-text string. */\nfunction escapeHTML(text: string): string {\n\treturn text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\n/** Builds a complete HTML document string from CSS, body content, and title. */\nexport function buildHTMLDocument(\n\tcss: string,\n\tcontent: string,\n\ttitle: string,\n\tlang = 'en',\n): string {\n\tconst safeTitle: string = escapeHTML(title);\n\treturn [\n\t\t'<!DOCTYPE html>',\n\t\t`<html lang=\"${lang}\">`,\n\t\t'<head>',\n\t\t`<meta charset=\"utf-8\">`,\n\t\t`<title>${safeTitle}</title>`,\n\t\t`<style>${css}</style>`,\n\t\t'</head>',\n\t\t`<body>${content}</body>`,\n\t\t'</html>',\n\t].join('\\n');\n}\n\n/** Creates and returns the PrintService implementation. */\nexport function createPrintService(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\tcontainer: HTMLElement,\n\teventBus: PluginEventBus,\n): PrintService {\n\tfunction mergeOptions(options?: PrintOptions): PrintOptions {\n\t\treturn options ?? {};\n\t}\n\n\tfunction executePrint(options: PrintOptions): string | null {\n\t\t// 1. Emit BEFORE_PRINT — listeners can mutate options or cancel\n\t\tconst beforeEvent: BeforePrintEvent = {\n\t\t\toptions,\n\t\t\tcancelled: false,\n\t\t};\n\t\teventBus.emit(BEFORE_PRINT, beforeEvent);\n\n\t\tif (beforeEvent.cancelled) return null;\n\n\t\tconst finalOptions: PrintOptions = beforeEvent.options;\n\n\t\t// 2. Collect styles\n\t\tconst css: string = collectAll(shadowRoot, host, finalOptions);\n\n\t\t// 3. Prepare content\n\t\tconst clone: HTMLElement = prepare(container, finalOptions);\n\t\tconst contentHTML: string = clone.outerHTML;\n\n\t\t// 4. Build HTML document\n\t\tconst title: string = finalOptions.title ?? '';\n\t\tconst lang: string =\n\t\t\thost.closest('[lang]')?.getAttribute('lang') ?? (document.documentElement.lang || 'en');\n\t\tconst html: string = buildHTMLDocument(css, contentHTML, title, lang);\n\n\t\t// 5. Emit AFTER_PRINT\n\t\tconst afterEvent: AfterPrintEvent = { html };\n\t\teventBus.emit(AFTER_PRINT, afterEvent);\n\n\t\treturn html;\n\t}\n\n\treturn {\n\t\tprint(options?: PrintOptions): void {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\tconst html: string | null = executePrint(resolved);\n\t\t\tif (!html) return;\n\n\t\t\t// Create hidden iframe\n\t\t\tconst iframe: HTMLIFrameElement = document.createElement('iframe');\n\t\t\tiframe.style.cssText = 'position:fixed;left:-9999px;width:0;height:0;border:none;';\n\t\t\tdocument.body.appendChild(iframe);\n\n\t\t\tconst iframeDoc: Document | null = iframe.contentDocument;\n\t\t\tif (!iframeDoc) {\n\t\t\t\tdocument.body.removeChild(iframe);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tiframeDoc.open();\n\t\t\tiframeDoc.write(html);\n\t\t\tiframeDoc.close();\n\n\t\t\tconst cleanup = (): void => {\n\t\t\t\tiframe.remove();\n\t\t\t};\n\n\t\t\t// Defer cleanup until print dialog closes\n\t\t\tif (iframe.contentWindow) {\n\t\t\t\tiframe.contentWindow.addEventListener('afterprint', cleanup, { once: true });\n\t\t\t\tiframe.contentWindow.print();\n\t\t\t} else {\n\t\t\t\tcleanup();\n\t\t\t}\n\t\t},\n\n\t\ttoHTML(options?: PrintOptions): string {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\treturn executePrint(resolved) ?? '';\n\t\t},\n\t};\n}\n","/**\n * Collects and aggregates CSS for print output.\n * Extracts adopted stylesheets, snapshots theme tokens, and generates print-specific CSS.\n */\n\nimport {\n\tPAPER_MARGIN_HORIZONTAL_PX,\n\tPAPER_MARGIN_TOP_PX,\n\tgetPaperCSSSize,\n} from '../../editor/PaperSize.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Extracts CSS text from all adopted stylesheets on a ShadowRoot. */\nexport function extractAdoptedStyles(shadowRoot: ShadowRoot): string {\n\tconst parts: string[] = [];\n\tfor (const sheet of shadowRoot.adoptedStyleSheets) {\n\t\tfor (const rule of sheet.cssRules) {\n\t\t\tparts.push(rule.cssText);\n\t\t}\n\t}\n\treturn parts.join('\\n');\n}\n\n/** Snapshots --notectl-* CSS custom properties from the host element into a :root block. */\nexport function snapshotThemeTokens(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst tokens: string[] = [];\n\n\tfor (let i = 0; i < computed.length; i++) {\n\t\tconst prop: string = computed[i] ?? '';\n\t\tif (prop.startsWith('--notectl-')) {\n\t\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\t\tif (value) {\n\t\t\t\ttokens.push(` ${prop}: ${value};`);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (tokens.length === 0) return '';\n\treturn `:root {\\n${tokens.join('\\n')}\\n}`;\n}\n\n/**\n * Snapshots computed typography from the host element into a `body` rule.\n * In the editor, typography is inherited from `:host` (shadow DOM).\n * The print iframe is a regular document where `:host` doesn't match,\n * so we must apply the same font/line-height explicitly.\n */\nexport function snapshotTypography(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst props: string[] = [\n\t\t'font-family',\n\t\t'font-size',\n\t\t'font-weight',\n\t\t'line-height',\n\t\t'letter-spacing',\n\t\t'word-spacing',\n\t\t'color',\n\t];\n\tconst rules: string[] = [' margin: 0;'];\n\tfor (const prop of props) {\n\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\tif (value) {\n\t\t\trules.push(` ${prop}: ${value};`);\n\t\t}\n\t}\n\treturn `body {\\n${rules.join('\\n')}\\n}`;\n}\n\n/** Generates print-specific CSS rules based on PrintOptions. */\nexport function generatePrintCSS(options: PrintOptions): string {\n\tconst parts: string[] = [];\n\n\t// @page rule\n\tconst pageProps: string[] = [];\n\tif (options.margin) {\n\t\tpageProps.push(` margin: ${options.margin};`);\n\t} else if (options.paperSize) {\n\t\t// WYSIWYG: zero @page margin so body = full paper width;\n\t\t// document margins are applied as content padding below.\n\t\tpageProps.push(' margin: 0;');\n\t}\n\tif (options.paperSize || options.orientation) {\n\t\tconst sizeKeyword: string = options.paperSize ? getPaperCSSSize(options.paperSize) : 'A4';\n\t\tconst sizeParts: string[] = [sizeKeyword];\n\t\tif (options.orientation) {\n\t\t\tsizeParts.push(options.orientation);\n\t\t}\n\t\tpageProps.push(` size: ${sizeParts.join(' ')};`);\n\t}\n\tif (pageProps.length > 0) {\n\t\tparts.push(`@page {\\n${pageProps.join('\\n')}\\n}`);\n\t}\n\n\t// WYSIWYG: apply paper-mode document margins to print content\n\tif (options.paperSize) {\n\t\tparts.push(\n\t\t\t`.notectl-content { padding: ${PAPER_MARGIN_TOP_PX}px ${PAPER_MARGIN_HORIZONTAL_PX}px !important; }`,\n\t\t);\n\t}\n\n\t// Print media rules\n\tconst printRules: string[] = [];\n\n\t// Hide non-printable elements\n\tprintRules.push('[data-notectl-no-print] { display: none !important; }');\n\n\t// Code blocks: preserve background, force wrapping\n\tprintRules.push(\n\t\t'.notectl-code-block { white-space: pre-wrap !important; ' +\n\t\t\t'word-break: break-all !important; page-break-inside: avoid; }',\n\t);\n\n\t// Images: avoid page breaks\n\tprintRules.push('img { page-break-inside: avoid; }');\n\n\t// Tables: avoid page breaks\n\tprintRules.push('.notectl-table { break-inside: avoid; }');\n\n\t// Preserve background colors and images in print output (WYSIWYG default).\n\t// Only omitted when the consumer explicitly opts out via printBackground: false.\n\tif (options.printBackground !== false) {\n\t\tprintRules.push(\n\t\t\t'* { -webkit-print-color-adjust: exact !important; ' +\n\t\t\t\t'print-color-adjust: exact !important; }',\n\t\t);\n\t}\n\n\tparts.push(`@media print {\\n ${printRules.join('\\n ')}\\n}`);\n\n\treturn parts.join('\\n\\n');\n}\n\n/** Collects all CSS needed for print: adopted styles, theme tokens, print CSS, and custom CSS. */\nexport function collectAll(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\toptions: PrintOptions,\n): string {\n\tconst parts: string[] = [];\n\n\tconst adopted: string = extractAdoptedStyles(shadowRoot);\n\tif (adopted) parts.push(adopted);\n\n\tconst theme: string = snapshotThemeTokens(host);\n\tif (theme) parts.push(theme);\n\n\t// WYSIWYG: snapshot host typography so the print iframe matches the editor.\n\t// In the editor, .notectl-content inherits font from :host (shadow DOM).\n\t// The print iframe is a regular document where :host doesn't apply.\n\tif (options.paperSize) {\n\t\tparts.push(snapshotTypography(host));\n\t}\n\n\tconst printCSS: string = generatePrintCSS(options);\n\tif (printCSS) parts.push(printCSS);\n\n\tif (options.customCSS) {\n\t\tparts.push(options.customCSS);\n\t}\n\n\treturn parts.join('\\n\\n');\n}\n","/**\n * Theme token types, built-in themes, and theme creation helpers.\n */\n\n/** Primitive color palette a theme defines. */\nexport interface ThemePrimitives {\n\treadonly background: string;\n\treadonly foreground: string;\n\treadonly mutedForeground: string;\n\treadonly border: string;\n\treadonly borderFocus: string;\n\treadonly primary: string;\n\treadonly primaryForeground: string;\n\treadonly primaryMuted: string;\n\treadonly surfaceRaised: string;\n\treadonly surfaceOverlay: string;\n\treadonly hoverBackground: string;\n\treadonly activeBackground: string;\n\treadonly danger: string;\n\treadonly dangerMuted: string;\n\treadonly success: string;\n\treadonly shadow: string;\n\treadonly focusRing: string;\n}\n\n/** Component-level toolbar overrides. */\nexport interface ThemeToolbar {\n\treadonly background: string;\n\treadonly borderColor: string;\n}\n\n/** Component-level code block overrides. */\nexport interface ThemeCodeBlock {\n\treadonly background: string;\n\treadonly foreground: string;\n\treadonly headerBackground: string;\n\treadonly headerForeground: string;\n\treadonly headerBorder: string;\n}\n\n/** Component-level tooltip overrides. */\nexport interface ThemeTooltip {\n\treadonly background: string;\n\treadonly foreground: string;\n}\n\n/** Full theme definition. */\nexport interface Theme {\n\treadonly name: string;\n\treadonly primitives: ThemePrimitives;\n\treadonly toolbar?: Partial<ThemeToolbar>;\n\treadonly codeBlock?: Partial<ThemeCodeBlock>;\n\treadonly tooltip?: Partial<ThemeTooltip>;\n}\n\n/** Partial custom theme — deeply partial for creating overrides. */\nexport interface PartialTheme {\n\treadonly name: string;\n\treadonly primitives?: Partial<ThemePrimitives>;\n\treadonly toolbar?: Partial<ThemeToolbar>;\n\treadonly codeBlock?: Partial<ThemeCodeBlock>;\n\treadonly tooltip?: Partial<ThemeTooltip>;\n}\n\n/** Built-in theme presets. */\nexport const ThemePreset = {\n\tLight: 'light',\n\tDark: 'dark',\n\tSystem: 'system',\n} as const;\nexport type ThemePreset = (typeof ThemePreset)[keyof typeof ThemePreset];\n\n/** Built-in light theme. */\nexport const LIGHT_THEME: Theme = {\n\tname: 'light',\n\tprimitives: {\n\t\tbackground: '#ffffff',\n\t\tforeground: '#1a1a1a',\n\t\tmutedForeground: '#666666',\n\t\tborder: '#d0d0d0',\n\t\tborderFocus: '#4a90d9',\n\t\tprimary: '#4a90d9',\n\t\tprimaryForeground: '#1a5fa0',\n\t\tprimaryMuted: '#d0e0f0',\n\t\tsurfaceRaised: '#f8f8f8',\n\t\tsurfaceOverlay: '#ffffff',\n\t\thoverBackground: '#e8e8e8',\n\t\tactiveBackground: '#d0e0f0',\n\t\tdanger: '#dc2626',\n\t\tdangerMuted: '#fee2e2',\n\t\tsuccess: '#1a8c1a',\n\t\tshadow: 'rgba(0, 0, 0, 0.15)',\n\t\tfocusRing: 'rgba(74, 144, 217, 0.2)',\n\t},\n\tcodeBlock: {\n\t\tbackground: '#f8fafc',\n\t\tforeground: '#334155',\n\t\theaderBackground: '#f1f5f9',\n\t\theaderForeground: '#64748b',\n\t\theaderBorder: '#e2e8f0',\n\t},\n\ttooltip: {\n\t\tbackground: '#1a1a1a',\n\t\tforeground: '#ffffff',\n\t},\n};\n\n/** Built-in dark theme. */\nexport const DARK_THEME: Theme = {\n\tname: 'dark',\n\tprimitives: {\n\t\tbackground: '#1e1e2e',\n\t\tforeground: '#cdd6f4',\n\t\tmutedForeground: '#7f849c',\n\t\tborder: '#45475a',\n\t\tborderFocus: '#89b4fa',\n\t\tprimary: '#89b4fa',\n\t\tprimaryForeground: '#89b4fa',\n\t\tprimaryMuted: 'rgba(137, 180, 250, 0.15)',\n\t\tsurfaceRaised: '#313244',\n\t\tsurfaceOverlay: '#313244',\n\t\thoverBackground: '#45475a',\n\t\tactiveBackground: 'rgba(137, 180, 250, 0.15)',\n\t\tdanger: '#f38ba8',\n\t\tdangerMuted: 'rgba(243, 139, 168, 0.15)',\n\t\tsuccess: '#a6e3a1',\n\t\tshadow: 'rgba(0, 0, 0, 0.4)',\n\t\tfocusRing: 'rgba(137, 180, 250, 0.25)',\n\t},\n\tcodeBlock: {\n\t\tbackground: '#11111b',\n\t\tforeground: '#cdd6f4',\n\t\theaderBackground: '#181825',\n\t\theaderForeground: '#7f849c',\n\t\theaderBorder: 'rgba(205, 214, 244, 0.08)',\n\t},\n\ttooltip: {\n\t\tbackground: '#585b70',\n\t\tforeground: '#cdd6f4',\n\t},\n};\n\n/** Creates a custom theme by extending a base theme with partial overrides. */\nexport function createTheme(base: Theme, overrides: PartialTheme): Theme {\n\treturn {\n\t\tname: overrides.name,\n\t\tprimitives: { ...base.primitives, ...overrides.primitives },\n\t\ttoolbar: overrides.toolbar ? { ...base.toolbar, ...overrides.toolbar } : base.toolbar,\n\t\tcodeBlock: overrides.codeBlock ? { ...base.codeBlock, ...overrides.codeBlock } : base.codeBlock,\n\t\ttooltip: overrides.tooltip ? { ...base.tooltip, ...overrides.tooltip } : base.tooltip,\n\t};\n}\n\n/** Resolves a ThemePreset string or Theme object to a full Theme. */\nexport function resolveTheme(theme: ThemePreset | Theme): Theme {\n\tif (typeof theme === 'object') return theme;\n\tswitch (theme) {\n\t\tcase ThemePreset.Light:\n\t\t\treturn LIGHT_THEME;\n\t\tcase ThemePreset.Dark:\n\t\t\treturn DARK_THEME;\n\t\tcase ThemePreset.System:\n\t\t\t// System is resolved externally via matchMedia; default to light.\n\t\t\treturn LIGHT_THEME;\n\t\tdefault:\n\t\t\treturn LIGHT_THEME;\n\t}\n}\n","/**\n * Theme engine — converts a Theme object into CSS custom properties.\n */\n\nimport type { Theme } from './ThemeTokens.js';\n\n/** Maps Theme fields to CSS custom property names. */\nconst VARIABLE_MAP: ReadonlyArray<readonly [string, string]> = [\n\t// Primitives\n\t['primitives.background', '--notectl-bg'],\n\t['primitives.foreground', '--notectl-fg'],\n\t['primitives.mutedForeground', '--notectl-fg-muted'],\n\t['primitives.border', '--notectl-border'],\n\t['primitives.borderFocus', '--notectl-border-focus'],\n\t['primitives.primary', '--notectl-primary'],\n\t['primitives.primaryForeground', '--notectl-primary-fg'],\n\t['primitives.primaryMuted', '--notectl-primary-muted'],\n\t['primitives.surfaceRaised', '--notectl-surface-raised'],\n\t['primitives.surfaceOverlay', '--notectl-surface-overlay'],\n\t['primitives.hoverBackground', '--notectl-hover-bg'],\n\t['primitives.activeBackground', '--notectl-active-bg'],\n\t['primitives.danger', '--notectl-danger'],\n\t['primitives.dangerMuted', '--notectl-danger-muted'],\n\t['primitives.success', '--notectl-success'],\n\t['primitives.shadow', '--notectl-shadow'],\n\t['primitives.focusRing', '--notectl-focus-ring'],\n\t// Component: toolbar\n\t['toolbar.background', '--notectl-toolbar-bg'],\n\t['toolbar.borderColor', '--notectl-toolbar-border'],\n\t// Component: codeBlock\n\t['codeBlock.background', '--notectl-code-block-bg'],\n\t['codeBlock.foreground', '--notectl-code-block-color'],\n\t['codeBlock.headerBackground', '--notectl-code-block-header-bg'],\n\t['codeBlock.headerForeground', '--notectl-code-block-header-color'],\n\t['codeBlock.headerBorder', '--notectl-code-block-header-border'],\n\t// Component: tooltip\n\t['tooltip.background', '--notectl-tooltip-bg'],\n\t['tooltip.foreground', '--notectl-tooltip-fg'],\n];\n\n/** Fallbacks for component tokens when not explicitly set. */\nconst COMPONENT_FALLBACKS: ReadonlyMap<string, string> = new Map([\n\t['--notectl-toolbar-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-toolbar-border', 'var(--notectl-border)'],\n\t['--notectl-code-block-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-code-block-color', 'var(--notectl-fg)'],\n\t['--notectl-code-block-header-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-code-block-header-color', 'var(--notectl-fg-muted)'],\n\t['--notectl-code-block-header-border', 'var(--notectl-border)'],\n\t['--notectl-tooltip-bg', 'var(--notectl-fg)'],\n\t['--notectl-tooltip-fg', 'var(--notectl-bg)'],\n]);\n\n/** Resolves a dotted path like 'primitives.background' from a Theme. */\nfunction resolvePath(theme: Theme, path: string): string | undefined {\n\tconst parts: string[] = path.split('.');\n\tlet current: unknown = theme;\n\tfor (const part of parts) {\n\t\tif (current === undefined || current === null) return undefined;\n\t\tif (typeof current !== 'object') return undefined;\n\t\tcurrent = (current as Record<string, unknown>)[part];\n\t}\n\treturn typeof current === 'string' ? current : undefined;\n}\n\n/** Generates CSS text with all theme custom properties on :host. */\nexport function generateThemeCSS(theme: Theme): string {\n\tconst lines: string[] = [':host {'];\n\n\tfor (const [path, cssVar] of VARIABLE_MAP) {\n\t\tconst value: string | undefined = resolvePath(theme, path);\n\t\tif (value !== undefined) {\n\t\t\tlines.push(`\\t${cssVar}: ${value};`);\n\t\t} else {\n\t\t\tconst fallback: string | undefined = COMPONENT_FALLBACKS.get(cssVar);\n\t\t\tif (fallback) {\n\t\t\t\tlines.push(`\\t${cssVar}: ${fallback};`);\n\t\t\t}\n\t\t}\n\t}\n\n\tlines.push('}');\n\treturn lines.join('\\n');\n}\n\n/** Creates a CSSStyleSheet populated with theme CSS variables. */\nexport function createThemeStyleSheet(theme: Theme): CSSStyleSheet {\n\tconst sheet: CSSStyleSheet = new CSSStyleSheet();\n\tsheet.replaceSync(generateThemeCSS(theme));\n\treturn sheet;\n}\n","/**\n * Supported locale identifiers for the notectl editor.\n * Use `Locale.BROWSER` to auto-detect from navigator.language.\n */\nexport const Locale = {\n\tEN: 'en',\n\tDE: 'de',\n\tES: 'es',\n\tFR: 'fr',\n\tZH: 'zh',\n\tRU: 'ru',\n\tAR: 'ar',\n\tHI: 'hi',\n\tBROWSER: 'browser',\n} as const;\n\nexport type Locale = (typeof Locale)[keyof typeof Locale];\n","/**\n * CSSClassCollector: maps CSS declarations to unique class names during serialization.\n * Deduplicates identical declaration sets and produces a minimal stylesheet.\n * Uses content-hash (FNV-1a) for deterministic, document-order-independent class names.\n */\n\n/** Prefix for generated style class names (avoids collisions with user classes). */\nconst CLASS_PREFIX = 'notectl-s-';\n\n/** Base for hash encoding output. */\nconst HASH_BASE = 36;\n/** Pad length for consistent 6-char hashes. */\nconst HASH_PAD_LENGTH = 6;\n\n/**\n * Normalizes a CSS declarations string by sorting individual declarations alphabetically.\n * This ensures `\"color: red; font-size: 14px\"` and `\"font-size: 14px; color: red\"` map\n * to the same class name.\n */\nfunction normalizeDeclarations(declarations: string): string {\n\treturn declarations\n\t\t.split(';')\n\t\t.map((d) => d.trim())\n\t\t.filter((d) => d.length > 0)\n\t\t.sort()\n\t\t.join('; ');\n}\n\n/** FNV-1a 32-bit offset basis. */\nconst FNV_OFFSET_BASIS = 0x811c9dc5;\n/** FNV-1a 32-bit prime. */\nconst FNV_PRIME = 0x01000193;\n\n/**\n * FNV-1a 32-bit hash function.\n * Fast, no crypto dependency, excellent distribution for short strings.\n */\nfunction fnv1aHash(input: string): string {\n\tlet hash: number = FNV_OFFSET_BASIS;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i);\n\t\thash = Math.imul(hash, FNV_PRIME);\n\t}\n\t// Convert to unsigned 32-bit, then to base-36, padded to 6 chars\n\tconst unsigned: number = hash >>> 0;\n\treturn unsigned.toString(HASH_BASE).padStart(HASH_PAD_LENGTH, '0');\n}\n\n/**\n * Stateful collector that assigns CSS class names to unique declaration sets.\n * Used during a single serialization pass, then produces the collected stylesheet.\n *\n * Class names are deterministic: the same declarations always produce the same\n * class name, regardless of encounter order across documents.\n */\nexport class CSSClassCollector {\n\t/** Maps normalized declarations → class name. */\n\tprivate readonly classMap: Map<string, string> = new Map();\n\t/** Tracks used hashes to handle the (extremely rare) collision case. */\n\tprivate readonly usedHashes: Set<string> = new Set();\n\n\t/**\n\t * Returns the class name for the given CSS declarations.\n\t * If the same (normalized) declarations were seen before, returns the existing class.\n\t */\n\tgetClassName(declarations: string): string {\n\t\tconst normalized: string = normalizeDeclarations(declarations);\n\t\tconst existing: string | undefined = this.classMap.get(normalized);\n\t\tif (existing) return existing;\n\n\t\tlet hash: string = fnv1aHash(normalized);\n\t\tlet suffix = 0;\n\t\t// Collision handling: append suffix counter if the hash is already in use\n\t\t// for a different declarations string\n\t\twhile (this.usedHashes.has(hash)) {\n\t\t\tsuffix++;\n\t\t\thash = fnv1aHash(normalized + String(suffix));\n\t\t}\n\n\t\tconst className: string = `${CLASS_PREFIX}${hash}`;\n\t\tthis.usedHashes.add(hash);\n\t\tthis.classMap.set(normalized, className);\n\t\treturn className;\n\t}\n\n\t/**\n\t * Returns the semantic alignment class name for a given alignment value.\n\t * Unlike style classes, alignment classes use descriptive names.\n\t */\n\tgetAlignmentClassName(alignment: string): string {\n\t\tconst declarations: string = `text-align: ${alignment}`;\n\t\tconst existing: string | undefined = this.classMap.get(declarations);\n\t\tif (existing) return existing;\n\n\t\tconst className = `notectl-align-${alignment}`;\n\t\tthis.classMap.set(declarations, className);\n\t\treturn className;\n\t}\n\n\t/** Produces CSS rules for all collected classes. Returns empty string if none collected. */\n\ttoCSS(): string {\n\t\tif (this.classMap.size === 0) return '';\n\n\t\tconst rules: string[] = [];\n\t\tfor (const [declarations, className] of this.classMap) {\n\t\t\trules.push(`.${className} { ${declarations}; }`);\n\t\t}\n\t\treturn rules.join('\\n');\n\t}\n\n\t/**\n\t * Returns a map from class name → CSS declarations for round-trip support.\n\t * Used by `setContentHTML` to rehydrate class-based HTML.\n\t */\n\ttoStyleMap(): ReadonlyMap<string, string> {\n\t\tconst map = new Map<string, string>();\n\t\tfor (const [declarations, className] of this.classMap) {\n\t\t\tmap.set(className, declarations);\n\t\t}\n\t\treturn map;\n\t}\n}\n","/**\n * DocumentSerializer: converts an immutable Document into sanitized HTML.\n * Pure functions — operates on Document/SchemaRegistry, no class state.\n */\n\nimport DOMPurify from 'dompurify';\nimport { isNodeOfType } from '../model/AttrRegistry.js';\nimport type { BlockNode, Document, InlineNode, TextNode } from '../model/Document.js';\nimport {\n\tgetBlockChildren,\n\tgetInlineChildren,\n\tisInlineNode,\n\tisLeafBlock,\n\tisTextNode,\n\tmarkSetsEqual,\n} from '../model/Document.js';\nimport { escapeHTML } from '../model/HTMLUtils.js';\nimport type { HTMLExportContext } from '../model/NodeSpec.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { CSSClassCollector } from './CSSClassCollector.js';\nimport type { ContentCSSResult } from './ContentHTMLTypes.js';\nimport {\n\tbuildMarkOrder,\n\tserializeMarksToClassHTML,\n\tserializeMarksToHTML,\n} from './MarkSerializer.js';\n\n/** Internal context threaded through all serialization helpers. */\ninterface SerializerContext {\n\treadonly registry?: SchemaRegistry;\n\treadonly collector?: CSSClassCollector;\n\treadonly exportCtx?: HTMLExportContext;\n}\n\n/** Known-safe alignment values accepted by the serializer (defense-in-depth). */\nexport const VALID_ALIGNMENTS: ReadonlySet<string> = new Set([\n\t'left',\n\t'center',\n\t'right',\n\t'justify',\n]);\n\n/** Creates an HTMLExportContext for inline style mode. */\nfunction createInlineExportContext(): HTMLExportContext {\n\treturn {\n\t\tstyleAttr(declarations: string): string {\n\t\t\tif (!declarations) return '';\n\t\t\treturn ` style=\"${declarations}\"`;\n\t\t},\n\t};\n}\n\n/** Creates an HTMLExportContext for CSS class mode. */\nfunction createClassExportContext(collector: CSSClassCollector): HTMLExportContext {\n\treturn {\n\t\tstyleAttr(declarations: string): string {\n\t\t\tif (!declarations) return '';\n\t\t\tconst className: string = collector.getClassName(declarations);\n\t\t\treturn ` class=\"${className}\"`;\n\t\t},\n\t};\n}\n\n/** Serializes a full document to sanitized HTML, wrapping list items in `<ul>`/`<ol>`. */\nexport function serializeDocumentToHTML(doc: Document, registry?: SchemaRegistry): string {\n\tconst exportCtx: HTMLExportContext = createInlineExportContext();\n\tconst ctx: SerializerContext = { registry, exportCtx };\n\tconst html: string = serializeBlocks(doc.children, ctx);\n\n\tconst allowedTags: string[] = registry ? registry.getAllowedTags() : ['p', 'br', 'div', 'span'];\n\tconst allowedAttrs: string[] = registry ? registry.getAllowedAttrs() : ['style'];\n\n\treturn DOMPurify.sanitize(html, {\n\t\tALLOWED_TAGS: allowedTags,\n\t\tALLOWED_ATTR: allowedAttrs,\n\t});\n}\n\n/**\n * Serializes a document to HTML with CSS class names instead of inline styles.\n * Returns the HTML and a collected stylesheet with only the rules actually used.\n */\nexport function serializeDocumentToCSS(doc: Document, registry?: SchemaRegistry): ContentCSSResult {\n\tconst collector = new CSSClassCollector();\n\tconst exportCtx: HTMLExportContext = createClassExportContext(collector);\n\tconst ctx: SerializerContext = { registry, collector, exportCtx };\n\tconst html: string = serializeBlocks(doc.children, ctx);\n\n\tconst allowedTags: string[] = registry ? registry.getAllowedTags() : ['p', 'br', 'div', 'span'];\n\tconst allowedAttrs: string[] = registry ? registry.getAllowedAttrs() : ['style', 'class'];\n\n\t// In class mode, allow `class` attribute through DOMPurify\n\tif (!allowedAttrs.includes('class')) {\n\t\tallowedAttrs.push('class');\n\t}\n\n\t// Defense-in-depth: strip `style` attribute in class mode to guarantee\n\t// zero inline styles — even from third-party plugins that forgot to use ctx.styleAttr().\n\tconst filteredAttrs: string[] = allowedAttrs.filter((a) => a !== 'style');\n\n\tconst sanitizedHTML: string = DOMPurify.sanitize(html, {\n\t\tALLOWED_TAGS: allowedTags,\n\t\tALLOWED_ATTR: filteredAttrs,\n\t});\n\n\treturn { html: sanitizedHTML, css: collector.toCSS(), styleMap: collector.toStyleMap() };\n}\n\n/** Serializes a sequence of blocks to HTML, grouping consecutive list items into wrappers. */\nfunction serializeBlocks(blocks: readonly BlockNode[], ctx: SerializerContext): string {\n\tconst parts: string[] = [];\n\tlet i = 0;\n\n\twhile (i < blocks.length) {\n\t\tconst block: BlockNode | undefined = blocks[i];\n\t\tif (!block) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isNodeOfType(block, 'list_item')) {\n\t\t\t// Collect consecutive list items\n\t\t\tconst listItems: BlockNode[] = [];\n\t\t\twhile (i < blocks.length) {\n\t\t\t\tconst item: BlockNode | undefined = blocks[i];\n\t\t\t\tif (!item || !isNodeOfType(item, 'list_item')) break;\n\t\t\t\tlistItems.push(item);\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tparts.push(serializeListGroup(listItems, ctx));\n\t\t} else {\n\t\t\tparts.push(serializeBlock(block, ctx));\n\t\t\ti++;\n\t\t}\n\t}\n\n\treturn parts.join('');\n}\n\n/**\n * Serializes a group of consecutive list items into properly nested `<ul>`/`<ol>` wrappers.\n * Uses a stack-based algorithm to handle indent-based nesting.\n * Produces valid HTML5: nested lists open *inside* the parent `<li>`.\n */\nfunction serializeListGroup(items: readonly BlockNode[], ctx: SerializerContext): string {\n\tconst parts: string[] = [];\n\tconst stack: { tag: string; indent: number }[] = [];\n\n\tfor (let idx = 0; idx < items.length; idx++) {\n\t\tconst item: BlockNode | undefined = items[idx];\n\t\tif (!item) continue;\n\n\t\tconst listType: string = (item.attrs?.listType as string) ?? 'bullet';\n\t\tconst indent: number = (item.attrs?.indent as number) ?? 0;\n\t\tconst tag: string = listType === 'ordered' ? 'ol' : 'ul';\n\n\t\t// Pop wrapper levels that are deeper than current indent,\n\t\t// or at the same level when the tag type changes\n\t\twhile (stack.length > 0) {\n\t\t\tconst top: { tag: string; indent: number } | undefined = stack[stack.length - 1];\n\t\t\tif (!top) break;\n\n\t\t\tif (top.indent > indent) {\n\t\t\t\tparts.push(`</${top.tag}></li>`);\n\t\t\t\tstack.pop();\n\t\t\t} else if (top.indent === indent && top.tag !== tag) {\n\t\t\t\tparts.push(`</${top.tag}></li>`);\n\t\t\t\tstack.pop();\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (stack.length === 0) {\n\t\t\tparts.push(`<${tag}>`);\n\t\t\tstack.push({ tag, indent });\n\t\t} else {\n\t\t\tconst top: { tag: string; indent: number } | undefined = stack[stack.length - 1];\n\t\t\tif (top && indent > top.indent) {\n\t\t\t\tparts.push(`<${tag}>`);\n\t\t\t\tstack.push({ tag, indent });\n\t\t\t}\n\t\t}\n\n\t\tconst content: string = serializeBlock(item, ctx);\n\n\t\t// Look ahead: if the next item is deeper, strip </li> so the nested\n\t\t// list opens inside this <li> (valid HTML5 nesting).\n\t\tconst nextItem: BlockNode | undefined = items[idx + 1];\n\t\tconst nextIndent: number | undefined = nextItem\n\t\t\t? ((nextItem.attrs?.indent as number) ?? 0)\n\t\t\t: undefined;\n\n\t\tif (nextIndent !== undefined && nextIndent > indent) {\n\t\t\tparts.push(stripTrailingLiClose(content));\n\t\t} else {\n\t\t\tparts.push(content);\n\t\t}\n\t}\n\n\t// Close all remaining open wrappers\n\twhile (stack.length > 0) {\n\t\tconst top: { tag: string; indent: number } | undefined = stack.pop();\n\t\tif (!top) break;\n\t\tparts.push(`</${top.tag}>`);\n\t\tif (stack.length > 0) {\n\t\t\tparts.push('</li>');\n\t\t}\n\t}\n\n\treturn parts.join('');\n}\n\n/** Removes the trailing `</li>` from serialized list item HTML. */\nfunction stripTrailingLiClose(html: string): string {\n\tconst suffix = '</li>';\n\tif (html.endsWith(suffix)) {\n\t\treturn html.slice(0, -suffix.length);\n\t}\n\treturn html;\n}\n\n/** Serializes a single block to HTML using its NodeSpec. */\nfunction serializeBlock(block: BlockNode, ctx: SerializerContext): string {\n\tconst content: string = isLeafBlock(block)\n\t\t? serializeInlineContent(block, ctx)\n\t\t: serializeBlocks(getBlockChildren(block), ctx);\n\tconst spec = ctx.registry?.getNodeSpec(block.type);\n\n\tlet html: string;\n\tif (spec?.toHTML) {\n\t\thtml = spec.toHTML(block, content, ctx.exportCtx);\n\t} else {\n\t\thtml = `<p>${content || '<br>'}</p>`;\n\t}\n\n\t// Inject alignment into the first opening tag (validated against allowlist).\n\tconst align: string | undefined = (block.attrs as Record<string, unknown>)?.align as\n\t\t| string\n\t\t| undefined;\n\tif (align && align !== 'left' && VALID_ALIGNMENTS.has(align)) {\n\t\tif (ctx.collector) {\n\t\t\t// Class mode: use semantic alignment class on the outer element only\n\t\t\tconst className: string = ctx.collector.getAlignmentClassName(align);\n\t\t\tconst firstTagEnd: number = html.indexOf('>');\n\t\t\tconst firstTag: string = html.slice(0, firstTagEnd + 1);\n\t\t\tconst existingClass: RegExpMatchArray | null = firstTag.match(/class=\"([^\"]*)\"/);\n\t\t\tif (existingClass) {\n\t\t\t\t// Merge alignment class into existing class attribute\n\t\t\t\thtml = html.replace(\n\t\t\t\t\t`class=\"${existingClass[1]}\"`,\n\t\t\t\t\t`class=\"${existingClass[1]} ${className}\"`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\thtml = html.replace(/>/, ` class=\"${className}\">`);\n\t\t\t}\n\t\t} else {\n\t\t\t// Inline mode: inject or merge style attribute\n\t\t\tconst firstTagEnd: number = html.indexOf('>');\n\t\t\tconst firstTag: string = html.slice(0, firstTagEnd + 1);\n\t\t\tconst existingStyle: RegExpMatchArray | null = firstTag.match(/style=\"([^\"]*)\"/);\n\t\t\tconst existingValue: string | undefined = existingStyle?.[1];\n\t\t\tif (existingValue !== undefined) {\n\t\t\t\t// Already has style — merge if no text-align yet\n\t\t\t\tif (!/text-align:/.test(existingValue)) {\n\t\t\t\t\thtml = html.replace(\n\t\t\t\t\t\t`style=\"${existingValue}\"`,\n\t\t\t\t\t\t`style=\"${existingValue}; text-align: ${align}\"`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\thtml = html.replace(/>/, ` style=\"text-align: ${align}\">`);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn html;\n}\n\n/** Serializes inline children (TextNode + InlineNode) of a block. */\nfunction serializeInlineContent(block: BlockNode, ctx: SerializerContext): string {\n\tconst children: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tconst merged: readonly (TextNode | InlineNode)[] = mergeAdjacentTextNodes(children);\n\tconst parts: string[] = [];\n\tconst markOrder: Map<string, number> | undefined = ctx.registry\n\t\t? buildMarkOrder(ctx.registry)\n\t\t: undefined;\n\n\tfor (const child of merged) {\n\t\tif (isInlineNode(child)) {\n\t\t\tconst inlineSpec = ctx.registry?.getInlineNodeSpec(child.inlineType);\n\t\t\tif (inlineSpec?.toHTMLString) {\n\t\t\t\tparts.push(inlineSpec.toHTMLString(child));\n\t\t\t}\n\t\t} else if (ctx.registry && ctx.collector) {\n\t\t\tparts.push(\n\t\t\t\tserializeMarksToClassHTML(child.text, child.marks, ctx.registry, ctx.collector, markOrder),\n\t\t\t);\n\t\t} else if (ctx.registry) {\n\t\t\tparts.push(serializeMarksToHTML(child.text, child.marks, ctx.registry, markOrder));\n\t\t} else if (child.text !== '') {\n\t\t\tparts.push(escapeHTML(child.text));\n\t\t}\n\t}\n\n\treturn parts.join('');\n}\n\n/**\n * Merges adjacent TextNodes that share identical mark sets.\n * InlineNodes act as merge boundaries.\n */\nfunction mergeAdjacentTextNodes(\n\tchildren: readonly (TextNode | InlineNode)[],\n): readonly (TextNode | InlineNode)[] {\n\tif (children.length <= 1) return children;\n\n\tconst result: (TextNode | InlineNode)[] = [];\n\n\tfor (const child of children) {\n\t\tif (isInlineNode(child)) {\n\t\t\tresult.push(child);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst prev: TextNode | InlineNode | undefined = result[result.length - 1];\n\t\tif (prev && isTextNode(prev) && markSetsEqual(prev.marks, child.marks)) {\n\t\t\tresult[result.length - 1] = {\n\t\t\t\ttype: 'text',\n\t\t\t\ttext: prev.text + child.text,\n\t\t\t\tmarks: prev.marks,\n\t\t\t};\n\t\t} else {\n\t\t\tresult.push(child);\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * DocumentParser: converts sanitized HTML strings into immutable Document instances.\n * Pure functions — no class state, no DOM mutation beyond a temporary `<template>`.\n */\n\nimport DOMPurify from 'dompurify';\nimport type { BlockNode, Document, InlineNode, Mark, TextNode } from '../model/Document.js';\nimport {\n\tcreateBlockNode,\n\tcreateDocument,\n\tcreateInlineNode,\n\tcreateTextNode,\n} from '../model/Document.js';\nimport type { ParseRule } from '../model/ParseRule.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { type InlineTypeName, inlineType, markType, nodeType } from '../model/TypeBrands.js';\nimport { VALID_ALIGNMENTS } from './DocumentSerializer.js';\n\n/** Options for `parseHTMLToDocument` when importing class-based HTML. */\nexport interface ParseHTMLOptions {\n\t/**\n\t * Style map from a previous `getContentHTML({ cssMode: 'classes' })` call.\n\t * Used to rehydrate class-based HTML back into styled content.\n\t */\n\treadonly styleMap?: ReadonlyMap<string, string>;\n}\n\n/** Parses an HTML string into a Document, applying sanitization and schema parse rules. */\nexport function parseHTMLToDocument(\n\thtml: string,\n\tregistry?: SchemaRegistry,\n\toptions?: ParseHTMLOptions,\n): Document {\n\tconst allowedTags: string[] = registry ? registry.getAllowedTags() : ['p', 'br', 'div', 'span'];\n\tconst allowedAttrs: string[] = registry ? registry.getAllowedAttrs() : ['style'];\n\n\t// When a styleMap is provided, also allow `class` through DOMPurify\n\t// so we can read class names and rehydrate styles before parsing.\n\tif (options?.styleMap && !allowedAttrs.includes('class')) {\n\t\tallowedAttrs.push('class');\n\t}\n\n\tconst template = document.createElement('template');\n\ttemplate.innerHTML = DOMPurify.sanitize(html, {\n\t\tALLOWED_TAGS: allowedTags,\n\t\tALLOWED_ATTR: allowedAttrs,\n\t});\n\tconst root: DocumentFragment = template.content;\n\n\t// Rehydrate class-based HTML: convert notectl class names back to inline styles\n\tif (options?.styleMap) {\n\t\trehydrateClasses(root, options.styleMap);\n\t}\n\n\tconst blockRules = registry?.getBlockParseRules() ?? [];\n\tconst blocks: BlockNode[] = [];\n\n\tfor (const child of Array.from(root.childNodes)) {\n\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\tconst el = child as HTMLElement;\n\t\t\tconst tag: string = el.tagName.toLowerCase();\n\n\t\t\t// Lists need cross-element logic — handle before parse rules\n\t\t\tif (tag === 'ul' || tag === 'ol') {\n\t\t\t\tconst listType: string = tag === 'ol' ? 'ordered' : 'bullet';\n\t\t\t\tparseListElement(el, listType, 0, blocks, registry);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Try block parse rules\n\t\t\tconst match = matchBlockParseRule(el, blockRules);\n\t\t\tif (match) {\n\t\t\t\tconst inlineContent = parseElementToInlineContent(el, registry);\n\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t...(match.attrs as Record<string, string | number | boolean> | undefined),\n\t\t\t\t};\n\t\t\t\textractAlignment(el, attrs);\n\t\t\t\tblocks.push(\n\t\t\t\t\tcreateBlockNode(\n\t\t\t\t\t\tnodeType(match.type),\n\t\t\t\t\t\tinlineContent,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tObject.keys(attrs).length > 0 ? attrs : undefined,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Fallback to paragraph\n\t\t\tconst inlineContent = parseElementToInlineContent(el, registry);\n\t\t\tconst attrs: Record<string, string | number | boolean> = {};\n\t\t\textractAlignment(el, attrs);\n\t\t\tblocks.push(\n\t\t\t\tcreateBlockNode(\n\t\t\t\t\tnodeType('paragraph'),\n\t\t\t\t\tinlineContent,\n\t\t\t\t\tundefined,\n\t\t\t\t\tObject.keys(attrs).length > 0 ? attrs : undefined,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (child.nodeType === Node.TEXT_NODE && child.textContent?.trim()) {\n\t\t\tblocks.push(\n\t\t\t\tcreateBlockNode(nodeType('paragraph'), [createTextNode(child.textContent.trim())]),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (blocks.length === 0) return createDocument();\n\treturn createDocument(blocks);\n}\n\n/**\n * Recursively parses a list element (`<ul>` or `<ol>`), creating list_item blocks\n * with correct indent depth. Handles nested lists inside `<li>` elements.\n */\nfunction parseListElement(\n\tlistEl: Element,\n\tlistType: string,\n\tdepth: number,\n\tblocks: BlockNode[],\n\tregistry?: SchemaRegistry,\n): void {\n\tfor (const child of Array.from(listEl.children)) {\n\t\tconst tag: string = child.tagName.toLowerCase();\n\n\t\tif (tag === 'li') {\n\t\t\tconst li: HTMLElement = child as HTMLElement;\n\n\t\t\t// Check for checklist: <input type=\"checkbox\">\n\t\t\tconst checkbox: HTMLInputElement | null = li.querySelector(':scope > input[type=\"checkbox\"]');\n\t\t\tconst isChecklist: boolean = checkbox !== null;\n\t\t\tconst checked: boolean = checkbox?.hasAttribute('checked') ?? false;\n\n\t\t\tconst resolvedType: string = isChecklist ? 'checklist' : listType;\n\n\t\t\tconst inlineContent = parseElementToInlineContent(li, registry, true);\n\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\tlistType: resolvedType,\n\t\t\t\tindent: depth,\n\t\t\t\tchecked,\n\t\t\t};\n\n\t\t\tblocks.push(createBlockNode(nodeType('list_item'), inlineContent, undefined, attrs));\n\n\t\t\t// Check for nested lists inside this <li>\n\t\t\tfor (const liChild of Array.from(li.children)) {\n\t\t\t\tconst liChildTag: string = liChild.tagName.toLowerCase();\n\t\t\t\tif (liChildTag === 'ul' || liChildTag === 'ol') {\n\t\t\t\t\tconst nestedType: string = liChildTag === 'ol' ? 'ordered' : 'bullet';\n\t\t\t\t\tparseListElement(liChild, nestedType, depth + 1, blocks, registry);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (tag === 'ul' || tag === 'ol') {\n\t\t\t// Direct nested list without wrapping <li> — increment depth\n\t\t\tconst nestedType: string = tag === 'ol' ? 'ordered' : 'bullet';\n\t\t\tparseListElement(child, nestedType, depth + 1, blocks, registry);\n\t\t}\n\t}\n}\n\n/**\n * Parses an HTML element's inline children into (TextNode | InlineNode)[].\n * Applies mark parse rules and inline node parse rules.\n */\nfunction parseElementToInlineContent(\n\tel: HTMLElement,\n\tregistry?: SchemaRegistry,\n\tskipNestedLists?: boolean,\n): (TextNode | InlineNode)[] {\n\tconst result: (TextNode | InlineNode)[] = [];\n\tconst markRules = registry?.getMarkParseRules() ?? [];\n\tconst inlineRules = registry?.getInlineParseRules() ?? [];\n\twalkElement(el, [], result, markRules, inlineRules, skipNestedLists);\n\treturn result.length > 0 ? result : [createTextNode('')];\n}\n\n/**\n * Recursively walks DOM nodes, collecting marks from parse rules,\n * matching inline node parse rules, and producing TextNodes/InlineNodes.\n */\nfunction walkElement(\n\tnode: Node,\n\tcurrentMarks: Mark[],\n\tresult: (TextNode | InlineNode)[],\n\tmarkRules: readonly { readonly rule: ParseRule; readonly type: string }[],\n\tinlineRules: readonly { readonly rule: ParseRule; readonly type: string }[],\n\tskipNestedLists?: boolean,\n): void {\n\tif (node.nodeType === Node.TEXT_NODE) {\n\t\tconst text: string = node.textContent ?? '';\n\t\tif (text) {\n\t\t\tresult.push(createTextNode(text, [...currentMarks]));\n\t\t}\n\t\treturn;\n\t}\n\n\tif (node.nodeType !== Node.ELEMENT_NODE) return;\n\n\tconst el = node as HTMLElement;\n\tconst tag: string = el.tagName.toLowerCase();\n\n\t// Skip nested lists inside <li> (handled by parseListElement)\n\tif (skipNestedLists && (tag === 'ul' || tag === 'ol')) return;\n\n\t// Skip checkbox inputs inside list items (already handled by parseListElement)\n\tif (skipNestedLists && tag === 'input' && el.getAttribute('type') === 'checkbox') return;\n\n\t// Try inline node parse rules first (atomic — no recursion)\n\tfor (const entry of inlineRules) {\n\t\tif (entry.rule.tag !== tag) continue;\n\n\t\tif (entry.rule.getAttrs) {\n\t\t\tconst attrs = entry.rule.getAttrs(el);\n\t\t\tif (attrs === false) continue;\n\t\t\tresult.push(\n\t\t\t\tcreateInlineNode(\n\t\t\t\t\tinlineType(entry.type) as InlineTypeName,\n\t\t\t\t\tattrs as Readonly<Record<string, string | number | boolean>>,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tresult.push(createInlineNode(inlineType(entry.type) as InlineTypeName));\n\t\treturn;\n\t}\n\n\tconst marks: Mark[] = [...currentMarks];\n\n\t// Try mark parse rules — collect all matching marks for this element\n\tconst matchedTypes = new Set<string>();\n\tfor (const entry of markRules) {\n\t\tif (entry.rule.tag !== tag) continue;\n\t\tif (matchedTypes.has(entry.type)) continue;\n\n\t\tif (entry.rule.getAttrs) {\n\t\t\tconst attrs = entry.rule.getAttrs(el);\n\t\t\tif (attrs === false) continue;\n\t\t\tif (!marks.some((m) => m.type === entry.type)) {\n\t\t\t\tmarks.push({\n\t\t\t\t\ttype: markType(entry.type),\n\t\t\t\t\t...(Object.keys(attrs).length > 0 ? { attrs } : {}),\n\t\t\t\t} as Mark);\n\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t}\n\t\t} else {\n\t\t\tif (!marks.some((m) => m.type === entry.type)) {\n\t\t\t\tmarks.push({ type: markType(entry.type) });\n\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const child of Array.from(el.childNodes)) {\n\t\twalkElement(child, marks, result, markRules, inlineRules, skipNestedLists);\n\t}\n}\n\n/** Extracts validated `text-align` from an element's style or class and adds it to attrs. */\nfunction extractAlignment(el: HTMLElement, attrs: Record<string, string | number | boolean>): void {\n\t// Check inline style first (works for both normal and rehydrated HTML)\n\tconst align: string = el.style?.textAlign ?? '';\n\tif (align && VALID_ALIGNMENTS.has(align)) {\n\t\tattrs.align = align;\n\t\treturn;\n\t}\n\n\t// Check for notectl-align-* class names (from class-based HTML)\n\tfor (const cls of Array.from(el.classList)) {\n\t\tconst match: RegExpMatchArray | null = cls.match(/^notectl-align-(\\w+)$/);\n\t\tconst alignValue: string | undefined = match?.[1];\n\t\tif (alignValue && VALID_ALIGNMENTS.has(alignValue)) {\n\t\t\tattrs.align = alignValue;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/**\n * Rehydrates class-based HTML by converting notectl class names back to inline styles.\n * This allows existing parse rules (which read inline styles) to work unchanged.\n */\nfunction rehydrateClasses(root: DocumentFragment, styleMap: ReadonlyMap<string, string>): void {\n\tconst elements: NodeListOf<Element> = root.querySelectorAll('[class]');\n\tfor (const el of Array.from(elements)) {\n\t\tconst htmlEl = el as HTMLElement;\n\t\tconst classes: string[] = Array.from(htmlEl.classList);\n\t\tconst toRemove: string[] = [];\n\n\t\tfor (const cls of classes) {\n\t\t\tconst declarations: string | undefined = styleMap.get(cls);\n\t\t\tif (declarations) {\n\t\t\t\t// Append declarations to existing inline style\n\t\t\t\tconst existing: string = htmlEl.getAttribute('style') ?? '';\n\t\t\t\tconst separator: string = existing && !existing.endsWith(';') ? '; ' : '';\n\t\t\t\thtmlEl.setAttribute('style', existing + separator + declarations);\n\t\t\t\ttoRemove.push(cls);\n\t\t\t}\n\t\t}\n\n\t\t// Remove rehydrated class names\n\t\tfor (const cls of toRemove) {\n\t\t\thtmlEl.classList.remove(cls);\n\t\t}\n\t}\n}\n\n/** Matches an element against block parse rules. Returns matched type and attrs. */\nfunction matchBlockParseRule(\n\tel: HTMLElement,\n\trules: readonly { readonly rule: ParseRule; readonly type: string }[],\n): { readonly type: string; readonly attrs?: Record<string, unknown> } | null {\n\tconst tag: string = el.tagName.toLowerCase();\n\tfor (const entry of rules) {\n\t\tif (entry.rule.tag !== tag) continue;\n\t\tif (entry.rule.getAttrs) {\n\t\t\tconst attrs = entry.rule.getAttrs(el);\n\t\t\tif (attrs === false) continue;\n\t\t\treturn { type: entry.type, attrs };\n\t\t}\n\t\treturn { type: entry.type };\n\t}\n\treturn null;\n}\n","/**\n * ContentStyleInjector: CSP-compliant utilities for injecting collected CSS\n * into the document. Supports nonce-based `<style>` elements and adoptedStyleSheets.\n */\n\n/** Options for {@link injectContentStyles}. */\nexport interface InjectStylesOptions {\n\t/** Nonce value for CSP compliance. Added as `nonce` attribute on the `<style>` element. */\n\treadonly nonce?: string;\n\t/** Target document. Defaults to `globalThis.document`. */\n\treadonly document?: Document;\n\t/** Container element to append the `<style>` to. Defaults to `document.head`. */\n\treadonly container?: HTMLElement;\n\t/**\n\t * Unique ID for the `<style>` element. When provided and an element with this ID\n\t * already exists, its content is replaced (avoiding duplicates on re-renders).\n\t */\n\treadonly id?: string;\n}\n\n/**\n * Injects CSS into the document via a `<style>` element.\n * Returns the created/updated element for manual cleanup.\n *\n * @example\n * ```ts\n * const result = editor.getContentHTML({ cssMode: 'classes' });\n * const style = injectContentStyles(result.css, { nonce: 'abc123' });\n * // Later: removeContentStyles('notectl-content', document);\n * ```\n */\nexport function injectContentStyles(css: string, options?: InjectStylesOptions): HTMLStyleElement {\n\tconst doc: Document = options?.document ?? globalThis.document;\n\tconst container: HTMLElement = options?.container ?? doc.head;\n\n\t// Reuse existing element if ID matches\n\tif (options?.id) {\n\t\tconst existing: HTMLElement | null = doc.getElementById(options.id);\n\t\tif (existing instanceof HTMLStyleElement) {\n\t\t\texisting.textContent = css;\n\t\t\tif (options.nonce) {\n\t\t\t\texisting.setAttribute('nonce', options.nonce);\n\t\t\t}\n\t\t\treturn existing;\n\t\t}\n\t}\n\n\tconst style: HTMLStyleElement = doc.createElement('style');\n\tstyle.textContent = css;\n\n\tif (options?.id) {\n\t\tstyle.id = options.id;\n\t}\n\tif (options?.nonce) {\n\t\tstyle.setAttribute('nonce', options.nonce);\n\t}\n\n\tcontainer.appendChild(style);\n\treturn style;\n}\n\n/**\n * Removes a previously injected `<style>` element by its ID.\n *\n * @param id - The ID of the `<style>` element to remove.\n * @param doc - Target document. Defaults to `globalThis.document`.\n */\nexport function removeContentStyles(id: string, doc?: Document): void {\n\tconst target: Document = doc ?? globalThis.document;\n\tconst element: HTMLElement | null = target.getElementById(id);\n\tif (element) {\n\t\telement.remove();\n\t}\n}\n\n/** Options for {@link adoptContentStyles}. */\nexport interface AdoptStylesOptions {\n\t/** Target document or ShadowRoot. Defaults to `globalThis.document`. */\n\treadonly target?: Document | ShadowRoot;\n\t/**\n\t * When true, replaces any previously adopted notectl sheet on the same target.\n\t * When false (default), appends a new sheet.\n\t */\n\treadonly replace?: boolean;\n}\n\n/** WeakSet tracking sheets created by {@link adoptContentStyles}. */\nconst notectlSheets: WeakSet<CSSStyleSheet> = new WeakSet();\n\n/**\n * Injects CSS via `adoptedStyleSheets` — no DOM element, no nonce needed.\n * Works with both `Document` and `ShadowRoot`, making it ideal for Web Components.\n *\n * Returns the created `CSSStyleSheet` for manual cleanup via {@link removeAdoptedStyles}.\n *\n * @example\n * ```ts\n * const result = editor.getContentHTML({ cssMode: 'classes' });\n * const sheet = adoptContentStyles(result.css);\n * // Later: removeAdoptedStyles(sheet);\n * ```\n */\nexport function adoptContentStyles(css: string, options?: AdoptStylesOptions): CSSStyleSheet {\n\tconst target: Document | ShadowRoot = options?.target ?? globalThis.document;\n\tconst sheet = new CSSStyleSheet();\n\tsheet.replaceSync(css);\n\tnotectlSheets.add(sheet);\n\n\tif (options?.replace) {\n\t\ttarget.adoptedStyleSheets = target.adoptedStyleSheets.filter((s) => !notectlSheets.has(s));\n\t}\n\n\ttarget.adoptedStyleSheets = [...target.adoptedStyleSheets, sheet];\n\treturn sheet;\n}\n\n/**\n * Removes a specific adopted stylesheet from its target.\n *\n * @param sheet - The `CSSStyleSheet` returned by {@link adoptContentStyles}.\n * @param target - Target document or ShadowRoot. Defaults to `globalThis.document`.\n */\nexport function removeAdoptedStyles(sheet: CSSStyleSheet, target?: Document | ShadowRoot): void {\n\tconst root: Document | ShadowRoot = target ?? globalThis.document;\n\troot.adoptedStyleSheets = root.adoptedStyleSheets.filter((s) => s !== sheet);\n}\n","/**\n * Input handler: intercepts all beforeinput events, maps them to transactions.\n * After text insertion, checks registered InputRules for pattern matches.\n */\n\nimport {\n\tdeleteBackward,\n\tdeleteForward,\n\tdeleteSoftLineBackward,\n\tdeleteSoftLineForward,\n\tdeleteWordBackward,\n\tdeleteWordForward,\n\tinsertHardBreakCommand,\n\tinsertTextCommand,\n\tsplitBlockCommand,\n} from '../commands/Commands.js';\nimport { getBlockText } from '../model/Document.js';\nimport { isGapCursor, isNodeSelection } from '../model/Selection.js';\nimport type { Transaction } from '../state/Transaction.js';\n\nimport type { EditorState } from '../state/EditorState.js';\nimport { CompositionTracker } from './CompositionTracker.js';\nimport type { InputRuleRegistry } from './InputRuleRegistry.js';\n\nexport type DispatchFn = (tr: Transaction) => void;\nexport type GetStateFn = () => EditorState;\nexport type UndoFn = () => void;\nexport type RedoFn = () => void;\n\nexport type SyncSelectionFn = () => void;\n\nexport interface InputHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tsyncSelection: SyncSelectionFn;\n\tinputRuleRegistry?: InputRuleRegistry;\n\tisReadOnly?: () => boolean;\n\tcompositionTracker?: CompositionTracker;\n}\n\nexport class InputHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly syncSelection: SyncSelectionFn;\n\tprivate readonly inputRuleRegistry?: InputRuleRegistry;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate readonly compositionTracker: CompositionTracker;\n\n\tprivate readonly handleBeforeInput: (e: InputEvent) => void;\n\tprivate readonly handleCompositionStart: (e: CompositionEvent) => void;\n\tprivate readonly handleCompositionEnd: (e: CompositionEvent) => void;\n\n\tconstructor(\n\t\tprivate readonly element: HTMLElement,\n\t\toptions: InputHandlerOptions,\n\t) {\n\t\tthis.getState = options.getState;\n\t\tthis.dispatch = options.dispatch;\n\t\tthis.syncSelection = options.syncSelection;\n\t\tthis.inputRuleRegistry = options.inputRuleRegistry;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\t\tthis.compositionTracker = options.compositionTracker ?? new CompositionTracker();\n\n\t\tthis.handleBeforeInput = this.onBeforeInput.bind(this);\n\t\tthis.handleCompositionStart = this.onCompositionStart.bind(this);\n\t\tthis.handleCompositionEnd = this.onCompositionEnd.bind(this);\n\n\t\telement.addEventListener('beforeinput', this.handleBeforeInput);\n\t\telement.addEventListener('compositionstart', this.handleCompositionStart);\n\t\telement.addEventListener('compositionend', this.handleCompositionEnd);\n\t}\n\n\tprivate onBeforeInput(e: InputEvent): void {\n\t\tif (this.isReadOnly()) return;\n\n\t\t// During composition, let the browser handle it\n\t\tif (this.compositionTracker.isComposing && e.inputType === 'insertCompositionText') {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\t// Sync selection from DOM before processing non-insert operations\n\t\t// (handles arrow key / mouse navigation that doesn't go through our state)\n\t\tconst needsSelectionSync =\n\t\t\te.inputType !== 'insertText' && e.inputType !== 'insertCompositionText';\n\t\tif (needsSelectionSync) {\n\t\t\tthis.syncSelection();\n\t\t}\n\n\t\tconst state = this.getState();\n\t\tlet tr: Transaction | null = null;\n\n\t\tswitch (e.inputType) {\n\t\t\tcase 'insertText':\n\t\t\t\tif (e.data) {\n\t\t\t\t\ttr = insertTextCommand(state, e.data, 'input');\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'insertParagraph':\n\t\t\t\ttr = splitBlockCommand(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'insertLineBreak':\n\t\t\t\ttr = insertHardBreakCommand(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteContentBackward':\n\t\t\t\ttr = deleteBackward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteContentForward':\n\t\t\t\ttr = deleteForward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteWordBackward':\n\t\t\t\ttr = deleteWordBackward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteWordForward':\n\t\t\t\ttr = deleteWordForward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteSoftLineBackward':\n\t\t\t\ttr = deleteSoftLineBackward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteSoftLineForward':\n\t\t\t\ttr = deleteSoftLineForward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'deleteByCut':\n\t\t\t\ttr = deleteBackward(state);\n\t\t\t\tbreak;\n\n\t\t\tcase 'insertFromPaste':\n\t\t\t\t// Handled by PasteHandler\n\t\t\t\tbreak;\n\n\t\t\tcase 'insertFromDrop':\n\t\t\t\t// Handled by PasteHandler\n\t\t\t\tbreak;\n\n\t\t\tcase 'formatBold':\n\t\t\tcase 'formatItalic':\n\t\t\tcase 'formatUnderline':\n\t\t\tcase 'historyUndo':\n\t\t\tcase 'historyRedo':\n\t\t\t\t// Handled by KeyboardHandler — just prevent default\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (tr) {\n\t\t\tthis.dispatch(tr);\n\n\t\t\t// Check input rules after text insertion\n\t\t\tif (e.inputType === 'insertText') {\n\t\t\t\tthis.checkInputRules();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onCompositionStart(_e: CompositionEvent): void {\n\t\tconst state = this.getState();\n\t\tif (isNodeSelection(state.selection) || isGapCursor(state.selection)) return;\n\t\tthis.compositionTracker.start(state.selection.anchor.blockId);\n\t}\n\n\tprivate onCompositionEnd(e: CompositionEvent): void {\n\t\tthis.compositionTracker.end();\n\t\tif (this.isReadOnly()) return;\n\t\tconst composedText = e.data;\n\t\tif (!composedText) return;\n\n\t\tconst state = this.getState();\n\t\tconst tr = insertTextCommand(state, composedText, 'input');\n\t\tthis.dispatch(tr);\n\t}\n\n\tprivate checkInputRules(): void {\n\t\tif (!this.inputRuleRegistry) return;\n\t\tconst rules = this.inputRuleRegistry.getInputRules();\n\t\tif (rules.length === 0) return;\n\n\t\tconst state = this.getState();\n\t\tif (isNodeSelection(state.selection) || isGapCursor(state.selection)) return;\n\t\tconst { anchor } = state.selection;\n\t\tconst block = state.getBlock(anchor.blockId);\n\t\tif (!block) return;\n\n\t\tconst text = getBlockText(block);\n\t\tconst textBefore = text.slice(0, anchor.offset);\n\n\t\tfor (const rule of rules) {\n\t\t\tconst match = rule.pattern.exec(textBefore);\n\t\t\tif (match) {\n\t\t\t\tconst start = match.index;\n\t\t\t\tconst end = start + match[0].length;\n\t\t\t\tconst tr = rule.handler(state, match, start, end);\n\t\t\t\tif (tr) {\n\t\t\t\t\tthis.dispatch(tr);\n\t\t\t\t\treturn; // Only first matching rule fires\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.element.removeEventListener('beforeinput', this.handleBeforeInput);\n\t\tthis.element.removeEventListener('compositionstart', this.handleCompositionStart);\n\t\tthis.element.removeEventListener('compositionend', this.handleCompositionEnd);\n\t}\n}\n","/**\n * ContentSlice: an immutable fragment of document content for paste operations.\n * Represents \"what to insert\" independent of where it will be inserted.\n */\n\nimport type { BlockAttrs, TextSegment } from './Document.js';\nimport type { NodeTypeName } from './TypeBrands.js';\nimport { nodeType } from './TypeBrands.js';\n\nexport interface SliceBlock {\n\treadonly type: NodeTypeName;\n\treadonly attrs?: BlockAttrs;\n\treadonly segments: readonly TextSegment[];\n}\n\nexport interface ContentSlice {\n\treadonly blocks: readonly SliceBlock[];\n}\n\n/** Concatenates all segment texts within a slice block. */\nexport function segmentsToText(segments: readonly TextSegment[]): string {\n\treturn segments.reduce((acc: string, s: TextSegment) => acc + s.text, '');\n}\n\n/** Returns the total text length of a slice block's segments. */\nexport function segmentsLength(segments: readonly TextSegment[]): number {\n\treturn segments.reduce((acc: number, s: TextSegment) => acc + s.text.length, 0);\n}\n\n/** Creates a single-paragraph content slice from plain text. */\nexport function plainTextSlice(text: string): ContentSlice {\n\tconst lines: readonly string[] = text.split(/\\r?\\n/);\n\tconst blocks: readonly SliceBlock[] = lines.map(\n\t\t(line: string): SliceBlock => ({\n\t\t\ttype: nodeType('paragraph'),\n\t\t\tsegments: [{ text: line, marks: [] }],\n\t\t}),\n\t);\n\treturn {\n\t\tblocks:\n\t\t\tblocks.length > 0\n\t\t\t\t? blocks\n\t\t\t\t: [{ type: nodeType('paragraph'), segments: [{ text: '', marks: [] }] }],\n\t};\n}\n","/**\n * PasteCommand: builds transactions from a ContentSlice and EditorState.\n * Handles three strategies: inline paste, single-block paste, multi-block paste.\n */\n\nimport type { ContentSlice, SliceBlock } from '../model/ContentSlice.js';\nimport { segmentsLength, segmentsToText } from '../model/ContentSlice.js';\nimport {\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgenerateBlockId,\n\tisBlockNode,\n} from '../model/Document.js';\nimport type { TextSegment } from '../model/Document.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { GapCursorSelection } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport { nodeType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction, TransactionBuilder } from '../state/Transaction.js';\nimport { resolveInsertPoint } from './CommandHelpers.js';\nimport { addDeleteSelectionSteps } from './Commands.js';\n\n/**\n * Builds a transaction that pastes the given ContentSlice into the editor state.\n * Selects the appropriate strategy based on the slice structure.\n */\nexport function pasteSlice(state: EditorState, slice: ContentSlice): Transaction {\n\tif (slice.blocks.length === 0) {\n\t\treturn state.transaction('paste').setSelection(state.selection).build();\n\t}\n\n\tconst firstBlock: SliceBlock | undefined = slice.blocks[0];\n\tif (!firstBlock) {\n\t\treturn state.transaction('paste').setSelection(state.selection).build();\n\t}\n\n\tif (slice.blocks.length === 1 && firstBlock.type === nodeType('paragraph')) {\n\t\treturn pasteInline(state, firstBlock.segments);\n\t}\n\tif (slice.blocks.length === 1) {\n\t\treturn pasteSingleBlock(state, firstBlock);\n\t}\n\treturn pasteMultiBlock(state, slice);\n}\n\n/** Case 1: single paragraph — insert segments into current block. */\nfunction pasteInline(state: EditorState, segments: readonly TextSegment[]): Transaction {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\tif (isGapCursor(sel)) {\n\t\treturn pasteInlineAtGap(state, sel, segments);\n\t}\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst { blockId: insertBlockId, offset: insertOffset } = resolveInsertPoint(\n\t\tsel,\n\t\tstate.getBlockOrder(),\n\t);\n\tconst totalLength: number = segmentsLength(segments);\n\tconst text: string = segmentsToText(segments);\n\n\tbuilder.insertText(insertBlockId, insertOffset, text, [], segments);\n\tbuilder.setSelection(createCollapsedSelection(insertBlockId, insertOffset + totalLength));\n\n\treturn builder.build();\n}\n\n/** Case 2: single non-paragraph block — change block type and insert segments. */\nfunction pasteSingleBlock(state: EditorState, block: SliceBlock): Transaction {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\tif (isGapCursor(sel)) {\n\t\treturn pasteBlocksAtGap(state, sel, [block]);\n\t}\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst { blockId: insertBlockId, offset: insertOffset } = resolveInsertPoint(\n\t\tsel,\n\t\tstate.getBlockOrder(),\n\t);\n\tconst totalLength: number = segmentsLength(block.segments);\n\tconst text: string = segmentsToText(block.segments);\n\n\tbuilder.setBlockType(insertBlockId, block.type, block.attrs);\n\tbuilder.insertText(insertBlockId, insertOffset, text, [], block.segments);\n\tbuilder.setSelection(createCollapsedSelection(insertBlockId, insertOffset + totalLength));\n\n\treturn builder.build();\n}\n\n/** Case 3: multiple blocks — split-insert-merge strategy. */\nfunction pasteMultiBlock(state: EditorState, slice: ContentSlice): Transaction {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\tif (isGapCursor(sel)) {\n\t\treturn pasteBlocksAtGap(state, sel, slice.blocks);\n\t}\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst blockOrder = state.getBlockOrder();\n\tconst { blockId, offset } = resolveInsertPoint(sel, blockOrder);\n\tconst blockIdx: number = blockOrder.indexOf(blockId);\n\n\tconst firstSlice: SliceBlock | undefined = slice.blocks[0];\n\tconst lastSlice: SliceBlock | undefined = slice.blocks[slice.blocks.length - 1];\n\tif (!firstSlice || !lastSlice) {\n\t\treturn builder.build();\n\t}\n\tconst middleSlices: readonly SliceBlock[] = slice.blocks.slice(1, -1);\n\n\t// 1. Insert first slice's segments into current block\n\tconst firstLen: number = segmentsLength(firstSlice.segments);\n\tif (firstSlice.segments.length > 0 && firstLen > 0) {\n\t\tbuilder.insertText(\n\t\t\tblockId,\n\t\t\toffset,\n\t\t\tsegmentsToText(firstSlice.segments),\n\t\t\t[],\n\t\t\tfirstSlice.segments,\n\t\t);\n\t}\n\n\t// 2. Change block type if first slice is not a paragraph\n\tif (firstSlice.type !== nodeType('paragraph')) {\n\t\tbuilder.setBlockType(blockId, firstSlice.type, firstSlice.attrs);\n\t}\n\n\t// 3. Split current block after inserted text\n\tconst splitOffset: number = offset + firstLen;\n\tconst tailBlockId = generateBlockId();\n\tbuilder.splitBlock(blockId, splitOffset, tailBlockId);\n\n\t// 4. Insert middle blocks between first and tail\n\tlet insertAt: number = blockIdx + 1;\n\tfor (const mid of middleSlices) {\n\t\tconst textNodes = mid.segments.map((s: TextSegment) => createTextNode(s.text, [...s.marks]));\n\t\tconst newBlock = createBlockNode(\n\t\t\tmid.type,\n\t\t\ttextNodes.length > 0 ? textNodes : undefined,\n\t\t\tgenerateBlockId(),\n\t\t\tmid.attrs,\n\t\t);\n\t\tbuilder.insertNode([], insertAt, newBlock);\n\t\tinsertAt++;\n\t}\n\n\t// 5. Insert last slice's segments at start of tail block\n\tconst lastLen: number = segmentsLength(lastSlice.segments);\n\tif (lastSlice.segments.length > 0 && lastLen > 0) {\n\t\tbuilder.insertText(tailBlockId, 0, segmentsToText(lastSlice.segments), [], lastSlice.segments);\n\t}\n\n\t// 6. Change tail block type if needed\n\tif (lastSlice.type !== nodeType('paragraph')) {\n\t\tbuilder.setBlockType(tailBlockId, lastSlice.type, lastSlice.attrs);\n\t}\n\n\t// 7. Set cursor to end of inserted content\n\tbuilder.setSelection(createCollapsedSelection(tailBlockId, lastLen));\n\n\treturn builder.build();\n}\n\n// --- GapCursor Paste Helpers ---\n\n/**\n * Resolves the insert position for a GapCursor: parent path and index\n * within siblings where new blocks should be inserted.\n */\nfunction gapInsertIndex(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n): { parentPath: BlockId[]; insertIndex: number } | null {\n\tconst path = findNodePath(state.doc, sel.blockId);\n\tif (!path) return null;\n\n\tconst parentPath: BlockId[] = path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\n\tconst siblings =\n\t\tparentPath.length === 0\n\t\t\t? state.doc.children\n\t\t\t: (() => {\n\t\t\t\t\tconst parent = state.getBlock(parentPath[parentPath.length - 1] as BlockId);\n\t\t\t\t\treturn parent ? parent.children : [];\n\t\t\t\t})();\n\n\tconst index: number = siblings.findIndex((c) => isBlockNode(c) && c.id === sel.blockId);\n\tif (index < 0) return null;\n\n\tconst insertIndex: number = sel.side === 'before' ? index : index + 1;\n\treturn { parentPath, insertIndex };\n}\n\n/** Pastes inline segments (single paragraph) at a GapCursor position. */\nfunction pasteInlineAtGap(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n\tsegments: readonly TextSegment[],\n): Transaction {\n\tconst gap = gapInsertIndex(state, sel);\n\tif (!gap) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\n\tconst newId: BlockId = generateBlockId();\n\tconst text: string = segmentsToText(segments);\n\tconst totalLength: number = segmentsLength(segments);\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tbuilder.insertNode(\n\t\tgap.parentPath,\n\t\tgap.insertIndex,\n\t\tcreateBlockNode(nodeType('paragraph') as NodeTypeName, [createTextNode('')], newId),\n\t);\n\tif (text.length > 0) {\n\t\tbuilder.insertText(newId, 0, text, [], segments);\n\t}\n\tbuilder.setSelection(createCollapsedSelection(newId, totalLength));\n\n\treturn builder.build();\n}\n\n/** Pastes one or more blocks at a GapCursor position. */\nfunction pasteBlocksAtGap(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n\tblocks: readonly SliceBlock[],\n): Transaction {\n\tconst gap = gapInsertIndex(state, sel);\n\tif (!gap) {\n\t\treturn state.transaction('paste').setSelection(sel).build();\n\t}\n\n\tconst builder: TransactionBuilder = state.transaction('paste');\n\tlet insertAt: number = gap.insertIndex;\n\tlet lastBlockId: BlockId | undefined;\n\tlet lastTextLen = 0;\n\n\tfor (const block of blocks) {\n\t\tconst newId: BlockId = generateBlockId();\n\t\tconst text: string = segmentsToText(block.segments);\n\t\tconst textNodes = block.segments.map((s: TextSegment) => createTextNode(s.text, [...s.marks]));\n\t\tconst newBlock = createBlockNode(\n\t\t\tblock.type,\n\t\t\ttextNodes.length > 0 ? textNodes : [createTextNode('')],\n\t\t\tnewId,\n\t\t\tblock.attrs,\n\t\t);\n\t\tbuilder.insertNode(gap.parentPath, insertAt, newBlock);\n\t\tinsertAt++;\n\t\tlastBlockId = newId;\n\t\tlastTextLen = text.length;\n\t}\n\n\tif (lastBlockId) {\n\t\tbuilder.setSelection(createCollapsedSelection(lastBlockId, lastTextLen));\n\t}\n\n\treturn builder.build();\n}\n","/**\n * HTMLParser: converts sanitized HTML DOM into a ContentSlice.\n * Works on DOM nodes (not strings), is schema-aware, and produces immutable output.\n */\n\nimport type { ContentSlice, SliceBlock } from './ContentSlice.js';\nimport type { Mark, TextSegment } from './Document.js';\nimport { markSetsEqual } from './Document.js';\nimport type { ParseRule } from './ParseRule.js';\nimport type { Schema } from './Schema.js';\nimport { isMarkAllowed, isNodeTypeAllowed } from './Schema.js';\nimport type { SchemaRegistry } from './SchemaRegistry.js';\nimport type { NodeTypeName } from './TypeBrands.js';\nimport { markType, nodeType } from './TypeBrands.js';\n\nexport interface HTMLParserOptions {\n\treadonly schema: Schema;\n\treadonly schemaRegistry?: SchemaRegistry;\n}\n\nconst BLOCK_ELEMENTS: ReadonlySet<string> = new Set([\n\t'P',\n\t'DIV',\n\t'H1',\n\t'H2',\n\t'H3',\n\t'H4',\n\t'H5',\n\t'H6',\n\t'BLOCKQUOTE',\n\t'UL',\n\t'OL',\n\t'LI',\n\t'HR',\n\t'PRE',\n\t'TABLE',\n\t'THEAD',\n\t'TBODY',\n\t'TR',\n]);\n\nconst INLINE_ELEMENTS: ReadonlySet<string> = new Set([\n\t'STRONG',\n\t'B',\n\t'EM',\n\t'I',\n\t'U',\n\t'S',\n\t'STRIKE',\n\t'DEL',\n\t'A',\n\t'SPAN',\n\t'BR',\n\t'SUB',\n\t'SUP',\n\t'CODE',\n]);\n\nexport class HTMLParser {\n\tprivate readonly schema: Schema;\n\tprivate readonly blockParseRules: readonly {\n\t\treadonly rule: ParseRule;\n\t\treadonly type: string;\n\t}[];\n\tprivate readonly markParseRules: readonly {\n\t\treadonly rule: ParseRule;\n\t\treadonly type: string;\n\t}[];\n\n\tconstructor(options: HTMLParserOptions) {\n\t\tthis.schema = options.schema;\n\t\tthis.blockParseRules = options.schemaRegistry?.getBlockParseRules() ?? [];\n\t\tthis.markParseRules = options.schemaRegistry?.getMarkParseRules() ?? [];\n\t}\n\n\t/** Parses an HTML fragment and returns a ContentSlice. */\n\tparse(container: DocumentFragment | HTMLElement): ContentSlice {\n\t\tconst blocks: SliceBlock[] = this.parseContainer(container);\n\n\t\tif (blocks.length === 0) {\n\t\t\treturn {\n\t\t\t\tblocks: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\t\t\t\tsegments: [{ text: '', marks: [] }],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\n\t\treturn { blocks };\n\t}\n\n\tprivate parseContainer(container: DocumentFragment | HTMLElement): SliceBlock[] {\n\t\tconst blocks: SliceBlock[] = [];\n\t\tlet pendingSegments: TextSegment[] = [];\n\n\t\tfor (const child of Array.from(container.childNodes)) {\n\t\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst el = child as HTMLElement;\n\n\t\t\t\tif (this.isBlockElement(el)) {\n\t\t\t\t\tthis.flushPendingSegments(blocks, pendingSegments);\n\t\t\t\t\tpendingSegments = [];\n\t\t\t\t\tblocks.push(...this.parseBlockElement(el));\n\t\t\t\t} else if (el.children.length > 0 && this.containsBlockDescendants(el)) {\n\t\t\t\t\tthis.flushPendingSegments(blocks, pendingSegments);\n\t\t\t\t\tpendingSegments = [];\n\t\t\t\t\tblocks.push(...this.parseContainerWithMarks(el, this.marksFromElement(el)));\n\t\t\t\t} else {\n\t\t\t\t\tpendingSegments.push(...this.parseInlineNode(child, []));\n\t\t\t\t}\n\t\t\t} else if (child.nodeType === Node.TEXT_NODE) {\n\t\t\t\tconst text: string = child.textContent ?? '';\n\t\t\t\tif (text) {\n\t\t\t\t\tpendingSegments.push({ text, marks: [] });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.flushPendingSegments(blocks, pendingSegments);\n\t\treturn blocks;\n\t}\n\n\tprivate parseBlockElement(element: HTMLElement): SliceBlock[] {\n\t\tconst tag: string = element.tagName;\n\n\t\tconst headingMatch: RegExpExecArray | null = /^H([1-6])$/.exec(tag);\n\t\tif (headingMatch) {\n\t\t\tconst level: number = Number(headingMatch[1]);\n\t\t\tconst blockType: NodeTypeName = this.resolveBlockType(nodeType('heading'));\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\ttype: blockType,\n\t\t\t\t\t...(blockType === nodeType('heading') ? { attrs: { level } } : {}),\n\t\t\t\t\tsegments: this.ensureSegments(this.parseInlineChildren(element, [])),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\n\t\tswitch (tag) {\n\t\t\tcase 'P':\n\t\t\tcase 'DIV':\n\t\t\t\treturn this.parseBlockWithLineBreaks(element, this.resolveBlockType(nodeType('paragraph')));\n\n\t\t\tcase 'BLOCKQUOTE':\n\t\t\t\treturn this.parseBlockquote(element);\n\n\t\t\tcase 'UL':\n\t\t\t\treturn this.parseList(element, 'bullet', 0);\n\n\t\t\tcase 'OL':\n\t\t\t\treturn this.parseList(element, 'ordered', 0);\n\n\t\t\tcase 'LI':\n\t\t\t\treturn this.parseListItem(element, 'bullet', 0);\n\n\t\t\tcase 'HR':\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: this.resolveBlockType(nodeType('horizontal_rule')),\n\t\t\t\t\t\tsegments: [],\n\t\t\t\t\t},\n\t\t\t\t];\n\n\t\t\tcase 'PRE':\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\t\t\t\tsegments: this.ensureSegments(this.parsePreContent(element)),\n\t\t\t\t\t},\n\t\t\t\t];\n\n\t\t\tcase 'TABLE':\n\t\t\tcase 'THEAD':\n\t\t\tcase 'TBODY':\n\t\t\tcase 'TR':\n\t\t\t\treturn this.parseTableAsParagraphs(element);\n\n\t\t\tdefault: {\n\t\t\t\t// Try block parse rules before falling back to paragraph\n\t\t\t\tconst blockMatch = this.matchBlockRule(element);\n\t\t\t\tif (blockMatch) {\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: blockMatch.type,\n\t\t\t\t\t\t\t...(blockMatch.attrs ? { attrs: blockMatch.attrs } : {}),\n\t\t\t\t\t\t\tsegments: this.ensureSegments(this.parseInlineChildren(element, [])),\n\t\t\t\t\t\t},\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\t\t\t\tsegments: this.ensureSegments(this.parseInlineChildren(element, [])),\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate parseBlockquote(element: HTMLElement): SliceBlock[] {\n\t\tconst blockType: NodeTypeName = this.resolveBlockType(nodeType('blockquote'));\n\t\tconst children: Node[] = Array.from(element.childNodes);\n\t\tconst hasBlockChildren: boolean = children.some(\n\t\t\t(c: Node) => c.nodeType === Node.ELEMENT_NODE && this.isBlockElement(c as HTMLElement),\n\t\t);\n\n\t\tif (hasBlockChildren) {\n\t\t\tconst innerBlocks: SliceBlock[] = this.parseContainer(element as HTMLElement);\n\t\t\treturn innerBlocks.map(\n\t\t\t\t(b: SliceBlock): SliceBlock => ({\n\t\t\t\t\ttype: blockType,\n\t\t\t\t\tsegments: b.segments,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\treturn [\n\t\t\t{\n\t\t\t\ttype: blockType,\n\t\t\t\tsegments: this.ensureSegments(this.parseInlineChildren(element, [])),\n\t\t\t},\n\t\t];\n\t}\n\n\tprivate parseList(element: HTMLElement, listType: string, depth: number): SliceBlock[] {\n\t\tconst blocks: SliceBlock[] = [];\n\n\t\tfor (const child of Array.from(element.children)) {\n\t\t\tconst el: HTMLElement = child as HTMLElement;\n\t\t\tif (el.tagName === 'LI') {\n\t\t\t\tblocks.push(...this.parseListItem(el, listType, depth));\n\t\t\t} else if (el.tagName === 'UL') {\n\t\t\t\tblocks.push(...this.parseList(el, 'bullet', depth + 1));\n\t\t\t} else if (el.tagName === 'OL') {\n\t\t\t\tblocks.push(...this.parseList(el, 'ordered', depth + 1));\n\t\t\t}\n\t\t}\n\n\t\treturn blocks;\n\t}\n\n\tprivate parseListItem(element: HTMLElement, listType: string, depth: number): SliceBlock[] {\n\t\tconst blocks: SliceBlock[] = [];\n\t\tconst blockType: NodeTypeName = this.resolveBlockType(nodeType('list_item'));\n\n\t\tconst isChecklist: boolean = this.hasCheckbox(element);\n\t\tconst resolvedListType: string = isChecklist ? 'checklist' : listType;\n\t\tconst checked: boolean = isChecklist ? this.isCheckboxChecked(element) : false;\n\n\t\tconst inlineSegments: TextSegment[] = [];\n\t\tconst nestedLists: HTMLElement[] = [];\n\n\t\tfor (const child of Array.from(element.childNodes)) {\n\t\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst el: HTMLElement = child as HTMLElement;\n\t\t\t\tif (el.tagName === 'UL' || el.tagName === 'OL') {\n\t\t\t\t\tnestedLists.push(el);\n\t\t\t\t} else if (el.tagName === 'INPUT' && el.getAttribute('type') === 'checkbox') {\n\t\t\t\t\t// skip checkbox inputs — handled via block attributes\n\t\t\t\t} else if (this.isBlockElement(el)) {\n\t\t\t\t\tinlineSegments.push(...this.parseInlineChildren(el, []));\n\t\t\t\t} else {\n\t\t\t\t\tinlineSegments.push(...this.parseInlineNode(child, []));\n\t\t\t\t}\n\t\t\t} else if (child.nodeType === Node.TEXT_NODE) {\n\t\t\t\tconst text: string = child.textContent ?? '';\n\t\t\t\tif (text) {\n\t\t\t\t\tinlineSegments.push({ text, marks: [] });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tblocks.push({\n\t\t\ttype: blockType,\n\t\t\tattrs: {\n\t\t\t\tlistType: resolvedListType,\n\t\t\t\tindent: depth,\n\t\t\t\t...(resolvedListType === 'checklist' ? { checked } : {}),\n\t\t\t},\n\t\t\tsegments: this.ensureSegments(this.normalizeSegments(inlineSegments)),\n\t\t});\n\n\t\tfor (const nested of nestedLists) {\n\t\t\tconst nestedType: string = nested.tagName === 'OL' ? 'ordered' : 'bullet';\n\t\t\tblocks.push(...this.parseList(nested, nestedType, depth + 1));\n\t\t}\n\n\t\treturn blocks;\n\t}\n\n\tprivate parseInlineChildren(element: HTMLElement, parentMarks: readonly Mark[]): TextSegment[] {\n\t\tconst segments: TextSegment[] = [];\n\n\t\tfor (const child of Array.from(element.childNodes)) {\n\t\t\tsegments.push(...this.parseInlineNode(child, parentMarks));\n\t\t}\n\n\t\treturn this.normalizeSegments(segments);\n\t}\n\n\tprivate parseInlineNode(node: Node, parentMarks: readonly Mark[]): TextSegment[] {\n\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\tconst text: string = node.textContent ?? '';\n\t\t\tif (text) {\n\t\t\t\treturn [{ text, marks: this.resolveMarks(parentMarks) }];\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\n\t\tif (node.nodeType !== Node.ELEMENT_NODE) return [];\n\n\t\tconst el: HTMLElement = node as HTMLElement;\n\t\tconst tag: string = el.tagName;\n\n\t\tif (tag === 'BR') {\n\t\t\treturn [{ text: '\\n', marks: this.resolveMarks(parentMarks) }];\n\t\t}\n\n\t\tif (this.isBlockElement(el) && !INLINE_ELEMENTS.has(tag)) {\n\t\t\treturn this.parseInlineChildren(el, parentMarks);\n\t\t}\n\n\t\tconst childMarks: readonly Mark[] = this.mergeMarks(parentMarks, this.marksFromElement(el));\n\t\treturn this.parseInlineChildren(el, childMarks);\n\t}\n\n\tprivate parsePreContent(element: HTMLElement): TextSegment[] {\n\t\tconst text: string = element.textContent ?? '';\n\t\tif (!text) return [];\n\t\treturn [{ text, marks: [] }];\n\t}\n\n\tprivate parseTableAsParagraphs(element: HTMLElement): SliceBlock[] {\n\t\tconst blocks: SliceBlock[] = [];\n\t\tconst cells: NodeListOf<HTMLTableCellElement> = element.querySelectorAll('td, th');\n\n\t\tfor (const cell of Array.from(cells)) {\n\t\t\tconst segments: TextSegment[] = this.parseInlineChildren(cell, []);\n\t\t\tif (segments.length > 0 && segments.some((s: TextSegment) => s.text.length > 0)) {\n\t\t\t\tblocks.push({\n\t\t\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\t\t\tsegments: this.ensureSegments(segments),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn blocks;\n\t}\n\n\tprivate marksFromElement(element: HTMLElement): readonly Mark[] {\n\t\tconst marks: Mark[] = [];\n\t\tconst tag: string = element.tagName.toLowerCase();\n\n\t\t// Try mark parse rules first\n\t\tif (this.markParseRules.length > 0) {\n\t\t\tconst matchedTypes = new Set<string>();\n\t\t\tfor (const entry of this.markParseRules) {\n\t\t\t\tif (entry.rule.tag !== tag) continue;\n\t\t\t\tif (matchedTypes.has(entry.type)) continue;\n\n\t\t\t\tif (entry.rule.getAttrs) {\n\t\t\t\t\tconst attrs = entry.rule.getAttrs(element);\n\t\t\t\t\tif (attrs === false) continue;\n\t\t\t\t\tmarks.push({\n\t\t\t\t\t\ttype: markType(entry.type),\n\t\t\t\t\t\t...(Object.keys(attrs).length > 0 ? { attrs } : {}),\n\t\t\t\t\t} as Mark);\n\t\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t\t} else {\n\t\t\t\t\tmarks.push({ type: markType(entry.type) });\n\t\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (matchedTypes.size > 0) return marks;\n\t\t}\n\n\t\t// Fallback to hardcoded logic when no registry is provided\n\t\tconst upperTag: string = element.tagName;\n\t\tif (upperTag === 'STRONG' || upperTag === 'B') {\n\t\t\tconst fw: string = element.style.fontWeight;\n\t\t\tconst numeric: number = Number.parseInt(fw, 10);\n\t\t\tconst isExplicitlyNotBold: boolean =\n\t\t\t\tfw === 'normal' || (!Number.isNaN(numeric) && numeric < 700);\n\t\t\tif (!isExplicitlyNotBold) {\n\t\t\t\tmarks.push({ type: markType('bold') });\n\t\t\t}\n\t\t}\n\t\tif (upperTag === 'EM' || upperTag === 'I') {\n\t\t\tmarks.push({ type: markType('italic') });\n\t\t}\n\t\tif (upperTag === 'U') {\n\t\t\tmarks.push({ type: markType('underline') });\n\t\t}\n\t\tif (upperTag === 'S' || upperTag === 'STRIKE' || upperTag === 'DEL') {\n\t\t\tmarks.push({ type: markType('strikethrough') });\n\t\t}\n\t\tif (upperTag === 'A') {\n\t\t\tconst href: string = element.getAttribute('href') ?? '';\n\t\t\tmarks.push({ type: markType('link'), attrs: { href } });\n\t\t}\n\n\t\treturn marks;\n\t}\n\n\tprivate mergeMarks(existing: readonly Mark[], additional: readonly Mark[]): readonly Mark[] {\n\t\tconst result: Mark[] = [...existing];\n\t\tfor (const mark of additional) {\n\t\t\tif (!result.some((m: Mark) => m.type === mark.type)) {\n\t\t\t\tresult.push(mark);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate resolveMarks(rawMarks: readonly Mark[]): readonly Mark[] {\n\t\treturn rawMarks.filter((m: Mark) => isMarkAllowed(this.schema, m.type));\n\t}\n\n\tprivate resolveBlockType(type: NodeTypeName): NodeTypeName {\n\t\tif (isNodeTypeAllowed(this.schema, type)) return type;\n\t\treturn nodeType('paragraph');\n\t}\n\n\tprivate normalizeSegments(segments: readonly TextSegment[]): TextSegment[] {\n\t\tif (segments.length === 0) return [];\n\n\t\tconst result: TextSegment[] = [];\n\t\tfor (const segment of segments) {\n\t\t\tconst prev: TextSegment | undefined = result[result.length - 1];\n\t\t\tif (prev && markSetsEqual(prev.marks, segment.marks)) {\n\t\t\t\tresult[result.length - 1] = { text: prev.text + segment.text, marks: prev.marks };\n\t\t\t} else if (segment.text.length > 0) {\n\t\t\t\tresult.push(segment);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate ensureSegments(segments: readonly TextSegment[]): readonly TextSegment[] {\n\t\tif (segments.length === 0) return [{ text: '', marks: [] }];\n\t\treturn segments;\n\t}\n\n\tprivate matchBlockRule(el: HTMLElement): {\n\t\treadonly type: NodeTypeName;\n\t\treadonly attrs?: Record<string, string | number | boolean>;\n\t} | null {\n\t\tconst tag: string = el.tagName.toLowerCase();\n\t\tfor (const entry of this.blockParseRules) {\n\t\t\tif (entry.rule.tag !== tag) continue;\n\t\t\tif (entry.rule.getAttrs) {\n\t\t\t\tconst attrs = entry.rule.getAttrs(el);\n\t\t\t\tif (attrs === false) continue;\n\t\t\t\treturn {\n\t\t\t\t\ttype: nodeType(entry.type),\n\t\t\t\t\tattrs: attrs as Record<string, string | number | boolean>,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { type: nodeType(entry.type) };\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate isBlockElement(el: HTMLElement): boolean {\n\t\tif (BLOCK_ELEMENTS.has(el.tagName)) return true;\n\t\t// Check if any block parse rule matches this tag\n\t\tconst tag: string = el.tagName.toLowerCase();\n\t\treturn this.blockParseRules.some((entry) => entry.rule.tag === tag);\n\t}\n\n\tprivate hasCheckbox(element: HTMLElement): boolean {\n\t\tconst input: HTMLInputElement | null = element.querySelector('input[type=\"checkbox\"]');\n\t\treturn input !== null;\n\t}\n\n\tprivate isCheckboxChecked(element: HTMLElement): boolean {\n\t\tconst input: HTMLInputElement | null = element.querySelector('input[type=\"checkbox\"]');\n\t\treturn input?.hasAttribute('checked') ?? false;\n\t}\n\n\t/** Checks whether an element contains any block-level descendants. */\n\tprivate containsBlockDescendants(el: HTMLElement): boolean {\n\t\tfor (const child of Array.from(el.children)) {\n\t\t\tif (this.isBlockElement(child as HTMLElement)) return true;\n\t\t\tif (this.containsBlockDescendants(child as HTMLElement)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** Parses a container element, prepending inherited marks to all resulting blocks. */\n\tprivate parseContainerWithMarks(\n\t\tcontainer: HTMLElement,\n\t\tinheritedMarks: readonly Mark[],\n\t): SliceBlock[] {\n\t\tconst innerBlocks: SliceBlock[] = this.parseContainer(container);\n\t\tif (inheritedMarks.length === 0) return innerBlocks;\n\n\t\treturn innerBlocks.map(\n\t\t\t(block: SliceBlock): SliceBlock => ({\n\t\t\t\t...block,\n\t\t\t\tsegments: this.prependMarks(block.segments, inheritedMarks),\n\t\t\t}),\n\t\t);\n\t}\n\n\t/** Merges inherited marks into each segment's mark list. */\n\tprivate prependMarks(\n\t\tsegments: readonly TextSegment[],\n\t\tmarks: readonly Mark[],\n\t): readonly TextSegment[] {\n\t\treturn segments.map(\n\t\t\t(s: TextSegment): TextSegment => ({\n\t\t\t\ttext: s.text,\n\t\t\t\tmarks: this.mergeMarks(marks, s.marks),\n\t\t\t}),\n\t\t);\n\t}\n\n\t/**\n\t * Parses a block element, splitting into multiple blocks at `<br>` boundaries.\n\t * `<br>` may appear at any nesting depth (e.g. inside `<b>` or `<span>`),\n\t * so we parse inline content first, then split the resulting segments at\n\t * the `\\n` characters produced by `<br>`.\n\t */\n\tprivate parseBlockWithLineBreaks(element: HTMLElement, blockType: NodeTypeName): SliceBlock[] {\n\t\tconst segments: readonly TextSegment[] = this.parseInlineChildren(element, []);\n\t\tconst hasLineBreak: boolean = segments.some((s: TextSegment) => s.text.includes('\\n'));\n\n\t\tif (!hasLineBreak) {\n\t\t\treturn [{ type: blockType, segments: this.ensureSegments(segments) }];\n\t\t}\n\n\t\tconst blocks: SliceBlock[] = [];\n\t\tlet current: TextSegment[] = [];\n\n\t\tfor (const segment of segments) {\n\t\t\tconst parts: readonly string[] = segment.text.split('\\n');\n\t\t\tfor (let i = 0; i < parts.length; i++) {\n\t\t\t\tif (i > 0) {\n\t\t\t\t\tblocks.push({\n\t\t\t\t\t\ttype: blockType,\n\t\t\t\t\t\tsegments: this.ensureSegments(this.normalizeSegments(current)),\n\t\t\t\t\t});\n\t\t\t\t\tcurrent = [];\n\t\t\t\t}\n\t\t\t\tconst part: string = parts[i] ?? '';\n\t\t\t\tif (part) {\n\t\t\t\t\tcurrent.push({ text: part, marks: segment.marks });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tblocks.push({\n\t\t\ttype: blockType,\n\t\t\tsegments: this.ensureSegments(this.normalizeSegments(current)),\n\t\t});\n\n\t\treturn blocks;\n\t}\n\n\tprivate flushPendingSegments(blocks: SliceBlock[], segments: TextSegment[]): void {\n\t\tconst normalized: TextSegment[] = this.normalizeSegments(segments);\n\t\tif (normalized.length === 0) return;\n\t\tif (normalized.every((s: TextSegment) => s.text.trim() === '')) return;\n\n\t\tblocks.push({\n\t\t\ttype: this.resolveBlockType(nodeType('paragraph')),\n\t\t\tsegments: normalized,\n\t\t});\n\t}\n}\n","/**\n * Normalizes legacy HTML elements to their modern CSS equivalents.\n * Converts {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/font | <font>}\n * `color/face/size` attributes to `<span style=\"color/font-family/font-size\">`\n * so that DOMPurify + existing plugin parse rules handle them transparently.\n *\n * Must be called BEFORE DOMPurify sanitization.\n */\n\nimport { setStyleText } from '../style/StyleRuntime.js';\n\n/** Maps HTML `<font size>` values (1–7) to CSS font-size keywords per the HTML 4 spec. */\nconst FONT_SIZE_MAP: Readonly<Record<string, string>> = {\n\t'1': 'x-small',\n\t'2': 'small',\n\t'3': 'medium',\n\t'4': 'large',\n\t'5': 'x-large',\n\t'6': 'xx-large',\n\t'7': 'xxx-large',\n};\n\n/**\n * Normalizes legacy `<font>` elements in-place, converting them to `<span style=\"...\">`.\n *\n * - `color` attribute → `style.color`\n * - `face` attribute → `style.fontFamily`\n * - `size` attribute → mapped to CSS `font-size` keyword (unless inline `font-size` already set)\n * - `<font>` with no meaningful attributes → unwrapped (children promoted to parent)\n */\nexport function normalizeLegacyHTML(container: DocumentFragment | HTMLElement): void {\n\tconst fonts: HTMLElement[] = Array.from(container.querySelectorAll('font'));\n\n\tfor (const font of fonts) {\n\t\tconst color: string | null = font.getAttribute('color');\n\t\tconst face: string | null = font.getAttribute('face');\n\t\tconst size: string | null = font.getAttribute('size');\n\t\tconst existingStyle: string = font.getAttribute('style') ?? '';\n\n\t\tconst hasFormatting: boolean =\n\t\t\tcolor !== null || face !== null || size !== null || existingStyle.length > 0;\n\n\t\tif (!hasFormatting) {\n\t\t\tunwrap(font);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst span: HTMLSpanElement = document.createElement('span');\n\t\tconst styles: string[] = [];\n\n\t\tif (existingStyle) {\n\t\t\tstyles.push(existingStyle.endsWith(';') ? existingStyle : `${existingStyle};`);\n\t\t}\n\n\t\tif (color) {\n\t\t\tstyles.push(`color: ${color};`);\n\t\t}\n\n\t\tif (face) {\n\t\t\tstyles.push(`font-family: ${face};`);\n\t\t}\n\n\t\tif (size && !hasFontSizeInStyle(existingStyle)) {\n\t\t\tconst mapped: string | undefined = FONT_SIZE_MAP[size];\n\t\t\tif (mapped) {\n\t\t\t\tstyles.push(`font-size: ${mapped};`);\n\t\t\t}\n\t\t}\n\n\t\tsetStyleText(span, styles.join(' '));\n\n\t\tmoveChildren(font, span);\n\t\tfont.parentNode?.replaceChild(span, font);\n\t}\n}\n\n/** Checks whether an inline style string already contains a `font-size` declaration. */\nfunction hasFontSizeInStyle(style: string): boolean {\n\treturn style.toLowerCase().includes('font-size');\n}\n\n/** Moves all child nodes from `source` to `target`. */\nfunction moveChildren(source: Node, target: Node): void {\n\twhile (source.firstChild) {\n\t\ttarget.appendChild(source.firstChild);\n\t}\n}\n\n/** Unwraps an element, promoting its children into its parent. */\nfunction unwrap(element: HTMLElement): void {\n\tconst parent: Node | null = element.parentNode;\n\tif (!parent) return;\n\n\twhile (element.firstChild) {\n\t\tparent.insertBefore(element.firstChild, element);\n\t}\n\tparent.removeChild(element);\n}\n","/**\n * Paste handler: intercepts paste events and converts clipboard content to transactions.\n * Supports file paste via registered FileHandlers, plain text, and HTML.\n */\n\nimport DOMPurify from 'dompurify';\nimport { insertTextCommand } from '../commands/Commands.js';\nimport { pasteSlice } from '../commands/PasteCommand.js';\nimport {\n\ttype BlockAttrs,\n\ttype BlockNode,\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgetBlockText,\n\tisBlockNode,\n} from '../model/Document.js';\nimport { generateBlockId } from '../model/Document.js';\nimport { HTMLParser } from '../model/HTMLParser.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { AttrSpec } from '../model/NodeSpec.js';\nimport { schemaFromRegistry } from '../model/Schema.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport { nodeType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { FileHandlerRegistry } from './FileHandlerRegistry.js';\nimport type { DispatchFn, GetStateFn } from './InputHandler.js';\nimport { type RichBlockData, consumeRichClipboard } from './InternalClipboard.js';\nimport { normalizeLegacyHTML } from './LegacyHTMLNormalizer.js';\n\n/**\n * Validates incoming attributes against the declared AttrSpec.\n * Only keys declared in the spec are kept; non-primitive values fall back to defaults.\n */\nfunction sanitizeAttrs(\n\tincoming: Record<string, unknown> | undefined,\n\tspecAttrs: Readonly<Record<string, AttrSpec>> | undefined,\n): Record<string, string | number | boolean> | undefined {\n\tif (!specAttrs) return undefined;\n\n\tconst result: Record<string, string | number | boolean> = {};\n\tlet hasKeys = false;\n\n\tfor (const key of Object.keys(specAttrs)) {\n\t\tconst spec: AttrSpec = specAttrs[key] as AttrSpec;\n\t\tconst raw: unknown = incoming?.[key];\n\n\t\tif (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {\n\t\t\tresult[key] = raw;\n\t\t} else if (spec.default !== undefined) {\n\t\t\tresult[key] = spec.default;\n\t\t}\n\t\tif (key in result) hasKeys = true;\n\t}\n\n\treturn hasKeys ? result : undefined;\n}\n\nexport interface PasteHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tschemaRegistry?: SchemaRegistry;\n\tfileHandlerRegistry?: FileHandlerRegistry;\n\tisReadOnly?: () => boolean;\n}\n\nexport class PasteHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate readonly fileHandlerRegistry?: FileHandlerRegistry;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate readonly handlePaste: (e: ClipboardEvent) => void;\n\n\tconstructor(\n\t\tprivate readonly element: HTMLElement,\n\t\toptions: PasteHandlerOptions,\n\t) {\n\t\tthis.getState = options.getState;\n\t\tthis.dispatch = options.dispatch;\n\t\tthis.schemaRegistry = options.schemaRegistry;\n\t\tthis.fileHandlerRegistry = options.fileHandlerRegistry;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\n\t\tthis.handlePaste = this.onPaste.bind(this);\n\t\telement.addEventListener('paste', this.handlePaste);\n\t}\n\n\tprivate onPaste(e: ClipboardEvent): void {\n\t\te.preventDefault();\n\t\tif (this.isReadOnly()) return;\n\n\t\tconst clipboardData = e.clipboardData;\n\t\tif (!clipboardData) return;\n\n\t\t// Check for internal block paste (from ClipboardHandler)\n\t\tconst blockJson: string = clipboardData.getData('application/x-notectl-block');\n\t\tif (blockJson) {\n\t\t\tthis.handleBlockPaste(blockJson);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for file paste first\n\t\tif (this.handleFilePaste(clipboardData)) return;\n\n\t\t// Check in-memory rich clipboard (block structure from our own copy)\n\t\tconst plainText: string = clipboardData.getData('text/plain');\n\t\tif (plainText) {\n\t\t\tconst richBlocks: readonly RichBlockData[] | undefined = consumeRichClipboard(plainText);\n\t\t\tif (richBlocks && this.handleRichPaste(richBlocks)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst state = this.getState();\n\n\t\t// Try HTML first, fall back to plain text\n\t\tconst html = clipboardData.getData('text/html');\n\t\tif (html) {\n\t\t\t// Check for embedded rich block data (from programmatic paste)\n\t\t\tconst richJson: string | undefined = this.extractRichData(html);\n\t\t\tif (richJson && this.handleRichPasteFromJson(richJson)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Normalize legacy elements (e.g. <font>) before sanitization\n\t\t\tconst preTemplate: HTMLTemplateElement = document.createElement('template');\n\t\t\tpreTemplate.innerHTML = html;\n\t\t\tnormalizeLegacyHTML(preTemplate.content);\n\t\t\tconst normalizedHTML: string = preTemplate.innerHTML;\n\n\t\t\tconst allowedTags: string[] = this.schemaRegistry\n\t\t\t\t? this.schemaRegistry.getAllowedTags()\n\t\t\t\t: ['strong', 'em', 'u', 'b', 'i', 'p', 'br', 'div', 'span'];\n\t\t\tconst allowedAttrs: string[] = this.schemaRegistry\n\t\t\t\t? this.schemaRegistry.getAllowedAttrs()\n\t\t\t\t: [];\n\t\t\tconst sanitized = DOMPurify.sanitize(normalizedHTML, {\n\t\t\t\tALLOWED_TAGS: allowedTags,\n\t\t\t\tALLOWED_ATTR: allowedAttrs,\n\t\t\t});\n\n\t\t\tif (this.schemaRegistry) {\n\t\t\t\tconst schema = schemaFromRegistry(this.schemaRegistry);\n\t\t\t\tconst parser = new HTMLParser({ schema, schemaRegistry: this.schemaRegistry });\n\t\t\t\tconst template = document.createElement('template');\n\t\t\t\ttemplate.innerHTML = sanitized;\n\t\t\t\tconst slice = parser.parse(template.content);\n\t\t\t\tconst tr = pasteSlice(state, slice);\n\t\t\t\tthis.dispatch(tr);\n\t\t\t} else {\n\t\t\t\tconst text = this.extractTextFromHTML(sanitized);\n\t\t\t\tif (text) {\n\t\t\t\t\tconst tr = insertTextCommand(state, text, 'paste');\n\t\t\t\t\tthis.dispatch(tr);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (plainText) {\n\t\t\tconst tr = insertTextCommand(this.getState(), plainText, 'paste');\n\t\t\tthis.dispatch(tr);\n\t\t}\n\t}\n\n\t/** Handles paste of an internal block node from ClipboardHandler. */\n\tprivate handleBlockPaste(json: string): void {\n\t\tlet parsed: { type?: string; attrs?: Record<string, unknown> };\n\t\ttry {\n\t\t\tparsed = JSON.parse(json) as { type?: string; attrs?: Record<string, unknown> };\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\n\t\tconst typeName: string | undefined = parsed.type;\n\t\tif (!typeName) return;\n\n\t\t// Validate that this type is known (if we have a registry)\n\t\tconst spec = this.schemaRegistry?.getNodeSpec(typeName);\n\t\tif (this.schemaRegistry && !spec) return;\n\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\n\t\t// Find anchor block to insert after\n\t\tconst anchorBlockId: BlockId = isNodeSelection(sel)\n\t\t\t? sel.nodeId\n\t\t\t: isGapCursor(sel)\n\t\t\t\t? sel.blockId\n\t\t\t\t: sel.anchor.blockId;\n\n\t\tconst newBlockId: BlockId = generateBlockId();\n\t\tconst attrs: BlockAttrs | undefined = sanitizeAttrs(parsed.attrs, spec?.attrs) as\n\t\t\t| BlockAttrs\n\t\t\t| undefined;\n\t\tconst newBlock: BlockNode = createBlockNode(\n\t\t\tnodeType(typeName) as NodeTypeName,\n\t\t\t[],\n\t\t\tnewBlockId,\n\t\t\tattrs,\n\t\t);\n\n\t\t// Check if we're inside a table cell — insert as child of cell\n\t\tconst cellId: BlockId | undefined = this.findTableCellAncestor(state, anchorBlockId);\n\t\tif (cellId) {\n\t\t\tconst cellPath: BlockId[] | undefined = findNodePath(state.doc, cellId) as\n\t\t\t\t| BlockId[]\n\t\t\t\t| undefined;\n\t\t\tif (!cellPath) return;\n\n\t\t\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\t\t\tif (!cell) return;\n\n\t\t\tconst builder = state.transaction('paste');\n\t\t\tbuilder.insertNode(cellPath, cell.children.length, newBlock);\n\t\t\tbuilder.setSelection(createNodeSelection(newBlockId, [...cellPath, newBlockId]));\n\t\t\tthis.dispatch(builder.build());\n\t\t\treturn;\n\t\t}\n\n\t\t// Default: insert after the anchor block at the same level\n\t\tconst path = findNodePath(state.doc, anchorBlockId);\n\t\tconst parentPath: BlockId[] = path && path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\n\t\tconst siblings: readonly (BlockNode | import('../model/Document.js').ChildNode)[] =\n\t\t\tparentPath.length === 0\n\t\t\t\t? state.doc.children\n\t\t\t\t: (() => {\n\t\t\t\t\t\tconst parent = state.getBlock(parentPath[parentPath.length - 1] as BlockId);\n\t\t\t\t\t\treturn parent ? parent.children : [];\n\t\t\t\t\t})();\n\n\t\tconst index: number = siblings.findIndex((c) => isBlockNode(c) && c.id === anchorBlockId);\n\t\tif (index < 0) return;\n\n\t\tconst insertOffset: number = isGapCursor(sel) && sel.side === 'before' ? 0 : 1;\n\t\tconst builder = state.transaction('paste');\n\t\tbuilder.insertNode(parentPath, index + insertOffset, newBlock);\n\t\tbuilder.setSelection(createNodeSelection(newBlockId, [...parentPath, newBlockId]));\n\n\t\tthis.dispatch(builder.build());\n\t}\n\n\t/** Parses JSON and delegates to handleRichPaste (for HTML-embedded data). */\n\tprivate handleRichPasteFromJson(json: string): boolean {\n\t\tlet blocks: RichBlockData[];\n\t\ttry {\n\t\t\tblocks = JSON.parse(json) as RichBlockData[];\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t\tif (!Array.isArray(blocks) || blocks.length === 0) return false;\n\t\treturn this.handleRichPaste(blocks);\n\t}\n\n\t/**\n\t * Handles paste of rich block data (text selections that carry block structure).\n\t * Returns true if the paste was handled, false to fall through to plain-text paste.\n\t */\n\tprivate handleRichPaste(blocks: readonly RichBlockData[]): boolean {\n\t\tif (blocks.length === 0) return false;\n\n\t\t// Only use rich paste for structured blocks (list_item, heading, etc.)\n\t\tconst hasStructured: boolean = blocks.some(\n\t\t\t(b) => b.type !== undefined && b.type !== 'paragraph',\n\t\t);\n\t\tif (!hasStructured) return false;\n\n\t\tconst state = this.getState();\n\t\tconst sel = state.selection;\n\t\tconst anchorBlockId: BlockId = isNodeSelection(sel)\n\t\t\t? sel.nodeId\n\t\t\t: isGapCursor(sel)\n\t\t\t\t? sel.blockId\n\t\t\t\t: sel.anchor.blockId;\n\n\t\tconst cellId: BlockId | undefined = this.findTableCellAncestor(state, anchorBlockId);\n\n\t\tif (cellId) {\n\t\t\treturn this.insertRichBlocksIntoCell(blocks, state, anchorBlockId, cellId);\n\t\t}\n\t\treturn this.insertRichBlocksAtRoot(blocks, state, anchorBlockId);\n\t}\n\n\t/** Inserts rich blocks as children of a table cell. */\n\tprivate insertRichBlocksIntoCell(\n\t\tblocks: readonly RichBlockData[],\n\t\tstate: EditorState,\n\t\tanchorBlockId: BlockId,\n\t\tcellId: BlockId,\n\t): boolean {\n\t\tconst cellPath: BlockId[] | undefined = findNodePath(state.doc, cellId) as\n\t\t\t| BlockId[]\n\t\t\t| undefined;\n\t\tif (!cellPath) return false;\n\n\t\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\t\tif (!cell) return false;\n\n\t\tconst anchorBlock: BlockNode | undefined = state.getBlock(anchorBlockId);\n\t\tconst anchorIndex: number = cell.children.findIndex(\n\t\t\t(c) => isBlockNode(c) && c.id === anchorBlockId,\n\t\t);\n\t\tconst isAnchorEmpty: boolean =\n\t\t\tanchorBlock !== undefined &&\n\t\t\tanchorBlock.type === 'paragraph' &&\n\t\t\tgetBlockText(anchorBlock) === '';\n\n\t\tlet insertIndex: number = anchorIndex >= 0 ? anchorIndex + 1 : cell.children.length;\n\t\tconst builder = state.transaction('paste');\n\t\tlet lastBlockId: BlockId | undefined;\n\t\tlet lastTextLen = 0;\n\n\t\tfor (const raw of blocks) {\n\t\t\tconst blockData: RichBlockData | undefined = this.validateRichBlockData(raw);\n\t\t\tif (!blockData) continue;\n\n\t\t\tconst newId: BlockId = generateBlockId();\n\t\t\tconst text: string = blockData.text ?? '';\n\t\t\tconst children = text ? [createTextNode(text)] : undefined;\n\t\t\tconst attrs: BlockAttrs | undefined = blockData.attrs\n\t\t\t\t? (blockData.attrs as BlockAttrs)\n\t\t\t\t: undefined;\n\n\t\t\tconst newBlock: BlockNode = createBlockNode(\n\t\t\t\tnodeType(blockData.type) as NodeTypeName,\n\t\t\t\tchildren,\n\t\t\t\tnewId,\n\t\t\t\tattrs,\n\t\t\t);\n\n\t\t\tbuilder.insertNode(cellPath, insertIndex, newBlock);\n\t\t\tinsertIndex++;\n\t\t\tlastBlockId = newId;\n\t\t\tlastTextLen = text.length;\n\t\t}\n\n\t\t// Remove the empty anchor paragraph (it is still at anchorIndex in the working doc)\n\t\tif (isAnchorEmpty && anchorIndex >= 0) {\n\t\t\tbuilder.removeNode(cellPath, anchorIndex);\n\t\t}\n\n\t\tif (lastBlockId) {\n\t\t\tbuilder.setSelection(createCollapsedSelection(lastBlockId, lastTextLen));\n\t\t}\n\n\t\tthis.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\t/** Inserts rich blocks after the anchor block at the root/parent level. */\n\tprivate insertRichBlocksAtRoot(\n\t\tblocks: readonly RichBlockData[],\n\t\tstate: EditorState,\n\t\tanchorBlockId: BlockId,\n\t): boolean {\n\t\tconst path = findNodePath(state.doc, anchorBlockId);\n\t\tconst parentPath: BlockId[] = path && path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\n\t\tconst siblings: readonly (BlockNode | import('../model/Document.js').ChildNode)[] =\n\t\t\tparentPath.length === 0\n\t\t\t\t? state.doc.children\n\t\t\t\t: (() => {\n\t\t\t\t\t\tconst parent = state.getBlock(parentPath[parentPath.length - 1] as BlockId);\n\t\t\t\t\t\treturn parent ? parent.children : [];\n\t\t\t\t\t})();\n\n\t\tconst anchorIndex: number = siblings.findIndex((c) => isBlockNode(c) && c.id === anchorBlockId);\n\t\tif (anchorIndex < 0) return false;\n\n\t\tconst anchorBlock: BlockNode | undefined = state.getBlock(anchorBlockId);\n\t\tconst isAnchorEmpty: boolean =\n\t\t\tanchorBlock !== undefined &&\n\t\t\tanchorBlock.type === 'paragraph' &&\n\t\t\tgetBlockText(anchorBlock) === '';\n\n\t\tconst sel = state.selection;\n\t\tconst insertOffset: number = isGapCursor(sel) && sel.side === 'before' ? 0 : 1;\n\t\tlet insertIndex: number = anchorIndex + insertOffset;\n\t\tconst builder = state.transaction('paste');\n\t\tlet lastBlockId: BlockId | undefined;\n\t\tlet lastTextLen = 0;\n\n\t\tfor (const raw of blocks) {\n\t\t\tconst blockData: RichBlockData | undefined = this.validateRichBlockData(raw);\n\t\t\tif (!blockData) continue;\n\n\t\t\tconst newId: BlockId = generateBlockId();\n\t\t\tconst text: string = blockData.text ?? '';\n\t\t\tconst children = text ? [createTextNode(text)] : undefined;\n\t\t\tconst attrs: BlockAttrs | undefined = blockData.attrs\n\t\t\t\t? (blockData.attrs as BlockAttrs)\n\t\t\t\t: undefined;\n\n\t\t\tconst newBlock: BlockNode = createBlockNode(\n\t\t\t\tnodeType(blockData.type) as NodeTypeName,\n\t\t\t\tchildren,\n\t\t\t\tnewId,\n\t\t\t\tattrs,\n\t\t\t);\n\n\t\t\tbuilder.insertNode(parentPath, insertIndex, newBlock);\n\t\t\tinsertIndex++;\n\t\t\tlastBlockId = newId;\n\t\t\tlastTextLen = text.length;\n\t\t}\n\n\t\t// Remove the empty anchor paragraph (don't remove void blocks at gap cursor)\n\t\tif (isAnchorEmpty && !isGapCursor(sel)) {\n\t\t\tbuilder.removeNode(parentPath, anchorIndex);\n\t\t}\n\n\t\tif (lastBlockId) {\n\t\t\tbuilder.setSelection(createCollapsedSelection(lastBlockId, lastTextLen));\n\t\t}\n\n\t\tthis.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\t/** Validates a rich block against the schema registry. Returns undefined for invalid blocks. */\n\tprivate validateRichBlockData(raw: RichBlockData): RichBlockData | undefined {\n\t\tif (!raw.type) return undefined;\n\n\t\tif (!this.schemaRegistry) return raw;\n\n\t\tconst spec = this.schemaRegistry.getNodeSpec(raw.type);\n\t\tif (!spec) return undefined;\n\n\t\tconst attrs: Record<string, string | number | boolean> | undefined = sanitizeAttrs(\n\t\t\traw.attrs,\n\t\t\tspec.attrs,\n\t\t);\n\n\t\treturn { ...raw, attrs };\n\t}\n\n\t/** Finds a table_cell ancestor for the given block (or the block itself). */\n\tprivate findTableCellAncestor(state: EditorState, blockId: BlockId): BlockId | undefined {\n\t\tconst block: BlockNode | undefined = state.getBlock(blockId);\n\t\tif (block?.type === 'table_cell') return blockId;\n\n\t\tconst path: BlockId[] | undefined = findNodePath(state.doc, blockId) as BlockId[] | undefined;\n\t\tif (!path) return undefined;\n\n\t\tfor (const id of path) {\n\t\t\tconst node: BlockNode | undefined = state.getBlock(id as BlockId);\n\t\t\tif (node?.type === 'table_cell') return id as BlockId;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Checks for files in clipboard data and delegates to registered handlers. */\n\tprivate handleFilePaste(clipboardData: DataTransfer): boolean {\n\t\tif (!this.fileHandlerRegistry) return false;\n\n\t\t// Check clipboardData.files first\n\t\tconst files: File[] = Array.from(clipboardData.files);\n\n\t\t// Also check items for file entries (some browsers use items instead)\n\t\tif (files.length === 0) {\n\t\t\tfor (let i = 0; i < clipboardData.items.length; i++) {\n\t\t\t\tconst item = clipboardData.items[i];\n\t\t\t\tif (item && item.kind === 'file') {\n\t\t\t\t\tconst file = item.getAsFile();\n\t\t\t\t\tif (file) files.push(file);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (files.length === 0) return false;\n\n\t\tlet handled = false;\n\t\tfor (const file of files) {\n\t\t\tconst handlers = this.fileHandlerRegistry.matchFileHandlers(file.type);\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = handler(file, null);\n\t\t\t\tif (result === true || result instanceof Promise) {\n\t\t\t\t\thandled = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn handled;\n\t}\n\n\t/** Extracts embedded rich block JSON from HTML (data-notectl-rich attribute). */\n\tprivate extractRichData(html: string): string | undefined {\n\t\tconst template = document.createElement('template');\n\t\ttemplate.innerHTML = html;\n\t\tconst richEl: Element | null = template.content.querySelector('[data-notectl-rich]');\n\t\tif (!richEl) return undefined;\n\t\treturn richEl.getAttribute('data-notectl-rich') ?? undefined;\n\t}\n\n\tprivate extractTextFromHTML(html: string): string {\n\t\tconst template = document.createElement('template');\n\t\ttemplate.innerHTML = html;\n\t\treturn template.content.textContent ?? '';\n\t}\n\n\tdestroy(): void {\n\t\tthis.element.removeEventListener('paste', this.handlePaste);\n\t}\n}\n","/**\n * Reconciler: diffs old and new state and applies minimal DOM patches.\n * Uses block-level granularity — changed blocks are re-rendered entirely.\n * Supports plugin-registered NodeSpecs, MarkSpecs, and NodeViews via SchemaRegistry.\n */\n\nimport type { Decoration, DecorationAttrs, InlineDecoration } from '../decorations/Decoration.js';\nimport { type DecorationSet, decorationArraysEqual } from '../decorations/Decoration.js';\nimport type { NodeAttrsFor } from '../model/AttrRegistry.js';\nimport type { BlockNode, InlineNode, TextNode } from '../model/Document.js';\nimport {\n\tgetBlockChildren,\n\tgetInlineChildren,\n\tisInlineNode,\n\tisLeafBlock,\n\tisTextNode,\n\tmarkSetsEqual,\n} from '../model/Document.js';\nimport { createBlockElement } from '../model/NodeSpec.js';\nimport type { WrapperSpec } from '../model/NodeSpec.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport { blockId as toBlockId } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport { appendStyleText, setStyleText } from '../style/StyleRuntime.js';\nimport { createMarkElement, getMarkRank } from './MarkRendering.js';\nimport type { NodeView } from './NodeView.js';\nimport type { NodeViewRegistry } from './NodeViewRegistry.js';\n\nexport interface ReconcileOptions {\n\tregistry?: SchemaRegistry;\n\tnodeViewRegistry?: NodeViewRegistry;\n\tnodeViews?: Map<string, NodeView>;\n\tgetState?: () => EditorState;\n\tdispatch?: (tr: import('../state/Transaction.js').Transaction) => void;\n\tdecorations?: DecorationSet;\n\toldDecorations?: DecorationSet;\n\tselectedNodeId?: BlockId;\n\tpreviousSelectedNodeId?: BlockId;\n\t/** When set, the block with this ID is skipped during reconciliation to preserve IME composition. */\n\tcompositionBlockId?: BlockId;\n}\n\n/** Reconciles the DOM container to match the new state. */\nexport function reconcile(\n\tcontainer: HTMLElement,\n\toldState: EditorState | null,\n\tnewState: EditorState,\n\toptions?: ReconcileOptions,\n): void {\n\tconst oldBlocks = oldState?.doc.children ?? [];\n\tconst newBlocks = newState.doc.children;\n\tconst registry = options?.registry;\n\tconst nodeViews = options?.nodeViews;\n\n\t// Unwrap blocks from existing wrapper elements (e.g. <ul>/<ol>)\n\t// so the main reconciliation loop sees all blocks as direct children.\n\t// Skip during active IME composition — moving DOM nodes breaks the browser's\n\t// composition session. Wrappers are structural (based on block types) and\n\t// don't change during text composition; the next non-composing reconcile will fix them.\n\tconst isComposing = options?.compositionBlockId != null;\n\tif (!isComposing) {\n\t\tunwrapBlocks(container);\n\t}\n\n\tconst oldBlockMap = new Map<BlockId, HTMLElement>();\n\tfor (const el of getRenderedBlockElements(container)) {\n\t\tconst bid = el.getAttribute('data-block-id');\n\t\tif (bid) oldBlockMap.set(toBlockId(bid), el);\n\t}\n\n\t// Build set of new block IDs for removal detection\n\tconst newBlockIds = new Set(newBlocks.map((b) => b.id));\n\n\t// Remove blocks that no longer exist\n\tfor (const [blockId, el] of oldBlockMap) {\n\t\tif (!newBlockIds.has(blockId)) {\n\t\t\tremoveBlockElement(el);\n\t\t\toldBlockMap.delete(blockId);\n\t\t\t// Destroy NodeView if exists\n\t\t\tconst nv = nodeViews?.get(blockId);\n\t\t\tif (nv) {\n\t\t\t\tnv.destroy?.();\n\t\t\t\tnodeViews?.delete(blockId);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Mapping from old state for change detection\n\tconst oldBlockById = new Map<string, BlockNode>();\n\tfor (const block of oldBlocks) {\n\t\toldBlockById.set(block.id, block);\n\t}\n\n\t// Insert/update blocks in order\n\tlet previousSibling: Element | null = null;\n\n\tconst selectedNodeId = options?.selectedNodeId;\n\tconst previousSelectedNodeId = options?.previousSelectedNodeId;\n\n\tfor (const block of newBlocks) {\n\t\tconst existingEl = oldBlockMap.get(block.id);\n\t\tconst oldBlock = oldBlockById.get(block.id);\n\n\t\t// Skip reconciliation for the block under active IME composition\n\t\tif (options?.compositionBlockId === block.id && existingEl) {\n\t\t\tpreviousSibling = existingEl;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst oldDecos = options?.oldDecorations?.find(block.id);\n\t\tconst newDecos = options?.decorations?.find(block.id);\n\n\t\tif (existingEl && oldBlock && !blockChanged(oldBlock, block, oldDecos, newDecos)) {\n\t\t\t// Block unchanged — keep existing DOM\n\t\t\tpreviousSibling = existingEl;\n\t\t} else if (existingEl) {\n\t\t\t// Block changed — try NodeView update first\n\t\t\tconst existingNv = nodeViews?.get(block.id);\n\t\t\tif (existingNv) {\n\t\t\t\tconst handled = existingNv.update?.(block) ?? false;\n\t\t\t\tif (handled) {\n\t\t\t\t\t// Re-render inline content into contentDOM for leaf blocks\n\t\t\t\t\tif (isLeafBlock(block) && existingNv.contentDOM) {\n\t\t\t\t\t\texistingNv.contentDOM.textContent = '';\n\t\t\t\t\t\tconst updatedInlineDecos = options?.decorations?.findInline(block.id);\n\t\t\t\t\t\trenderBlockContent(existingNv.contentDOM, block, registry, updatedInlineDecos);\n\t\t\t\t\t}\n\t\t\t\t\tpreviousSibling = existingNv.dom;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Update not handled — destroy and re-create\n\t\t\t\texistingNv.destroy?.();\n\t\t\t\tnodeViews?.delete(block.id);\n\t\t\t}\n\n\t\t\tconst newEl = renderBlock(block, registry, nodeViews, options);\n\t\t\treplaceBlockElement(existingEl, newEl, container);\n\t\t\tpreviousSibling = newEl;\n\t\t} else {\n\t\t\t// New block — insert after previousSibling\n\t\t\tconst newEl = renderBlock(block, registry, nodeViews, options);\n\t\t\tinsertAfterPreviousSibling(container, previousSibling, newEl);\n\t\t\tpreviousSibling = newEl;\n\t\t}\n\n\t\t// Handle NodeSelection visual state (CSS class only — aria-selected is\n\t\t// invalid on generic block elements like <figure>, <pre>, etc.)\n\t\tif (selectedNodeId === block.id) {\n\t\t\tconst nv = nodeViews?.get(block.id);\n\t\t\tif (nv) {\n\t\t\t\tnv.selectNode?.();\n\t\t\t} else {\n\t\t\t\tconst el = oldBlockMap.get(block.id) ?? previousSibling;\n\t\t\t\tif (el instanceof HTMLElement) {\n\t\t\t\t\tel.classList.add('notectl-node-selected');\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (previousSelectedNodeId === block.id) {\n\t\t\tconst nv = nodeViews?.get(block.id);\n\t\t\tif (nv) {\n\t\t\t\tnv.deselectNode?.();\n\t\t\t} else {\n\t\t\t\tconst el = oldBlockMap.get(block.id) ?? previousSibling;\n\t\t\t\tif (el instanceof HTMLElement) {\n\t\t\t\t\tel.classList.remove('notectl-node-selected');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Handle selection for nested NodeViews (e.g. images inside table cells)\n\tif (previousSelectedNodeId && previousSelectedNodeId !== selectedNodeId) {\n\t\tconst nested = nodeViews?.get(previousSelectedNodeId);\n\t\tif (nested && !newBlockIds.has(previousSelectedNodeId)) {\n\t\t\tnested.deselectNode?.();\n\t\t}\n\t}\n\tif (selectedNodeId && !newBlockIds.has(selectedNodeId)) {\n\t\tconst nested = nodeViews?.get(selectedNodeId);\n\t\tif (nested) {\n\t\t\tnested.selectNode?.();\n\t\t}\n\t}\n\n\t// Group consecutive blocks into wrapper elements (e.g. <ul>/<ol> for list items)\n\tif (!isComposing) {\n\t\twrapBlocks(container, newBlocks, registry);\n\t}\n}\n\n/** Checks whether a block has changed by comparing its children, attrs, and decorations. */\nfunction blockChanged(\n\toldBlock: BlockNode,\n\tnewBlock: BlockNode,\n\toldDecos?: readonly Decoration[],\n\tnewDecos?: readonly Decoration[],\n): boolean {\n\tif (oldBlock.type !== newBlock.type) return true;\n\tif (oldBlock.children.length !== newBlock.children.length) return true;\n\n\t// Compare attrs\n\tconst oldAttrs = oldBlock.attrs;\n\tconst newAttrs = newBlock.attrs;\n\tif (oldAttrs !== newAttrs) {\n\t\tif (!oldAttrs || !newAttrs) return true;\n\t\tconst oldKeys = Object.keys(oldAttrs);\n\t\tconst newKeys = Object.keys(newAttrs);\n\t\tif (oldKeys.length !== newKeys.length) return true;\n\t\tfor (const key of oldKeys) {\n\t\t\tif (oldAttrs[key] !== newAttrs[key]) return true;\n\t\t}\n\t}\n\n\tfor (let i = 0; i < oldBlock.children.length; i++) {\n\t\tconst oldChild = oldBlock.children[i];\n\t\tconst newChild = newBlock.children[i];\n\t\tif (!oldChild || !newChild) return true;\n\n\t\tif (isTextNode(oldChild) && isTextNode(newChild)) {\n\t\t\tif (oldChild.text !== newChild.text) return true;\n\t\t\tif (!markSetsEqual(oldChild.marks, newChild.marks)) return true;\n\t\t} else if (isInlineNode(oldChild) && isInlineNode(newChild)) {\n\t\t\tif (oldChild.inlineType !== newChild.inlineType) return true;\n\t\t\tif (!inlineAttrsEqual(oldChild.attrs, newChild.attrs)) return true;\n\t\t} else if (\n\t\t\t!isTextNode(oldChild) &&\n\t\t\t!isTextNode(newChild) &&\n\t\t\t!isInlineNode(oldChild) &&\n\t\t\t!isInlineNode(newChild)\n\t\t) {\n\t\t\t// Both are BlockNodes — compare recursively\n\t\t\tif (blockChanged(oldChild as BlockNode, newChild as BlockNode)) return true;\n\t\t} else {\n\t\t\t// Different child types\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Compare decorations\n\tconst oldArr = oldDecos ?? [];\n\tconst newArr = newDecos ?? [];\n\tif (oldArr !== newArr && !decorationArraysEqual(oldArr, newArr)) return true;\n\n\treturn false;\n}\n\n/** Renders a block node to a DOM element, using registry specs or NodeViews. */\nexport function renderBlock(\n\tblock: BlockNode,\n\tregistry?: SchemaRegistry,\n\tnodeViews?: Map<string, NodeView>,\n\toptions?: ReconcileOptions,\n): HTMLElement {\n\tconst inlineDecos = options?.decorations?.findInline(block.id);\n\n\t// 1. Try NodeViewFactory\n\tconst nodeViewRegistry = options?.nodeViewRegistry;\n\tif (nodeViewRegistry && registry && nodeViews && options?.getState && options?.dispatch) {\n\t\tconst factory = nodeViewRegistry.getNodeViewFactory(block.type);\n\t\tif (factory) {\n\t\t\tconst nv = factory(block, options.getState, options.dispatch);\n\t\t\tnodeViews.set(block.id, nv);\n\n\t\t\t// Mark void blocks\n\t\t\tconst nvSpec = registry.getNodeSpec(block.type);\n\t\t\tif (nvSpec?.isVoid) {\n\t\t\t\tnv.dom.setAttribute('data-void', 'true');\n\t\t\t}\n\t\t\tif (nvSpec?.selectable) {\n\t\t\t\tnv.dom.setAttribute('data-selectable', 'true');\n\t\t\t}\n\n\t\t\t// Mark contentDOM so SelectionSync can find it\n\t\t\tif (nv.contentDOM && nv.contentDOM !== nv.dom) {\n\t\t\t\tnv.contentDOM.setAttribute('data-content-dom', 'true');\n\t\t\t}\n\n\t\t\t// Render children into NodeView content area\n\t\t\tif (isLeafBlock(block) && nv.contentDOM) {\n\t\t\t\t// Leaf blocks: render inline content (TextNodes) into contentDOM\n\t\t\t\trenderBlockContent(nv.contentDOM, block, registry, inlineDecos);\n\t\t\t} else {\n\t\t\t\t// Container blocks: recursively render block children\n\t\t\t\tconst blockChildren = getBlockChildren(block);\n\t\t\t\tconst contentDOMChildren = new Map<HTMLElement, BlockNode[]>();\n\t\t\t\tfor (const child of blockChildren) {\n\t\t\t\t\tconst contentDOM = nv.getContentDOM?.(child.id) ?? nv.contentDOM;\n\t\t\t\t\tif (contentDOM) {\n\t\t\t\t\t\tconst childEl = renderBlock(child, registry, nodeViews, options);\n\t\t\t\t\t\tcontentDOM.appendChild(childEl);\n\t\t\t\t\t\tlet arr = contentDOMChildren.get(contentDOM);\n\t\t\t\t\t\tif (!arr) {\n\t\t\t\t\t\t\tarr = [];\n\t\t\t\t\t\t\tcontentDOMChildren.set(contentDOM, arr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tarr.push(child);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Wrap blocks in each contentDOM (e.g., list items in table cells → <ul>/<ol>)\n\t\t\t\tfor (const [dom, children] of contentDOMChildren) {\n\t\t\t\t\twrapBlocks(dom, children, registry);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnv.dom.setAttribute('data-block-type', block.type);\n\t\t\tapplyNodeDecorations(nv.dom, block.id, options);\n\t\t\treturn nv.dom;\n\t\t}\n\t}\n\n\t// 2. Try NodeSpec\n\tif (registry) {\n\t\tconst spec = registry.getNodeSpec(block.type);\n\t\tif (spec) {\n\t\t\tconst el = spec.toDOM(\n\t\t\t\tblock as Omit<BlockNode, 'attrs'> & { readonly attrs: NodeAttrsFor<string> },\n\t\t\t);\n\t\t\tif (spec.isVoid) {\n\t\t\t\tel.setAttribute('data-void', 'true');\n\t\t\t}\n\t\t\tif (spec.selectable) {\n\t\t\t\tel.setAttribute('data-selectable', 'true');\n\t\t\t}\n\t\t\tif (!spec.isVoid) {\n\t\t\t\tif (isLeafBlock(block)) {\n\t\t\t\t\trenderBlockContent(el, block, registry, inlineDecos);\n\t\t\t\t} else {\n\t\t\t\t\t// Render block children recursively\n\t\t\t\t\tconst blockChildren = getBlockChildren(block);\n\t\t\t\t\tfor (const child of blockChildren) {\n\t\t\t\t\t\tconst childEl = renderBlock(child, registry, nodeViews, options);\n\t\t\t\t\t\tel.appendChild(childEl);\n\t\t\t\t\t}\n\t\t\t\t\t// Wrap blocks (e.g., list items → <ul>/<ol>)\n\t\t\t\t\twrapBlocks(el, blockChildren, registry);\n\t\t\t\t}\n\t\t\t}\n\t\t\tel.setAttribute('data-block-type', block.type);\n\t\t\tapplyNodeDecorations(el, block.id, options);\n\t\t\treturn el;\n\t\t}\n\t}\n\n\t// 3. Fallback — render as paragraph\n\treturn renderParagraphFallback(block, registry, inlineDecos);\n}\n\n/** Renders block content (inline children) into a container element. */\nexport function renderBlockContent(\n\tcontainer: HTMLElement,\n\tblock: BlockNode,\n\tregistry?: SchemaRegistry,\n\tinlineDecos?: readonly InlineDecoration[],\n): void {\n\t// Remove stale CursorWrapper spans that may survive into reconciliation\n\tfor (const el of container.querySelectorAll('[data-cursor-wrapper]')) {\n\t\tel.remove();\n\t}\n\n\tconst inlineChildren = getInlineChildren(block);\n\n\t// Empty block: single empty text node → render <br> placeholder\n\tif (\n\t\tinlineChildren.length === 1 &&\n\t\tisTextNode(inlineChildren[0]) &&\n\t\tinlineChildren[0].text === ''\n\t) {\n\t\tcontainer.appendChild(document.createElement('br'));\n\t\treturn;\n\t}\n\n\t// Fast path: no inline decorations\n\tif (!inlineDecos || inlineDecos.length === 0) {\n\t\tfor (const child of inlineChildren) {\n\t\t\tif (isTextNode(child)) {\n\t\t\t\tcontainer.appendChild(renderTextNode(child, registry));\n\t\t\t} else {\n\t\t\t\tcontainer.appendChild(renderInlineNode(child, registry));\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Decorated path: split content into micro-segments\n\t\trenderDecoratedContent(container, inlineChildren, inlineDecos, registry);\n\t}\n\n\t// Trailing <br> hack: when the last child is a hard_break InlineNode,\n\t// browsers won't render an empty line after a trailing <br>.\n\t// Append an extra plain <br> (without contenteditable=\"false\") so the\n\t// cursor can be placed on the new line. SelectionSync skips non-\n\t// contenteditable, non-text elements, so offset counting stays correct.\n\tconst lastChild = inlineChildren[inlineChildren.length - 1];\n\tif (lastChild && isInlineNode(lastChild) && lastChild.inlineType === 'hard_break') {\n\t\tcontainer.appendChild(document.createElement('br'));\n\t}\n}\n\n/** Fallback paragraph rendering when no NodeSpec is found. */\nfunction renderParagraphFallback(\n\tblock: BlockNode,\n\tregistry?: SchemaRegistry,\n\tinlineDecos?: readonly InlineDecoration[],\n): HTMLElement {\n\tconst p = createBlockElement('p', block.id);\n\tp.setAttribute('data-block-type', block.type);\n\trenderBlockContent(p, block, registry, inlineDecos);\n\treturn p;\n}\n\n/**\n * Converts spaces for contenteditable rendering.\n * Trailing spaces and double spaces are replaced with \\u00a0 (non-breaking space)\n * to prevent the browser from collapsing them.\n */\nfunction preserveSpaces(text: string): string {\n\t// Replace consecutive spaces: alternate regular and non-breaking\n\tlet result = text.replace(/ {2}/g, ' \\u00a0');\n\t// If the text ends with a space, replace it with nbsp\n\tif (result.endsWith(' ')) {\n\t\tresult = `${result.slice(0, -1)}\\u00a0`;\n\t}\n\t// If the text starts with a space, replace it with nbsp\n\tif (result.startsWith(' ')) {\n\t\tresult = `\\u00a0${result.slice(1)}`;\n\t}\n\treturn result;\n}\n\n/** Renders a text node with marks as nested inline elements. */\nfunction renderTextNode(node: TextNode, registry?: SchemaRegistry): Node {\n\tif (node.text === '') {\n\t\treturn document.createTextNode('');\n\t}\n\n\tconst textNode = document.createTextNode(preserveSpaces(node.text));\n\n\tif (node.marks.length === 0) {\n\t\treturn textNode;\n\t}\n\n\t// Sort marks: use MarkSpec.rank if available, otherwise fallback order\n\tconst sortedMarks = [...node.marks].sort(\n\t\t(a, b) => getMarkRank(a, registry) - getMarkRank(b, registry),\n\t);\n\n\tlet current: Node = textNode;\n\n\t// Wrap from inside out (last mark is outermost)\n\tfor (let i = sortedMarks.length - 1; i >= 0; i--) {\n\t\tconst mark = sortedMarks[i];\n\t\tif (!mark) continue;\n\t\tconst el = createMarkElement(mark, registry);\n\t\tel.appendChild(current);\n\t\tcurrent = el;\n\t}\n\n\treturn current;\n}\n\n/** Renders an InlineNode, using InlineNodeSpec.toDOM() or a fallback element. */\nfunction renderInlineNode(node: InlineNode, registry?: SchemaRegistry): HTMLElement {\n\tif (registry) {\n\t\tconst spec = registry.getInlineNodeSpec(node.inlineType);\n\t\tif (spec) {\n\t\t\tconst el = spec.toDOM(node);\n\t\t\tel.setAttribute('contenteditable', 'false');\n\t\t\treturn el;\n\t\t}\n\t}\n\t// Fallback: generic non-editable span\n\tconst el = document.createElement('span');\n\tel.setAttribute('data-inline-type', node.inlineType);\n\tel.setAttribute('contenteditable', 'false');\n\treturn el;\n}\n\n/** Compares two InlineNode attr records for equality. */\nfunction inlineAttrsEqual(\n\ta: Readonly<Record<string, string | number | boolean>>,\n\tb: Readonly<Record<string, string | number | boolean>>,\n): boolean {\n\tconst aKeys = Object.keys(a);\n\tconst bKeys = Object.keys(b);\n\tif (aKeys.length !== bKeys.length) return false;\n\tfor (const key of aKeys) {\n\t\tif (a[key] !== b[key]) return false;\n\t}\n\treturn true;\n}\n\n// --- Decoration Rendering ---\n\n/**\n * Renders inline content with decorations. InlineNodes are width-1 split points\n * rendered as their own elements (not wrapped by decorations).\n *\n * For each child:\n * - TextNode: split by decoration boundaries, render text → marks → decorations\n * - InlineNode: render directly without decoration wrapping\n */\nfunction renderDecoratedContent(\n\tcontainer: HTMLElement,\n\tinlineChildren: readonly (TextNode | InlineNode)[],\n\tinlineDecos: readonly InlineDecoration[],\n\tregistry?: SchemaRegistry,\n): void {\n\tlet globalOffset = 0;\n\n\tfor (const child of inlineChildren) {\n\t\tif (isInlineNode(child)) {\n\t\t\t// InlineNodes are rendered directly, not wrapped by decorations\n\t\t\tcontainer.appendChild(renderInlineNode(child, registry));\n\t\t\tglobalOffset += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// TextNode: split by decoration boundaries within this node's range\n\t\tconst textFrom = globalOffset;\n\t\tconst textTo = globalOffset + child.text.length;\n\n\t\tif (child.text.length === 0) {\n\t\t\tglobalOffset = textTo;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Find split points within this text range\n\t\tconst splitSet = new Set<number>();\n\t\tsplitSet.add(textFrom);\n\t\tsplitSet.add(textTo);\n\t\tfor (const deco of inlineDecos) {\n\t\t\tconst dFrom = Math.max(textFrom, deco.from);\n\t\t\tconst dTo = Math.min(textTo, deco.to);\n\t\t\tif (dFrom > textFrom && dFrom < textTo) splitSet.add(dFrom);\n\t\t\tif (dTo > textFrom && dTo < textTo) splitSet.add(dTo);\n\t\t}\n\t\tconst splits = [...splitSet].sort((a, b) => a - b);\n\n\t\t// Render micro-segments\n\t\tfor (let i = 0; i < splits.length - 1; i++) {\n\t\t\tconst from = splits[i];\n\t\t\tconst to = splits[i + 1];\n\t\t\tif (from === undefined || to === undefined || from >= to) continue;\n\n\t\t\tconst localFrom = from - textFrom;\n\t\t\tconst localTo = to - textFrom;\n\t\t\tconst text = child.text.slice(localFrom, localTo);\n\n\t\t\t// Find decorations that fully cover this micro-segment\n\t\t\tconst activeDecos: InlineDecoration[] = [];\n\t\t\tfor (const deco of inlineDecos) {\n\t\t\t\tif (deco.from <= from && deco.to >= to) {\n\t\t\t\t\tactiveDecos.push(deco);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Render: text → marks (inner) → decorations (outer)\n\t\t\tconst textNode = document.createTextNode(preserveSpaces(text));\n\t\t\tlet current: Node = textNode;\n\n\t\t\t// Wrap with marks (innermost to outermost)\n\t\t\tif (child.marks.length > 0) {\n\t\t\t\tconst sortedMarks = [...child.marks].sort(\n\t\t\t\t\t(a, b) => getMarkRank(a, registry) - getMarkRank(b, registry),\n\t\t\t\t);\n\t\t\t\tfor (let j = sortedMarks.length - 1; j >= 0; j--) {\n\t\t\t\t\tconst mark = sortedMarks[j];\n\t\t\t\t\tif (!mark) continue;\n\t\t\t\t\tconst el = createMarkElement(mark, registry);\n\t\t\t\t\tel.appendChild(current);\n\t\t\t\t\tcurrent = el;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Wrap with decorations (outermost)\n\t\t\tfor (const deco of activeDecos) {\n\t\t\t\tconst el = createDecorationElement(deco.attrs);\n\t\t\t\tel.appendChild(current);\n\t\t\t\tcurrent = el;\n\t\t\t}\n\n\t\t\tcontainer.appendChild(current);\n\t\t}\n\n\t\tglobalOffset = textTo;\n\t}\n}\n\n/** Creates a DOM element for an inline decoration. */\nfunction createDecorationElement(attrs: DecorationAttrs): HTMLElement {\n\tconst tagName = attrs.nodeName ?? 'span';\n\tconst el = document.createElement(tagName);\n\tel.setAttribute('data-decoration', 'true');\n\n\tif (attrs.class) {\n\t\tfor (const cls of attrs.class.split(' ')) {\n\t\t\tif (cls) el.classList.add(cls);\n\t\t}\n\t}\n\tif (attrs.style) {\n\t\tsetStyleText(el, attrs.style);\n\t}\n\n\t// Apply any other custom attributes\n\tfor (const [key, value] of Object.entries(attrs)) {\n\t\tif (key === 'class' || key === 'style' || key === 'nodeName') continue;\n\t\tif (value !== undefined) {\n\t\t\tel.setAttribute(key, value);\n\t\t}\n\t}\n\n\treturn el;\n}\n\n/** Applies node decorations (CSS classes/styles) to a block element. */\nfunction applyNodeDecorations(el: HTMLElement, bid: BlockId, options?: ReconcileOptions): void {\n\tconst nodeDecos = options?.decorations?.findNode(bid);\n\tif (!nodeDecos || nodeDecos.length === 0) return;\n\n\tfor (const deco of nodeDecos) {\n\t\tif (deco.attrs.class) {\n\t\t\tfor (const cls of deco.attrs.class.split(' ')) {\n\t\t\t\tif (cls) el.classList.add(cls);\n\t\t\t}\n\t\t}\n\t\tif (deco.attrs.style) {\n\t\t\tappendStyleText(el, deco.attrs.style);\n\t\t}\n\t}\n}\n\n// --- Block Wrapper Management ---\n\n/**\n * Moves block elements out of wrapper elements (e.g. `<ul>`, `<ol>`) so the\n * main reconciliation loop sees all blocks as direct children of the container.\n */\nfunction unwrapBlocks(container: HTMLElement): void {\n\tconst wrappers: Element[] = Array.from(\n\t\tcontainer.querySelectorAll(':scope > [data-block-wrapper]'),\n\t);\n\tfor (const wrapper of wrappers) {\n\t\twhile (wrapper.firstChild) {\n\t\t\tcontainer.insertBefore(wrapper.firstChild, wrapper);\n\t\t}\n\t\twrapper.remove();\n\t}\n}\n\n/**\n * Groups consecutive blocks that declare the same wrapper key into shared\n * wrapper elements (`<ul>`, `<ol>`, etc.). Called after the main reconcile loop.\n */\nfunction wrapBlocks(\n\tcontainer: HTMLElement,\n\tblocks: readonly BlockNode[],\n\tregistry?: SchemaRegistry,\n): void {\n\tif (!registry) return;\n\n\t// Compute wrapper groups from the block model\n\tinterface WrapperGroup {\n\t\treadonly spec: WrapperSpec;\n\t\treadonly blockIds: readonly BlockId[];\n\t}\n\n\tconst groups: WrapperGroup[] = [];\n\tlet currentSpec: WrapperSpec | null = null;\n\tlet currentIds: BlockId[] = [];\n\n\tfor (const block of blocks) {\n\t\tconst nodeSpec = registry.getNodeSpec(block.type);\n\t\tconst wSpec: WrapperSpec | undefined = nodeSpec?.wrapper?.(block as never);\n\n\t\tif (wSpec && currentSpec && wSpec.key === currentSpec.key) {\n\t\t\tcurrentIds.push(block.id);\n\t\t} else if (wSpec) {\n\t\t\tif (currentSpec && currentIds.length > 0) {\n\t\t\t\tgroups.push({ spec: currentSpec, blockIds: currentIds });\n\t\t\t}\n\t\t\tcurrentSpec = wSpec;\n\t\t\tcurrentIds = [block.id];\n\t\t} else {\n\t\t\tif (currentSpec && currentIds.length > 0) {\n\t\t\t\tgroups.push({ spec: currentSpec, blockIds: currentIds });\n\t\t\t}\n\t\t\tcurrentSpec = null;\n\t\t\tcurrentIds = [];\n\t\t}\n\t}\n\tif (currentSpec && currentIds.length > 0) {\n\t\tgroups.push({ spec: currentSpec, blockIds: currentIds });\n\t}\n\n\t// Apply wrapper elements to the DOM\n\tfor (const group of groups) {\n\t\tconst firstEl: HTMLElement | null = container.querySelector(\n\t\t\t`[data-block-id=\"${group.blockIds[0]}\"]`,\n\t\t);\n\t\tif (!firstEl) continue;\n\n\t\tconst wrapper: HTMLElement = document.createElement(group.spec.tag);\n\t\twrapper.setAttribute('data-block-wrapper', group.spec.key);\n\t\tif (group.spec.className) {\n\t\t\twrapper.className = group.spec.className;\n\t\t}\n\t\tif (group.spec.attrs) {\n\t\t\tfor (const [key, value] of Object.entries(group.spec.attrs)) {\n\t\t\t\twrapper.setAttribute(key, value);\n\t\t\t}\n\t\t}\n\n\t\tfirstEl.before(wrapper);\n\t\tfor (const bid of group.blockIds) {\n\t\t\tconst el: HTMLElement | null = container.querySelector(`[data-block-id=\"${bid}\"]`);\n\t\t\tif (el) {\n\t\t\t\twrapper.appendChild(el);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Returns rendered top-level block elements in visual order.\n * Includes direct children and immediate children of block wrappers.\n */\nfunction getRenderedBlockElements(container: HTMLElement): readonly HTMLElement[] {\n\tconst blocks: HTMLElement[] = [];\n\tfor (const child of Array.from(container.children)) {\n\t\tif (!(child instanceof HTMLElement)) continue;\n\t\tif (child.hasAttribute('data-block-id')) {\n\t\t\tblocks.push(child);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!child.hasAttribute('data-block-wrapper')) continue;\n\n\t\tfor (const wrappedChild of Array.from(child.children)) {\n\t\t\tif (!(wrappedChild instanceof HTMLElement)) continue;\n\t\t\tif (wrappedChild.hasAttribute('data-block-id')) {\n\t\t\t\tblocks.push(wrappedChild);\n\t\t\t}\n\t\t}\n\t}\n\treturn blocks;\n}\n\n/** Removes a rendered block from whichever parent currently owns it. */\nfunction removeBlockElement(el: HTMLElement): void {\n\tel.parentElement?.removeChild(el);\n}\n\n/** Replaces a rendered block in-place, honoring wrapper parents when present. */\nfunction replaceBlockElement(oldEl: HTMLElement, newEl: HTMLElement, container: HTMLElement): void {\n\tconst parent = oldEl.parentElement;\n\tif (parent) {\n\t\tparent.replaceChild(newEl, oldEl);\n\t\treturn;\n\t}\n\tcontainer.replaceChild(newEl, oldEl);\n}\n\n/**\n * Inserts a new rendered block after the given sibling.\n * If the sibling is inside a wrapper, insertion happens inside that wrapper.\n */\nfunction insertAfterPreviousSibling(\n\tcontainer: HTMLElement,\n\tpreviousSibling: Element | null,\n\tnewEl: HTMLElement,\n): void {\n\tif (previousSibling?.parentElement) {\n\t\tconst parent = previousSibling.parentElement;\n\t\tif (previousSibling.nextSibling) {\n\t\t\tparent.insertBefore(newEl, previousSibling.nextSibling);\n\t\t} else {\n\t\t\tparent.appendChild(newEl);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (container.firstChild) {\n\t\tcontainer.insertBefore(newEl, container.firstChild);\n\t} else {\n\t\tcontainer.appendChild(newEl);\n\t}\n}\n","/**\n * EditorView: orchestrates input handling, reconciliation, and selection sync.\n */\n\nimport { DecorationSet } from '../decorations/Decoration.js';\nimport { ClipboardHandler } from '../input/ClipboardHandler.js';\nimport { CompositionTracker } from '../input/CompositionTracker.js';\nimport type { FileHandlerRegistry } from '../input/FileHandlerRegistry.js';\nimport { InputHandler } from '../input/InputHandler.js';\nimport type { InputRuleRegistry } from '../input/InputRuleRegistry.js';\nimport { KeyboardHandler } from '../input/KeyboardHandler.js';\nimport type { KeymapRegistry } from '../input/KeymapRegistry.js';\nimport { PasteHandler } from '../input/PasteHandler.js';\nimport { generateBlockId, getBlockLength } from '../model/Document.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { Position } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n\tselectionsEqual,\n} from '../model/Selection.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport { nodeType, blockId as toBlockId } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport { HistoryManager } from '../state/History.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport {\n\ttype CaretDirection,\n\tendOfTextblock,\n\tgetCaretRectFromSelection,\n\tnavigateAcrossBlocks,\n\tnavigateVerticalWithGoalColumn,\n\tskipInlineNode,\n} from './CaretNavigation.js';\nimport { CursorWrapper } from './CursorWrapper.js';\nimport { domPositionFromPoint } from './DomPointUtils.js';\nimport type { NodeView } from './NodeView.js';\nimport type { NodeViewRegistry } from './NodeViewRegistry.js';\nimport { getTextDirection } from './Platform.js';\nimport { type ReconcileOptions, reconcile } from './Reconciler.js';\nimport { domPositionToState, readSelectionFromDOM, syncSelectionToDOM } from './SelectionSync.js';\n\nexport type StateChangeCallback = (\n\toldState: EditorState,\n\tnewState: EditorState,\n\ttr: Transaction,\n) => void;\n\nexport interface EditorViewOptions {\n\tstate: EditorState;\n\tschemaRegistry?: SchemaRegistry;\n\tkeymapRegistry?: KeymapRegistry;\n\tinputRuleRegistry?: InputRuleRegistry;\n\tfileHandlerRegistry?: FileHandlerRegistry;\n\tnodeViewRegistry?: NodeViewRegistry;\n\tmaxHistoryDepth?: number;\n\tonStateChange?: StateChangeCallback;\n\tgetDecorations?: (state: EditorState, tr?: Transaction) => DecorationSet;\n\tisReadOnly?: () => boolean;\n}\n\nexport class EditorView {\n\tprivate state: EditorState;\n\tprivate readonly contentElement: HTMLElement;\n\tprivate readonly inputHandler: InputHandler;\n\tprivate readonly keyboardHandler: KeyboardHandler;\n\tprivate readonly pasteHandler: PasteHandler;\n\tprivate readonly clipboardHandler: ClipboardHandler;\n\treadonly history: HistoryManager;\n\tprivate readonly stateChangeCallbacks: StateChangeCallback[] = [];\n\tprivate readonly handleSelectionChange: () => void;\n\tprivate readonly handleMousedown: (e: MouseEvent) => void;\n\tprivate readonly handleDragover: (e: DragEvent) => void;\n\tprivate readonly handleDrop: (e: DragEvent) => void;\n\tprivate readonly handleCompositionStartForWrapper: () => void;\n\tprivate readonly handleCompositionEndForWrapper: () => void;\n\tprivate isUpdating = false;\n\tprivate pendingNodeSelectionClear = false;\n\tprivate pendingGapCursorClear = false;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate readonly keymapRegistry?: KeymapRegistry;\n\tprivate readonly fileHandlerRegistry?: FileHandlerRegistry;\n\tprivate readonly nodeViewRegistry?: NodeViewRegistry;\n\tprivate readonly nodeViews = new Map<string, NodeView>();\n\tprivate decorations: DecorationSet = DecorationSet.empty;\n\tprivate readonly getDecorations?: (state: EditorState, tr?: Transaction) => DecorationSet;\n\tprivate readonly isReadOnly: () => boolean;\n\tprivate navigationKeymap: Record<string, () => boolean> | null = null;\n\treadonly compositionTracker: CompositionTracker = new CompositionTracker();\n\tprivate readonly cursorWrapper: CursorWrapper;\n\tprivate goalColumn: number | null = null;\n\tprivate preserveGoalColumn = false;\n\n\tconstructor(contentElement: HTMLElement, options: EditorViewOptions) {\n\t\tthis.state = options.state;\n\t\tthis.contentElement = contentElement;\n\t\tthis.schemaRegistry = options.schemaRegistry;\n\t\tthis.keymapRegistry = options.keymapRegistry;\n\t\tthis.fileHandlerRegistry = options.fileHandlerRegistry;\n\t\tthis.nodeViewRegistry = options.nodeViewRegistry;\n\t\tthis.getDecorations = options.getDecorations;\n\t\tthis.isReadOnly = options.isReadOnly ?? (() => false);\n\n\t\tthis.history = new HistoryManager({\n\t\t\tmaxDepth: options.maxHistoryDepth ?? 100,\n\t\t});\n\n\t\tif (options.onStateChange) {\n\t\t\tthis.stateChangeCallbacks.push(options.onStateChange);\n\t\t}\n\n\t\tthis.inputHandler = new InputHandler(contentElement, {\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tsyncSelection: () => this.syncSelectionFromDOM(),\n\t\t\tinputRuleRegistry: options.inputRuleRegistry,\n\t\t\tisReadOnly: this.isReadOnly,\n\t\t\tcompositionTracker: this.compositionTracker,\n\t\t});\n\t\tthis.keyboardHandler = new KeyboardHandler(contentElement, {\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tundo: () => this.undo(),\n\t\t\tredo: () => this.redo(),\n\t\t\tkeymapRegistry: this.keymapRegistry,\n\t\t\tisReadOnly: this.isReadOnly,\n\t\t\tcompositionTracker: this.compositionTracker,\n\t\t});\n\t\tthis.pasteHandler = new PasteHandler(contentElement, {\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tschemaRegistry: this.schemaRegistry,\n\t\t\tfileHandlerRegistry: this.fileHandlerRegistry,\n\t\t\tisReadOnly: this.isReadOnly,\n\t\t});\n\t\tthis.clipboardHandler = new ClipboardHandler(contentElement, {\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tschemaRegistry: this.schemaRegistry,\n\t\t\tsyncSelection: () => this.syncSelectionFromDOM(),\n\t\t\tisReadOnly: this.isReadOnly,\n\t\t});\n\n\t\tthis.cursorWrapper = new CursorWrapper(contentElement, this.schemaRegistry);\n\n\t\tthis.handleCompositionStartForWrapper = () => {\n\t\t\tthis.cursorWrapper.onCompositionStart(this.state);\n\t\t};\n\t\tthis.handleCompositionEndForWrapper = () => {\n\t\t\tthis.cursorWrapper.cleanup();\n\t\t};\n\t\tcontentElement.addEventListener('compositionstart', this.handleCompositionStartForWrapper);\n\t\tcontentElement.addEventListener('compositionend', this.handleCompositionEndForWrapper);\n\n\t\tthis.handleSelectionChange = this.onSelectionChange.bind(this);\n\t\tdocument.addEventListener('selectionchange', this.handleSelectionChange);\n\n\t\tthis.handleMousedown = this.onMousedown.bind(this);\n\t\tcontentElement.addEventListener('mousedown', this.handleMousedown);\n\n\t\tthis.handleDragover = this.onDragover.bind(this);\n\t\tcontentElement.addEventListener('dragover', this.handleDragover);\n\n\t\tthis.handleDrop = this.onDrop.bind(this);\n\t\tcontentElement.addEventListener('drop', this.handleDrop);\n\n\t\t// Initial render\n\t\tthis.decorations = this.getDecorations?.(this.state) ?? DecorationSet.empty;\n\t\treconcile(contentElement, null, this.state, {\n\t\t\t...this.reconcileOptions(),\n\t\t\tdecorations: this.decorations,\n\t\t});\n\t\tsyncSelectionToDOM(contentElement, this.state.selection);\n\n\t\tthis.registerNavigationKeymaps();\n\t}\n\n\t/** Returns the current editor state. */\n\tgetState(): EditorState {\n\t\treturn this.state;\n\t}\n\n\t/**\n\t * Central update cycle: sets state, collects decorations, reconciles DOM,\n\t * syncs selection, and notifies listeners. Guarded against re-entrancy.\n\t */\n\tprivate applyUpdate(\n\t\tnewState: EditorState,\n\t\ttr: Transaction,\n\t\toptions?: { readonly pushHistory?: boolean },\n\t): void {\n\t\tif (this.isUpdating) return;\n\t\tthis.isUpdating = true;\n\t\ttry {\n\t\t\tconst oldState = this.state;\n\t\t\tthis.state = newState;\n\n\t\t\t// Clean up stale CursorWrapper when storedMarks are cleared by a dispatch\n\t\t\tif (this.cursorWrapper.isActive && !newState.storedMarks?.length) {\n\t\t\t\tthis.cursorWrapper.cleanup();\n\t\t\t}\n\n\t\t\tif (options?.pushHistory && tr.metadata.origin !== 'history') {\n\t\t\t\tthis.history.push(tr);\n\t\t\t}\n\n\t\t\tconst oldDecorations = this.decorations;\n\t\t\tconst newDecorations = this.getDecorations?.(newState, tr) ?? DecorationSet.empty;\n\t\t\tthis.decorations = newDecorations;\n\n\t\t\treconcile(this.contentElement, oldState, newState, {\n\t\t\t\t...this.reconcileOptions(oldState.selection),\n\t\t\t\tdecorations: newDecorations,\n\t\t\t\toldDecorations,\n\t\t\t\tcompositionBlockId: this.compositionTracker.isComposing\n\t\t\t\t\t? (this.compositionTracker.activeBlockId ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t});\n\t\t\tif (!this.compositionTracker.isComposing) {\n\t\t\t\tsyncSelectionToDOM(this.contentElement, newState.selection);\n\t\t\t}\n\n\t\t\tfor (const cb of this.stateChangeCallbacks) {\n\t\t\t\tcb(oldState, newState, tr);\n\t\t\t}\n\t\t\t// Reset goalColumn unless a vertical navigation is in progress\n\t\t\tif (!this.preserveGoalColumn) {\n\t\t\t\tthis.goalColumn = null;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.isUpdating = false;\n\t\t}\n\t}\n\n\t/** Dispatches a transaction, updates state, reconciles DOM, syncs selection. */\n\tdispatch(tr: Transaction): void {\n\t\tconst newState = this.state.apply(tr);\n\t\tthis.applyUpdate(newState, tr, { pushHistory: true });\n\t}\n\n\t/** Performs undo. */\n\tundo(): void {\n\t\tif (this.isUpdating || this.isReadOnly()) return;\n\t\tconst result = this.history.undo(this.state);\n\t\tif (!result) return;\n\t\tthis.applyUpdate(result.state, result.transaction);\n\t}\n\n\t/** Performs redo. */\n\tredo(): void {\n\t\tif (this.isUpdating || this.isReadOnly()) return;\n\t\tconst result = this.history.redo(this.state);\n\t\tif (!result) return;\n\t\tthis.applyUpdate(result.state, result.transaction);\n\t}\n\n\t/** Registers a state change callback. */\n\tonStateChange(callback: StateChangeCallback): () => void {\n\t\tthis.stateChangeCallbacks.push(callback);\n\t\treturn () => {\n\t\t\tconst idx = this.stateChangeCallbacks.indexOf(callback);\n\t\t\tif (idx !== -1) this.stateChangeCallbacks.splice(idx, 1);\n\t\t};\n\t}\n\n\t/** Replaces the editor state without destroying handlers or history. */\n\treplaceState(newState: EditorState): void {\n\t\tif (this.isUpdating) return;\n\t\tthis.isUpdating = true;\n\t\ttry {\n\t\t\tconst oldState = this.state;\n\t\t\tthis.state = newState;\n\t\t\tthis.history.clear();\n\n\t\t\tconst oldDecorations = this.decorations;\n\t\t\tconst newDecorations = this.getDecorations?.(newState) ?? DecorationSet.empty;\n\t\t\tthis.decorations = newDecorations;\n\n\t\t\treconcile(this.contentElement, oldState, newState, {\n\t\t\t\t...this.reconcileOptions(oldState.selection),\n\t\t\t\tdecorations: newDecorations,\n\t\t\t\toldDecorations,\n\t\t\t\tcompositionBlockId: this.compositionTracker.isComposing\n\t\t\t\t\t? (this.compositionTracker.activeBlockId ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t});\n\t\t\tif (!this.compositionTracker.isComposing) {\n\t\t\t\tsyncSelectionToDOM(this.contentElement, newState.selection);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.isUpdating = false;\n\t\t}\n\t}\n\n\t/** Syncs the DOM selection to the editor state. */\n\tprivate syncSelectionFromDOM(): void {\n\t\t// During IME composition, do not override the DOM selection\n\t\tif (this.compositionTracker.isComposing) return;\n\n\t\t// Selection change outside composition means CursorWrapper is stale\n\t\tif (this.cursorWrapper.isActive) {\n\t\t\tthis.cursorWrapper.cleanup();\n\t\t}\n\n\t\t// If NodeSelection or GapCursor is active, preserve it — DOM selectionchange should not override.\n\t\t// Exception: after mousedown on a non-selectable block, allow the DOM selection to take over.\n\t\tif (isNodeSelection(this.state.selection) && !this.pendingNodeSelectionClear) return;\n\t\tif (isGapCursor(this.state.selection) && !this.pendingGapCursorClear) return;\n\t\tthis.pendingNodeSelectionClear = false;\n\t\tthis.pendingGapCursorClear = false;\n\n\t\tconst sel = readSelectionFromDOM(this.contentElement);\n\t\tif (!sel) return;\n\n\t\t// Check if selection actually changed\n\t\tif (selectionsEqual(sel, this.state.selection)) return;\n\n\t\t// Update state with new selection (clear stored marks on selection change)\n\t\tconst tr = this.state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(sel)\n\t\t\t.setStoredMarks(null, this.state.storedMarks)\n\t\t\t.build();\n\n\t\tconst newState = this.state.apply(tr);\n\t\tthis.applyUpdate(newState, tr);\n\t}\n\n\t/** Handles mousedown on selectable/void blocks to create NodeSelection. */\n\tprivate onMousedown(e: MouseEvent): void {\n\t\tif (this.isUpdating) return;\n\t\tthis.goalColumn = null;\n\t\tconst target = e.target;\n\t\tif (!(target instanceof HTMLElement)) return;\n\n\t\tconst nearestBlockEl = target.closest('[data-block-id]');\n\n\t\t// Click in empty space below all blocks → create a paragraph\n\t\tif (!(nearestBlockEl instanceof HTMLElement) || !this.contentElement.contains(nearestBlockEl)) {\n\t\t\tif (this.contentElement.contains(target) || target === this.contentElement) {\n\t\t\t\tthis.handleClickBelowContent(e);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst isNodeSelectable =\n\t\t\tnearestBlockEl.hasAttribute('data-void') || nearestBlockEl.hasAttribute('data-selectable');\n\t\tif (!isNodeSelectable) {\n\t\t\t// When clicking a non-selectable block while NodeSelection or GapCursor is active,\n\t\t\t// allow the next syncSelectionFromDOM to override the selection\n\t\t\tif (isNodeSelection(this.state.selection)) {\n\t\t\t\tthis.pendingNodeSelectionClear = true;\n\t\t\t}\n\t\t\tif (isGapCursor(this.state.selection)) {\n\t\t\t\tthis.pendingGapCursorClear = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// If clicking inside contentDOM (e.g. code block content area),\n\t\t// allow browser cursor placement instead of creating NodeSelection.\n\t\tconst contentDOM: Element | null = nearestBlockEl.querySelector('[data-content-dom]');\n\t\tif (contentDOM?.contains(target)) {\n\t\t\tif (isNodeSelection(this.state.selection)) {\n\t\t\t\tthis.pendingNodeSelectionClear = true;\n\t\t\t}\n\t\t\tif (isGapCursor(this.state.selection)) {\n\t\t\t\tthis.pendingGapCursorClear = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\t\tthis.contentElement.focus();\n\n\t\tconst bid = toBlockId(nearestBlockEl.getAttribute('data-block-id') ?? '');\n\t\tconst path = this.buildBlockPath(nearestBlockEl);\n\t\tconst sel = createNodeSelection(bid, path);\n\n\t\tconst tr = this.state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(sel)\n\t\t\t.setStoredMarks(null, this.state.storedMarks)\n\t\t\t.build();\n\n\t\tconst newState = this.state.apply(tr);\n\t\tthis.applyUpdate(newState, tr);\n\t}\n\n\t/**\n\t * When the user clicks in empty space below all rendered blocks,\n\t * appends a new paragraph after the last block and focuses it.\n\t */\n\tprivate handleClickBelowContent(e: MouseEvent): void {\n\t\tif (this.isReadOnly()) return;\n\t\tconst blockOrder: readonly BlockId[] = this.state.getBlockOrder();\n\t\tconst lastBlockId: BlockId | undefined = blockOrder[blockOrder.length - 1];\n\t\tif (!lastBlockId) return;\n\t\tconst lastBlockEl: Element | null = this.contentElement.querySelector(\n\t\t\t`[data-block-id=\"${lastBlockId}\"]`,\n\t\t);\n\t\tif (!lastBlockEl) return;\n\n\t\t// Only act if click is below the last block\n\t\tconst lastRect: DOMRect = lastBlockEl.getBoundingClientRect();\n\t\tif (e.clientY <= lastRect.bottom) return;\n\n\t\t// Check if the last block is already an empty paragraph we can focus\n\t\tconst lastBlock = this.state.getBlock(lastBlockId);\n\t\tif (lastBlock?.type === 'paragraph' && getBlockLength(lastBlock) === 0) {\n\t\t\t// Focus the existing empty paragraph\n\t\t\tconst tr: Transaction = this.state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setSelection(createCollapsedSelection(lastBlockId, 0))\n\t\t\t\t.build();\n\t\t\tthis.dispatch(tr);\n\t\t\te.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\t// Create a new paragraph after the last block\n\t\te.preventDefault();\n\t\tthis.contentElement.focus();\n\n\t\tconst newId: BlockId = generateBlockId();\n\t\tconst lastLen: number = lastBlock ? getBlockLength(lastBlock) : 0;\n\n\t\tconst tr: Transaction = this.state\n\t\t\t.transaction('input')\n\t\t\t.splitBlock(lastBlockId, lastLen, newId)\n\t\t\t.setBlockType(newId, nodeType('paragraph'))\n\t\t\t.setSelection(createCollapsedSelection(newId, 0))\n\t\t\t.build();\n\n\t\tthis.dispatch(tr);\n\t}\n\n\t/** Builds an array of block IDs from root to leaf. */\n\tprivate buildBlockPath(leafBlockEl: HTMLElement): BlockId[] {\n\t\tconst path: BlockId[] = [];\n\t\tlet current: HTMLElement | null = leafBlockEl;\n\t\twhile (current && current !== this.contentElement) {\n\t\t\tif (current.hasAttribute('data-block-id')) {\n\t\t\t\tpath.unshift(toBlockId(current.getAttribute('data-block-id') ?? ''));\n\t\t\t}\n\t\t\tcurrent = current.parentElement;\n\t\t}\n\t\treturn path;\n\t}\n\n\t/** Allows file drop by preventing default on dragover when files are present. */\n\tprivate onDragover(e: DragEvent): void {\n\t\tif (!this.fileHandlerRegistry) return;\n\t\tif (!e.dataTransfer) return;\n\t\tif (e.dataTransfer.types.includes('Files')) {\n\t\t\te.preventDefault();\n\t\t}\n\t}\n\n\t/** Handles file drop by delegating to registered file handlers. */\n\tprivate onDrop(e: DragEvent): void {\n\t\tif (this.isReadOnly()) return;\n\t\tif (!this.fileHandlerRegistry) return;\n\t\tif (!e.dataTransfer) return;\n\n\t\tconst files: File[] = Array.from(e.dataTransfer.files);\n\t\tif (files.length === 0) return;\n\n\t\tconst position: Position | null = this.getPositionFromPoint(e.clientX, e.clientY);\n\n\t\tlet handled = false;\n\t\tfor (const file of files) {\n\t\t\tconst handlers = this.fileHandlerRegistry.matchFileHandlers(file.type);\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = handler(file, position);\n\t\t\t\tif (result === true || result instanceof Promise) {\n\t\t\t\t\thandled = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (handled) {\n\t\t\te.preventDefault();\n\t\t}\n\t}\n\n\t/** Converts screen coordinates to an editor Position. */\n\tprivate getPositionFromPoint(x: number, y: number): Position | null {\n\t\tconst root = this.contentElement.getRootNode() as Document | ShadowRoot;\n\t\tconst domPoint = domPositionFromPoint(root, x, y);\n\t\tif (!domPoint) return null;\n\t\tif (!this.contentElement.contains(domPoint.node)) return null;\n\n\t\treturn domPositionToState(this.contentElement, domPoint.node, domPoint.offset);\n\t}\n\n\t/** Handles DOM selection changes (clicks, arrow keys). */\n\tprivate onSelectionChange(): void {\n\t\tif (this.isUpdating) return;\n\n\t\t// Only process if our content element is focused\n\t\tconst shadowRoot = this.contentElement.getRootNode() as ShadowRoot | Document;\n\t\tconst activeEl =\n\t\t\t'activeElement' in shadowRoot ? shadowRoot.activeElement : document.activeElement;\n\t\tif (!this.contentElement.contains(activeEl) && activeEl !== this.contentElement) return;\n\n\t\tthis.syncSelectionFromDOM();\n\t}\n\n\tprivate reconcileOptions(\n\t\toldSelection?: import('../model/Selection.js').EditorSelection,\n\t): ReconcileOptions {\n\t\tconst selectedNodeId = isNodeSelection(this.state.selection)\n\t\t\t? this.state.selection.nodeId\n\t\t\t: undefined;\n\t\tconst previousSelectedNodeId =\n\t\t\toldSelection && isNodeSelection(oldSelection) ? oldSelection.nodeId : undefined;\n\t\treturn {\n\t\t\tregistry: this.schemaRegistry,\n\t\t\tnodeViewRegistry: this.nodeViewRegistry,\n\t\t\tnodeViews: this.nodeViews,\n\t\t\tgetState: () => this.state,\n\t\t\tdispatch: (tr: Transaction) => this.dispatch(tr),\n\t\t\tselectedNodeId,\n\t\t\tpreviousSelectedNodeId,\n\t\t};\n\t}\n\n\t/** Registers arrow-key keymaps with navigation priority for cross-block movement. */\n\tprivate registerNavigationKeymaps(): void {\n\t\tif (!this.keymapRegistry) return;\n\n\t\tconst directions: Record<string, CaretDirection> = {\n\t\t\tArrowLeft: 'left',\n\t\t\tArrowRight: 'right',\n\t\t\tArrowUp: 'up',\n\t\t\tArrowDown: 'down',\n\t\t};\n\n\t\tconst keymap: Record<string, () => boolean> = {};\n\t\tfor (const [key, dir] of Object.entries(directions)) {\n\t\t\tkeymap[key] = () => this.handleNavigationArrow(dir);\n\t\t}\n\n\t\tthis.navigationKeymap = keymap;\n\t\tthis.keymapRegistry.registerKeymap(keymap, { priority: 'navigation' });\n\t}\n\n\t/** Handles a navigation arrow key: cross-block movement if at textblock boundary. */\n\tprivate handleNavigationArrow(direction: CaretDirection): boolean {\n\t\t// NodeSelection arrows are handled by handleNodeSelectionKeys\n\t\tif (isNodeSelection(this.state.selection)) return false;\n\t\t// GapCursor arrows are handled by GapCursorPlugin keymap\n\t\tif (isGapCursor(this.state.selection)) return false;\n\n\t\t// Non-collapsed: plain arrows collapse the selection (browser handles this)\n\t\tif (!isCollapsed(this.state.selection)) return false;\n\n\t\tif (direction === 'left' || direction === 'right') {\n\t\t\treturn this.handleHorizontalArrow(direction);\n\t\t}\n\t\treturn this.handleVerticalArrow(direction);\n\t}\n\n\t/** Handles horizontal arrow navigation: InlineNode skip + cross-block. */\n\tprivate handleHorizontalArrow(direction: 'left' | 'right'): boolean {\n\t\t// Reset goalColumn on any horizontal movement\n\t\tthis.goalColumn = null;\n\t\tconst logicalDirection: 'left' | 'right' = this.resolveLogicalHorizontalDirection(direction);\n\n\t\t// Skip over InlineNodes atomically\n\t\tconst inlineSkipTr: Transaction | null = skipInlineNode(this.state, logicalDirection);\n\t\tif (inlineSkipTr) {\n\t\t\tthis.dispatch(inlineSkipTr);\n\t\t\tthis.validateSelectionAfterInlineSkip();\n\t\t\treturn true;\n\t\t}\n\n\t\t// Cross-block at textblock boundaries\n\t\tif (!endOfTextblock(this.contentElement, this.state, direction)) return false;\n\n\t\tconst tr: Transaction | null = navigateAcrossBlocks(this.state, logicalDirection);\n\t\tif (tr) {\n\t\t\tthis.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Maps visual horizontal arrow intent (left/right key) to logical movement\n\t * direction in offset space for the current block direction.\n\t */\n\tprivate resolveLogicalHorizontalDirection(visual: 'left' | 'right'): 'left' | 'right' {\n\t\tconst sel = this.state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return visual;\n\t\tconst blockEl = this.contentElement.querySelector(`[data-block-id=\"${sel.anchor.blockId}\"]`);\n\t\tconst isRtl: boolean = blockEl instanceof HTMLElement && getTextDirection(blockEl) === 'rtl';\n\t\tif (!isRtl) return visual;\n\t\treturn visual === 'left' ? 'right' : 'left';\n\t}\n\n\t/** Handles vertical arrow navigation with goalColumn preservation. */\n\tprivate handleVerticalArrow(direction: 'up' | 'down'): boolean {\n\t\t// Read caret rect once — used for both boundary check and goalColumn\n\t\tconst domSel: globalThis.Selection | null =\n\t\t\tthis.contentElement.ownerDocument.getSelection?.() ?? null;\n\t\tconst caretRect: DOMRect | null = domSel ? getCaretRectFromSelection(domSel) : null;\n\n\t\tif (!endOfTextblock(this.contentElement, this.state, direction, caretRect)) return false;\n\n\t\t// Capture goalColumn from current caret position (only on first vertical move)\n\t\tif (this.goalColumn === null && caretRect) {\n\t\t\tthis.goalColumn = caretRect.left;\n\t\t}\n\n\t\tthis.preserveGoalColumn = true;\n\t\tconst tr: Transaction | null = navigateVerticalWithGoalColumn(\n\t\t\tthis.contentElement,\n\t\t\tthis.state,\n\t\t\tdirection,\n\t\t\tthis.goalColumn,\n\t\t);\n\n\t\tif (tr) {\n\t\t\tthis.dispatch(tr);\n\t\t\tthis.preserveGoalColumn = false;\n\t\t\treturn true;\n\t\t}\n\t\tthis.preserveGoalColumn = false;\n\t\treturn false;\n\t}\n\n\t/**\n\t * Validates the DOM cursor position after an InlineNode skip.\n\t *\n\t * Chrome can place the cursor inside a `contenteditable=\"false\"` element\n\t * (phantom position), and Firefox may lose the cursor entirely next to such\n\t * elements. This read-back roundtrip detects drift between the model\n\t * selection and the actual DOM selection. If they diverge, we force\n\t * `syncSelectionToDOM()` a second time to correct the position.\n\t */\n\tprivate validateSelectionAfterInlineSkip(): void {\n\t\tconst domSel = readSelectionFromDOM(this.contentElement);\n\t\tif (!domSel) {\n\t\t\t// DOM selection lost (Firefox) — force re-sync\n\t\t\tsyncSelectionToDOM(this.contentElement, this.state.selection);\n\t\t\treturn;\n\t\t}\n\t\tif (!selectionsEqual(domSel, this.state.selection)) {\n\t\t\t// DOM position drifted (Chrome phantom) — force re-sync\n\t\t\tsyncSelectionToDOM(this.contentElement, this.state.selection);\n\t\t}\n\t}\n\n\t/** Cleans up all event listeners and handlers. */\n\tdestroy(): void {\n\t\tthis.cursorWrapper.cleanup();\n\t\tthis.inputHandler.destroy();\n\t\tthis.keyboardHandler.destroy();\n\t\tthis.pasteHandler.destroy();\n\t\tthis.clipboardHandler.destroy();\n\t\tthis.contentElement.removeEventListener(\n\t\t\t'compositionstart',\n\t\t\tthis.handleCompositionStartForWrapper,\n\t\t);\n\t\tthis.contentElement.removeEventListener('compositionend', this.handleCompositionEndForWrapper);\n\t\tdocument.removeEventListener('selectionchange', this.handleSelectionChange);\n\t\tthis.contentElement.removeEventListener('mousedown', this.handleMousedown);\n\t\tthis.contentElement.removeEventListener('dragover', this.handleDragover);\n\t\tthis.contentElement.removeEventListener('drop', this.handleDrop);\n\t\t// Remove navigation keymaps from registry\n\t\tif (this.navigationKeymap && this.keymapRegistry) {\n\t\t\tthis.keymapRegistry.removeKeymap(this.navigationKeymap);\n\t\t\tthis.navigationKeymap = null;\n\t\t}\n\t\t// Destroy all NodeViews\n\t\tfor (const nv of this.nodeViews.values()) {\n\t\t\tnv.destroy?.();\n\t\t}\n\t\tthis.nodeViews.clear();\n\t}\n}\n","/** Core editor styles — :host, .notectl-editor, .notectl-content, generic utilities. */\nexport const BASE_CSS = `\n:host {\n\tdisplay: block;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n\tfont-size: 16px;\n\tline-height: 1.6;\n\tcolor: var(--notectl-fg);\n}\n\n.notectl-editor {\n\tdisplay: flex;\n\tflex-direction: column;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\toverflow: hidden;\n\tbackground: var(--notectl-bg);\n}\n\n.notectl-editor:focus-within {\n\tborder-color: var(--notectl-border-focus);\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n}\n\n/* Content Area */\n.notectl-content {\n\tflex: 1;\n\tpadding: 12px 16px;\n\toutline: none;\n\tmin-height: var(--notectl-content-min-height, 400px);\n\tcursor: text;\n\tposition: relative;\n\twhite-space: pre-wrap;\n\tword-wrap: break-word;\n\t-moz-tab-size: 4;\n\ttab-size: 4;\n}\n\n.notectl-content p {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tmin-height: 1.6em;\n}\n\n.notectl-content p + p {\n\tmargin-top: 0;\n}\n\n/* Horizontal Rule */\n.notectl-content hr {\n\tborder: none;\n\tborder-top: 1px solid var(--notectl-border);\n\tmargin: 8px 0;\n\tpadding: 0;\n\tcursor: default;\n\tuser-select: none;\n}\n\n/* Placeholder */\n.notectl-content.notectl-content--empty::before {\n\tcontent: attr(data-placeholder);\n\tcolor: var(--notectl-fg-muted);\n\tpointer-events: none;\n\tposition: absolute;\n\ttop: 12px;\n\tleft: 16px;\n}\n\n/* Plugin container bottom */\n.notectl-plugin-container--bottom {\n\tborder-top: 1px solid var(--notectl-border);\n}\n\n/* Screen reader announcements */\n.notectl-sr-only {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\tmargin: -1px;\n\tpadding: 0;\n\toverflow: hidden;\n\tclip: rect(0, 0, 0, 0);\n\twhite-space: nowrap;\n\tborder: 0;\n}\n\n/* Node selection */\n.notectl-node-selected {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n}\n`;\n","/**\n * Editor styles using Adopted Stylesheets for Shadow DOM.\n *\n * All colors reference CSS custom properties set by the ThemeEngine.\n * The theme stylesheet is always injected first, providing all --notectl-* values.\n *\n * Only core styles (base + reduced-motion) live here.\n * Plugin-specific CSS is registered via `PluginContext.registerStyleSheet()`.\n */\n\nimport { BASE_CSS } from './styles/base.js';\nimport { PAPER_CSS } from './styles/paper.js';\nimport { REDUCED_MOTION_CSS } from './styles/reduced-motion.js';\n\n/**\n * Combined CSS for the core editor shell.\n * Plugin styles are added separately via the plugin system.\n */\nconst EDITOR_CSS: string = [BASE_CSS, REDUCED_MOTION_CSS, PAPER_CSS].join('\\n');\n\nlet cachedStyleSheet: CSSStyleSheet | null = null;\n\n/** Returns the shared editor stylesheet. */\nexport function getEditorStyleSheet(): CSSStyleSheet {\n\tif (!cachedStyleSheet) {\n\t\tcachedStyleSheet = new CSSStyleSheet();\n\t\tcachedStyleSheet.replaceSync(EDITOR_CSS);\n\t}\n\treturn cachedStyleSheet;\n}\n","/** Reduced motion preference (WCAG 2.3.3). */\nexport const REDUCED_MOTION_CSS = `\n@media (prefers-reduced-motion: reduce) {\n\t.notectl-toolbar-btn,\n\t.notectl-image__resize-handle,\n\t.notectl-image__size-indicator,\n\t.notectl-color-picker__swatch,\n\t.notectl-font-picker__item,\n\t.notectl-heading-picker__item,\n\t.notectl-font-size-picker__item,\n\t.ntbl-handle,\n\t.ntbl-handle-delete,\n\t.ntbl-insert-line,\n\t.ntbl-insert-btn,\n\t.ntbl-add-zone,\n\t.ntbl-add-icon,\n\t.ntbl-col-bar,\n\t.ntbl-row-bar,\n\t.ntbl-delete-table-btn,\n\t.notectl-code-block__copy {\n\t\ttransition: none !important;\n\t}\n}\n`;\n","/** Paper mode styles — viewport, surface, content overrides, and scale transitions. */\n\nimport {\n\tPAPER_MARGIN_HORIZONTAL_PX,\n\tPAPER_MARGIN_TOP_PX,\n\tPAPER_VIEWPORT_PADDING_PX,\n} from '../PaperSize.js';\n\nconst PT: number = PAPER_MARGIN_TOP_PX;\nconst PH: number = PAPER_MARGIN_HORIZONTAL_PX;\nconst VP: number = PAPER_VIEWPORT_PADDING_PX;\n\nexport const PAPER_CSS: string = `\n/* Paper viewport: scroll container with centered gray background */\n.notectl-paper-viewport {\n\tflex: 1;\n\toverflow-y: auto;\n\toverflow-x: hidden;\n\tbackground: var(--notectl-paper-viewport-bg, #e8e8e8);\n\tpadding: ${VP}px 0;\n}\n\n/* Paper surface: white page with shadow, centered */\n.notectl-paper-surface {\n\tmargin: 0 auto;\n\tbackground: var(--notectl-bg);\n\tborder-radius: 2px;\n\tbox-shadow: 0 2px 8px var(--notectl-shadow, rgba(0, 0, 0, 0.15));\n\ttransform-origin: top center;\n\ttransition: transform 0.15s ease-out;\n}\n\n/* Content overrides in paper mode: wider document margins */\n.notectl-editor[data-paper-mode] .notectl-content {\n\tflex: none;\n\tpadding: ${PT}px ${PH}px;\n\tmin-height: auto;\n}\n\n/* Placeholder position override for paper mode */\n.notectl-editor[data-paper-mode] .notectl-content.notectl-content--empty::before {\n\ttop: ${PT}px;\n\tleft: ${PH}px;\n}\n\n/* Dark mode: darker viewport background */\n:host([theme=\"dark\"]) .notectl-paper-viewport {\n\t--notectl-paper-viewport-bg: #181825;\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.notectl-paper-surface {\n\t\ttransition: none !important;\n\t}\n}\n`;\n","/**\n * EditorThemeController — manages theme lifecycle for a Shadow DOM host.\n * Owns the theme CSSStyleSheet, system-theme media listener, and cleanup.\n */\n\nimport { getEditorStyleSheet } from './styles.js';\nimport { generateThemeCSS } from './theme/ThemeEngine.js';\nimport { type Theme, ThemePreset, resolveTheme } from './theme/ThemeTokens.js';\n\nexport class EditorThemeController {\n\tprivate themeStyleSheet: CSSStyleSheet = new CSSStyleSheet();\n\tprivate systemThemeQuery: MediaQueryList | null = null;\n\tprivate systemThemeHandler: ((e: MediaQueryListEvent) => void) | null = null;\n\tprivate pluginSheets: readonly CSSStyleSheet[] = [];\n\tprivate runtimeSheets: readonly CSSStyleSheet[] = [];\n\tprivate readonly shadow: ShadowRoot;\n\n\tconstructor(shadow: ShadowRoot) {\n\t\tthis.shadow = shadow;\n\t}\n\n\t/** Applies a theme preset or custom Theme to the shadow root. */\n\tapply(theme: ThemePreset | Theme): void {\n\t\tthis.cleanupSystemThemeListener();\n\n\t\tif (theme === ThemePreset.System) {\n\t\t\tthis.setupSystemThemeListener();\n\t\t\tconst resolved: Theme = resolveTheme(this.getSystemTheme());\n\t\t\tthis.setThemeStyleSheet(resolved);\n\t\t} else {\n\t\t\tthis.setThemeStyleSheet(resolveTheme(theme));\n\t\t}\n\t}\n\n\t/** Updates the plugin-registered stylesheets and refreshes adoptedStyleSheets. */\n\tsetPluginStyleSheets(sheets: readonly CSSStyleSheet[]): void {\n\t\tthis.pluginSheets = sheets;\n\t\tthis.refreshAdoptedStyleSheets();\n\t}\n\n\t/** Updates runtime-generated stylesheets (e.g. strict CSP dynamic rules). */\n\tsetRuntimeStyleSheets(sheets: readonly CSSStyleSheet[]): void {\n\t\tthis.runtimeSheets = sheets;\n\t\tthis.refreshAdoptedStyleSheets();\n\t}\n\n\t/** Removes the system-theme listener. */\n\tdestroy(): void {\n\t\tthis.cleanupSystemThemeListener();\n\t}\n\n\tprivate setThemeStyleSheet(theme: Theme): void {\n\t\tthis.themeStyleSheet.replaceSync(generateThemeCSS(theme));\n\t\tthis.refreshAdoptedStyleSheets();\n\t}\n\n\tprivate refreshAdoptedStyleSheets(): void {\n\t\tthis.shadow.adoptedStyleSheets = [\n\t\t\tthis.themeStyleSheet,\n\t\t\tgetEditorStyleSheet(),\n\t\t\t...this.pluginSheets,\n\t\t\t...this.runtimeSheets,\n\t\t];\n\t}\n\n\tprivate setupSystemThemeListener(): void {\n\t\tthis.systemThemeQuery = window.matchMedia('(prefers-color-scheme: dark)');\n\t\tthis.systemThemeHandler = (_e: MediaQueryListEvent): void => {\n\t\t\tconst resolved: Theme = resolveTheme(this.getSystemTheme());\n\t\t\tthis.setThemeStyleSheet(resolved);\n\t\t};\n\t\tthis.systemThemeQuery.addEventListener('change', this.systemThemeHandler);\n\t}\n\n\tprivate cleanupSystemThemeListener(): void {\n\t\tif (this.systemThemeQuery && this.systemThemeHandler) {\n\t\t\tthis.systemThemeQuery.removeEventListener('change', this.systemThemeHandler);\n\t\t}\n\t\tthis.systemThemeQuery = null;\n\t\tthis.systemThemeHandler = null;\n\t}\n\n\tprivate getSystemTheme(): ThemePreset {\n\t\tconst prefersDark: boolean = window.matchMedia('(prefers-color-scheme: dark)').matches;\n\t\treturn prefersDark ? ThemePreset.Dark : ThemePreset.Light;\n\t}\n}\n","/**\n * Manages the paper-mode DOM transformation and scale-to-fit behavior.\n *\n * In paper mode, the content element is reparented into a viewport/surface\n * structure that constrains it to the exact paper width. A ResizeObserver\n * drives CSS `transform: scale()` when the container is narrower than\n * the paper, producing a Google Docs-like shrink-to-fit effect.\n */\n\nimport { setStyleProperty } from '../style/StyleRuntime.js';\nimport { PAPER_VIEWPORT_PADDING_PX, type PaperSize, getPaperDimensions } from './PaperSize.js';\n\nexport class PaperLayoutController {\n\tprivate readonly wrapper: HTMLElement;\n\tprivate readonly content: HTMLElement;\n\n\tprivate viewport: HTMLElement | null = null;\n\tprivate surface: HTMLElement | null = null;\n\n\tprivate viewportObserver: ResizeObserver | null = null;\n\tprivate surfaceObserver: ResizeObserver | null = null;\n\n\tprivate currentSize: PaperSize | null = null;\n\tprivate currentPaperWidthPx = 0;\n\tprivate currentPaperHeightPx = 0;\n\tprivate currentScale = 1;\n\tprivate compensationFrameId: number | null = null;\n\n\tconstructor(wrapper: HTMLElement, content: HTMLElement) {\n\t\tthis.wrapper = wrapper;\n\t\tthis.content = content;\n\t}\n\n\t/** Enables, changes, or disables paper mode. Pass `null` to disable. */\n\tapply(paperSize: PaperSize | null): void {\n\t\tif (paperSize === null) {\n\t\t\tthis.disable();\n\t\t\treturn;\n\t\t}\n\n\t\tconst dims = getPaperDimensions(paperSize);\n\t\tthis.currentPaperWidthPx = dims.widthPx;\n\t\tthis.currentPaperHeightPx = dims.heightPx;\n\t\tthis.currentSize = paperSize;\n\n\t\tif (!this.viewport) {\n\t\t\tthis.enable();\n\t\t}\n\n\t\tthis.updateSurfaceDimensions();\n\t\tthis.wrapper.setAttribute('data-paper-mode', paperSize);\n\t}\n\n\t/** Cleans up observers and restores original DOM. */\n\tdestroy(): void {\n\t\tthis.disable();\n\t}\n\n\t/** Returns the currently applied paper size, or null if disabled. */\n\tgetPaperSize(): PaperSize | null {\n\t\treturn this.currentSize;\n\t}\n\n\t// --- Private ---\n\n\tprivate enable(): void {\n\t\t// Create viewport (scroll container)\n\t\tthis.viewport = document.createElement('div');\n\t\tthis.viewport.className = 'notectl-paper-viewport';\n\n\t\t// Create surface (page representation)\n\t\tthis.surface = document.createElement('div');\n\t\tthis.surface.className = 'notectl-paper-surface';\n\n\t\t// Reparent content: remove from wrapper, place inside surface\n\t\tthis.wrapper.removeChild(this.content);\n\t\tthis.surface.appendChild(this.content);\n\t\tthis.viewport.appendChild(this.surface);\n\n\t\t// Insert viewport after top plugin container (index 1 in wrapper children)\n\t\tconst bottomContainer: Element | null = this.wrapper.querySelector(\n\t\t\t'.notectl-plugin-container--bottom',\n\t\t);\n\t\tif (bottomContainer) {\n\t\t\tthis.wrapper.insertBefore(this.viewport, bottomContainer);\n\t\t} else {\n\t\t\tthis.wrapper.appendChild(this.viewport);\n\t\t}\n\n\t\t// Observe viewport width for scale-to-fit\n\t\tthis.viewportObserver = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tthis.onViewportResize(entry.contentRect.width);\n\t\t\t}\n\t\t});\n\t\tthis.viewportObserver.observe(this.viewport);\n\n\t\t// Observe surface height to compensate for layout shift from transform\n\t\tthis.surfaceObserver = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tthis.onSurfaceResize(entry.contentRect.height);\n\t\t\t}\n\t\t});\n\t\tthis.surfaceObserver.observe(this.surface);\n\t}\n\n\tprivate disable(): void {\n\t\tif (this.compensationFrameId !== null) {\n\t\t\tcancelAnimationFrame(this.compensationFrameId);\n\t\t\tthis.compensationFrameId = null;\n\t\t}\n\t\tthis.viewportObserver?.disconnect();\n\t\tthis.viewportObserver = null;\n\t\tthis.surfaceObserver?.disconnect();\n\t\tthis.surfaceObserver = null;\n\n\t\tif (this.viewport && this.surface) {\n\t\t\t// Reparent content back to wrapper\n\t\t\tthis.surface.removeChild(this.content);\n\n\t\t\tconst bottomContainer: Element | null = this.wrapper.querySelector(\n\t\t\t\t'.notectl-plugin-container--bottom',\n\t\t\t);\n\t\t\tif (bottomContainer) {\n\t\t\t\tthis.wrapper.insertBefore(this.content, bottomContainer);\n\t\t\t} else {\n\t\t\t\tthis.wrapper.appendChild(this.content);\n\t\t\t}\n\n\t\t\t// Remove viewport from wrapper\n\t\t\tthis.wrapper.removeChild(this.viewport);\n\t\t}\n\n\t\tthis.viewport = null;\n\t\tthis.surface = null;\n\t\tthis.currentSize = null;\n\t\tthis.currentPaperWidthPx = 0;\n\t\tthis.currentPaperHeightPx = 0;\n\t\tthis.currentScale = 1;\n\t\tthis.wrapper.removeAttribute('data-paper-mode');\n\t}\n\n\tprivate updateSurfaceDimensions(): void {\n\t\tif (!this.surface) return;\n\t\tsetStyleProperty(this.surface, 'width', `${this.currentPaperWidthPx}px`);\n\t\tsetStyleProperty(this.surface, 'minHeight', `${this.currentPaperHeightPx}px`);\n\t}\n\n\tprivate onViewportResize(viewportWidth: number): void {\n\t\tif (!this.surface || this.currentPaperWidthPx === 0) return;\n\n\t\tconst availableWidth: number = viewportWidth - 2 * PAPER_VIEWPORT_PADDING_PX;\n\t\tconst scale: number = Math.min(1, availableWidth / this.currentPaperWidthPx);\n\t\tthis.currentScale = scale;\n\n\t\tsetStyleProperty(this.surface, 'transform', scale < 1 ? `scale(${scale})` : '');\n\n\t\t// Compensate margin-bottom so parent layout sees correct visual height\n\t\tthis.scheduleHeightCompensation(scale);\n\t}\n\n\tprivate onSurfaceResize(_height: number): void {\n\t\tif (!this.surface || !this.viewport) return;\n\t\tthis.scheduleHeightCompensation(this.currentScale);\n\t}\n\n\tprivate scheduleHeightCompensation(scale: number): void {\n\t\tif (this.compensationFrameId !== null) {\n\t\t\tcancelAnimationFrame(this.compensationFrameId);\n\t\t}\n\t\tthis.compensationFrameId = requestAnimationFrame(() => {\n\t\t\tthis.compensationFrameId = null;\n\t\t\tthis.updateHeightCompensation(scale);\n\t\t});\n\t}\n\n\tprivate updateHeightCompensation(scale: number): void {\n\t\tif (!this.surface) return;\n\n\t\tif (scale >= 1) {\n\t\t\tsetStyleProperty(this.surface, 'marginBottom', '');\n\t\t\treturn;\n\t\t}\n\n\t\t// transform doesn't affect layout size, so the parent sees unscaled height.\n\t\t// Negative margin-bottom compensates: surfaceHeight * (1 - scale).\n\t\tconst surfaceHeight: number = this.surface.scrollHeight;\n\t\tconst visualHeight: number = surfaceHeight * scale;\n\t\tconst compensation: number = visualHeight - surfaceHeight;\n\t\tsetStyleProperty(this.surface, 'marginBottom', `${compensation}px`);\n\t}\n}\n","/**\n * NotectlEditor Web Component — the public-facing editor element.\n */\n\nimport { selectAll } from '../commands/Commands.js';\nimport { DecorationSet } from '../decorations/Decoration.js';\nimport type { Locale } from '../i18n/Locale.js';\nimport { LocaleService, LocaleServiceKey } from '../i18n/LocaleService.js';\nimport { registerBuiltinSpecs } from '../model/BuiltinSpecs.js';\nimport { type Document, getBlockText } from '../model/Document.js';\nimport { formatHTML } from '../model/HTMLUtils.js';\nimport { isMarkAllowed, schemaFromRegistry } from '../model/Schema.js';\nimport { createCollapsedSelection, selectionsEqual } from '../model/Selection.js';\nimport { blockId } from '../model/TypeBrands.js';\nimport type {\n\tEventKey,\n\tPlugin,\n\tPluginConfig,\n\tPluginEventCallback,\n\tServiceKey,\n} from '../plugins/Plugin.js';\nimport { PluginManager } from '../plugins/PluginManager.js';\nimport { CaretNavigationPlugin } from '../plugins/caret-navigation/CaretNavigationPlugin.js';\nimport { GapCursorPlugin } from '../plugins/gap-cursor/GapCursorPlugin.js';\nimport { BEFORE_PRINT } from '../plugins/print/PrintTypes.js';\nimport { TextFormattingPlugin } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport type { TextFormattingConfig } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport type { ToolbarOverflowBehavior } from '../plugins/toolbar/ToolbarOverflowBehavior.js';\nimport { ToolbarPlugin } from '../plugins/toolbar/ToolbarPlugin.js';\nimport type { ToolbarLayoutConfig } from '../plugins/toolbar/ToolbarPlugin.js';\nimport { EditorState } from '../state/EditorState.js';\nimport { isAllowedInReadonly } from '../state/ReadonlyGuard.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport {\n\tcreateRuntimeStyleSheet,\n\tregisterStyleRoot,\n\tunregisterStyleRoot,\n} from '../style/StyleRuntime.js';\nimport { EditorView } from '../view/EditorView.js';\nimport { buildAnnouncement } from './Announcer.js';\nimport type {\n\tContentCSSResult,\n\tContentHTMLOptions,\n\tSetContentHTMLOptions,\n} from './ContentHTMLTypes.js';\nimport { parseHTMLToDocument } from './DocumentParser.js';\nimport { serializeDocumentToCSS, serializeDocumentToHTML } from './DocumentSerializer.js';\nimport { createEditorDOM } from './EditorDOM.js';\nimport { EditorThemeController } from './EditorThemeController.js';\nimport { PaperLayoutController } from './PaperLayoutController.js';\nimport { type PaperSize, isValidPaperSize } from './PaperSize.js';\nimport { type Theme, ThemePreset } from './theme/ThemeTokens.js';\n\n/**\n * Expanded toolbar configuration for `createEditor`.\n * Allows specifying both the plugin layout and overflow behavior.\n */\nexport interface ToolbarConfig {\n\t/**\n\t * Plugin groups defining toolbar layout. Each inner array is a visual group;\n\t * separators are rendered between groups. Order = array order.\n\t */\n\treadonly groups: ReadonlyArray<ReadonlyArray<Plugin>>;\n\t/**\n\t * Controls responsive overflow behavior when items exceed available width.\n\t * Defaults to `ToolbarOverflowBehavior.BurgerMenu`.\n\t */\n\treadonly overflow?: ToolbarOverflowBehavior;\n}\n\nexport interface NotectlEditorConfig {\n\t/** Controls which inline marks are enabled. Used to auto-configure TextFormattingPlugin. */\n\tfeatures?: Partial<TextFormattingConfig>;\n\tplugins?: readonly Plugin[];\n\t/**\n\t * Toolbar configuration. Accepts either:\n\t * - A shorthand array of plugin groups: `[[BoldPlugin, ItalicPlugin], [HeadingPlugin]]`\n\t * - A full config object: `{ groups: [...], overflow: ToolbarOverflowBehavior.Flow }`\n\t *\n\t * When set, a ToolbarPlugin is created internally — do not add one to `plugins`.\n\t */\n\ttoolbar?: ReadonlyArray<ReadonlyArray<Plugin>> | ToolbarConfig;\n\tplaceholder?: string;\n\treadonly?: boolean;\n\tautofocus?: boolean;\n\tmaxHistoryDepth?: number;\n\t/** Theme preset or custom Theme object. Defaults to ThemePreset.Light. */\n\ttheme?: ThemePreset | Theme;\n\t/** Optional nonce for fallback runtime `<style>` elements when strict mode cannot use adopted sheets. */\n\tstyleNonce?: string;\n\t/** Paper size for WYSIWYG page layout. When set, content renders at exact paper width. */\n\tpaperSize?: PaperSize;\n\t/** Editor locale. Defaults to Locale.BROWSER (auto-detect from navigator.language). */\n\tlocale?: Locale;\n}\n\nexport interface StateChangeEvent {\n\toldState: EditorState;\n\tnewState: EditorState;\n\ttransaction: Transaction;\n}\n\ntype EventMap = {\n\tstateChange: StateChangeEvent;\n\tselectionChange: { selection: import('../model/Selection.js').EditorSelection };\n\tfocus: undefined;\n\tblur: undefined;\n\tready: undefined;\n};\n\ntype EventCallback<T> = (payload: T) => void;\n\nexport class NotectlEditor extends HTMLElement {\n\tprivate view: EditorView | null = null;\n\tprivate pluginManager: PluginManager | null = null;\n\tprivate contentElement: HTMLElement | null = null;\n\tprivate editorWrapper: HTMLElement | null = null;\n\tprivate topPluginContainer: HTMLElement | null = null;\n\tprivate bottomPluginContainer: HTMLElement | null = null;\n\tprivate announcer: HTMLElement | null = null;\n\tprivate config: NotectlEditorConfig = {};\n\tprivate eventListeners: Map<string, Set<EventCallback<unknown>>> = new Map();\n\tprivate readyPromiseResolve: (() => void) | null = null;\n\tprivate readonly readyPromise: Promise<void>;\n\tprivate initialized = false;\n\tprivate preInitPlugins: Plugin[] = [];\n\tprivate themeController: EditorThemeController | null = null;\n\tprivate paperLayout: PaperLayoutController | null = null;\n\tprivate runtimeStyleSheet: CSSStyleSheet | null = null;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.readyPromise = new Promise((resolve) => {\n\t\t\tthis.readyPromiseResolve = resolve;\n\t\t});\n\t\tthis.attachShadow({ mode: 'open' });\n\t}\n\n\tstatic get observedAttributes(): string[] {\n\t\treturn ['placeholder', 'readonly', 'theme', 'paper-size'];\n\t}\n\n\tconnectedCallback(): void {\n\t\tif (this.initialized) return;\n\t\tthis.init();\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tsetTimeout(() => {\n\t\t\tif (!this.isConnected) {\n\t\t\t\tthis.destroy();\n\t\t\t}\n\t\t}, 0);\n\t}\n\n\tattributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n\t\tif (name === 'placeholder' && this.contentElement) {\n\t\t\tthis.contentElement.setAttribute('data-placeholder', newValue ?? '');\n\t\t}\n\t\tif (name === 'readonly' && this.contentElement) {\n\t\t\tconst isReadonly: boolean = newValue !== null;\n\t\t\tthis.contentElement.contentEditable = isReadonly ? 'false' : 'true';\n\t\t\tif (isReadonly) {\n\t\t\t\tthis.contentElement.setAttribute('aria-readonly', 'true');\n\t\t\t} else {\n\t\t\t\tthis.contentElement.removeAttribute('aria-readonly');\n\t\t\t}\n\t\t\tthis.config = { ...this.config, readonly: isReadonly };\n\t\t\tthis.pluginManager?.setReadOnly(isReadonly);\n\t\t}\n\t\tif (name === 'theme' && this.themeController) {\n\t\t\tthis.themeController.apply((newValue as ThemePreset) ?? ThemePreset.Light);\n\t\t}\n\t\tif (name === 'paper-size') {\n\t\t\tif (newValue === null) {\n\t\t\t\tthis.configure({ paperSize: undefined });\n\t\t\t} else if (isValidPaperSize(newValue)) {\n\t\t\t\tthis.configure({ paperSize: newValue });\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Registers a plugin before initialization. */\n\tregisterPlugin(plugin: Plugin): void {\n\t\tif (this.initialized) {\n\t\t\tthrow new Error(\n\t\t\t\t'Cannot register plugins after initialization. Register before calling init() or adding to DOM.',\n\t\t\t);\n\t\t}\n\t\tthis.preInitPlugins.push(plugin);\n\t}\n\n\t/** Initializes the editor with the given config. */\n\tasync init(config?: NotectlEditorConfig): Promise<void> {\n\t\tif (this.initialized) return;\n\t\tthis.initialized = true;\n\n\t\tif (config) this.config = config;\n\n\t\tconst shadow = this.shadowRoot;\n\t\tif (!shadow) return;\n\n\t\t// Apply theme (default: Light) — must happen before editor stylesheet\n\t\tthis.themeController = new EditorThemeController(shadow);\n\t\tthis.setupStyleRuntime(shadow);\n\t\tthis.themeController.apply(this.config.theme ?? ThemePreset.Light);\n\n\t\t// 1. Build DOM structure\n\t\tconst dom = createEditorDOM({\n\t\t\treadonly: this.config.readonly,\n\t\t\tplaceholder: this.config.placeholder,\n\t\t});\n\t\tthis.editorWrapper = dom.wrapper;\n\t\tthis.contentElement = dom.content;\n\t\tthis.topPluginContainer = dom.topPluginContainer;\n\t\tthis.bottomPluginContainer = dom.bottomPluginContainer;\n\t\tthis.announcer = dom.announcer;\n\n\t\tshadow.appendChild(this.editorWrapper);\n\n\t\t// Apply paper layout if configured (before plugins, so initial render is correct)\n\t\tif (this.config.paperSize) {\n\t\t\tthis.paperLayout = new PaperLayoutController(this.editorWrapper, this.contentElement);\n\t\t\tthis.paperLayout.apply(this.config.paperSize);\n\t\t}\n\n\t\t// 2. Create PluginManager (SchemaRegistry is available)\n\t\tthis.pluginManager = new PluginManager();\n\n\t\t// Register global LocaleService before plugins so they can resolve locale\n\t\tconst localeService = new LocaleService(this.config.locale ?? 'browser');\n\t\tthis.pluginManager.registerService(LocaleServiceKey, localeService);\n\n\t\t// 3. Register built-in specs on the registry\n\t\tregisterBuiltinSpecs(this.pluginManager.schemaRegistry);\n\n\t\t// Process declarative toolbar config (registers ToolbarPlugin + toolbar plugins)\n\t\tthis.processToolbarConfig();\n\n\t\t// Register plugins from config\n\t\tfor (const plugin of this.config.plugins ?? []) {\n\t\t\tthis.pluginManager.register(plugin);\n\t\t}\n\n\t\t// Register plugins from registerPlugin() calls\n\t\tfor (const plugin of this.preInitPlugins) {\n\t\t\tthis.pluginManager.register(plugin);\n\t\t}\n\t\tthis.preInitPlugins = [];\n\n\t\t// Auto-register essential plugins if none were explicitly provided\n\t\tthis.ensureTextFormattingPlugin();\n\t\tthis.ensureCaretNavigationPlugin();\n\t\tthis.ensureGapCursorPlugin();\n\n\t\t// Set up DOM events before plugin init\n\t\tthis.contentElement.addEventListener('focus', () => this.emit('focus', undefined));\n\t\tthis.contentElement.addEventListener('blur', () => this.emit('blur', undefined));\n\n\t\t// 4. Initialize plugins — specs are registered during init().\n\t\t// onBeforeReady fires after all init() but before onReady(),\n\t\t// so the schema is complete and the view renders once.\n\t\tconst contentEl = this.contentElement;\n\t\tconst pluginMgr = this.pluginManager;\n\t\tconst topContainer = this.topPluginContainer;\n\t\tconst bottomContainer = this.bottomPluginContainer;\n\t\tif (!contentEl || !pluginMgr || !topContainer || !bottomContainer) return;\n\n\t\tconst announcer = this.announcer;\n\t\tawait pluginMgr.init({\n\t\t\tgetState: () => {\n\t\t\t\tif (!this.view) throw new Error('View not initialized');\n\t\t\t\treturn this.view.getState();\n\t\t\t},\n\t\t\tdispatch: (tr) => this.dispatch(tr),\n\t\t\tgetContainer: () => contentEl,\n\t\t\tgetPluginContainer: (position) => (position === 'top' ? topContainer : bottomContainer),\n\t\t\tannounce: (text: string) => {\n\t\t\t\tif (announcer) announcer.textContent = text;\n\t\t\t},\n\t\t\thasAnnouncement: () => !!announcer?.textContent,\n\t\t\tonBeforeReady: () => {\n\t\t\t\tconst schema = schemaFromRegistry(pluginMgr.schemaRegistry);\n\t\t\t\tconst state = EditorState.create({ schema });\n\t\t\t\tthis.view = new EditorView(contentEl, {\n\t\t\t\t\tstate,\n\t\t\t\t\tschemaRegistry: pluginMgr.schemaRegistry,\n\t\t\t\t\tkeymapRegistry: pluginMgr.keymapRegistry,\n\t\t\t\t\tinputRuleRegistry: pluginMgr.inputRuleRegistry,\n\t\t\t\t\tfileHandlerRegistry: pluginMgr.fileHandlerRegistry,\n\t\t\t\t\tnodeViewRegistry: pluginMgr.nodeViewRegistry,\n\t\t\t\t\tmaxHistoryDepth: this.config.maxHistoryDepth,\n\t\t\t\t\tgetDecorations: (s, tr) =>\n\t\t\t\t\t\tthis.pluginManager?.collectDecorations(s, tr) ?? DecorationSet.empty,\n\t\t\t\t\tonStateChange: (oldState, newState, tr) => {\n\t\t\t\t\t\tthis.onStateChange(oldState, newState, tr);\n\t\t\t\t\t},\n\t\t\t\t\tisReadOnly: () => this.config.readonly ?? false,\n\t\t\t\t});\n\t\t\t\tthis.updateEmptyState();\n\n\t\t\t\t// Inject plugin-registered stylesheets into adopted stylesheets\n\t\t\t\tconst pluginSheets = pluginMgr.getPluginStyleSheets();\n\t\t\t\tif (pluginSheets.length > 0) {\n\t\t\t\t\tthis.themeController?.setPluginStyleSheets(pluginSheets);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\t\t// Guard: editor may have been destroyed during async plugin init\n\t\tif (!this.pluginManager) return;\n\n\t\t// Notify plugins of initial readonly state\n\t\tif (this.config.readonly) {\n\t\t\tthis.pluginManager.setReadOnly(true);\n\t\t}\n\n\t\t// Register BEFORE_PRINT listener to inject paperSize as fallback\n\t\tthis.pluginManager.onEvent(BEFORE_PRINT, (event) => {\n\t\t\tif (!event.options.paperSize && this.config.paperSize) {\n\t\t\t\tevent.options = { ...event.options, paperSize: this.config.paperSize };\n\t\t\t}\n\t\t});\n\n\t\tif (this.config.autofocus) {\n\t\t\trequestAnimationFrame(() => this.contentElement?.focus());\n\t\t}\n\n\t\tthis.readyPromiseResolve?.();\n\t\tthis.emit('ready', undefined);\n\t}\n\n\t/** Returns whether the editor is in read-only mode. */\n\tget isReadOnly(): boolean {\n\t\treturn this.config.readonly ?? false;\n\t}\n\n\t// --- Content API ---\n\n\t/** Returns the document as JSON. */\n\tgetJSON(): Document {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\treturn this.view.getState().doc;\n\t}\n\n\t/** Sets the document from JSON. */\n\tsetJSON(doc: Document): void {\n\t\tconst schema = this.pluginManager\n\t\t\t? schemaFromRegistry(this.pluginManager.schemaRegistry)\n\t\t\t: undefined;\n\t\tconst state = EditorState.create({\n\t\t\tdoc,\n\t\t\tschema,\n\t\t\tselection: createCollapsedSelection(doc.children[0]?.id ?? blockId(''), 0),\n\t\t});\n\t\tthis.replaceState(state);\n\t}\n\n\t/** Returns sanitized HTML representation of the document. */\n\tgetContentHTML(): string;\n\tgetContentHTML(options: { pretty?: boolean }): string;\n\tgetContentHTML(options: ContentHTMLOptions & { cssMode: 'classes' }): ContentCSSResult;\n\tgetContentHTML(options?: ContentHTMLOptions): string | ContentCSSResult {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\tconst doc = this.view.getState().doc;\n\t\tconst registry = this.pluginManager?.schemaRegistry;\n\n\t\tif (options?.cssMode === 'classes') {\n\t\t\tconst result: ContentCSSResult = serializeDocumentToCSS(doc, registry);\n\t\t\treturn options.pretty\n\t\t\t\t? { html: formatHTML(result.html), css: result.css, styleMap: result.styleMap }\n\t\t\t\t: result;\n\t\t}\n\n\t\tconst html: string = serializeDocumentToHTML(doc, registry);\n\t\treturn options?.pretty ? formatHTML(html) : html;\n\t}\n\n\t/** Sets content from HTML (sanitized). Accepts optional `styleMap` for class-based round-trip. */\n\tsetContentHTML(html: string, options?: SetContentHTMLOptions): void {\n\t\tconst doc = parseHTMLToDocument(html, this.pluginManager?.schemaRegistry, options);\n\t\tthis.setJSON(doc);\n\t}\n\n\t/** Returns plain text content. */\n\tgetText(): string {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\tconst doc = this.view.getState().doc;\n\t\treturn doc.children.map((b) => getBlockText(b)).join('\\n');\n\t}\n\n\t/** Returns true if the editor is empty (single empty paragraph). */\n\tisEmpty(): boolean {\n\t\tif (!this.view) return true;\n\t\tconst doc = this.view.getState().doc;\n\t\tif (doc.children.length === 0) return true;\n\t\tif (doc.children.length > 1) return false;\n\t\tconst block = doc.children[0];\n\t\tif (!block) return true;\n\t\treturn block.type === 'paragraph' && getBlockText(block) === '';\n\t}\n\n\t// --- Command API ---\n\n\treadonly commands = {\n\t\ttoggleBold: () => this.executeCommand('toggleBold'),\n\t\ttoggleItalic: () => this.executeCommand('toggleItalic'),\n\t\ttoggleUnderline: () => this.executeCommand('toggleUnderline'),\n\t\tundo: () => {\n\t\t\tif (this.config.readonly) return;\n\t\t\tthis.view?.undo();\n\t\t},\n\t\tredo: () => {\n\t\t\tif (this.config.readonly) return;\n\t\t\tthis.view?.redo();\n\t\t},\n\t\tselectAll: () => {\n\t\t\tif (!this.view) return;\n\t\t\tconst tr = selectAll(this.view.getState());\n\t\t\tthis.dispatch(tr);\n\t\t},\n\t};\n\n\t/** Checks whether a command can be executed. */\n\tcan(): {\n\t\ttoggleBold: () => boolean;\n\t\ttoggleItalic: () => boolean;\n\t\ttoggleUnderline: () => boolean;\n\t\tundo: () => boolean;\n\t\tredo: () => boolean;\n\t\tselectAll: () => boolean;\n\t} {\n\t\tconst schema = this.view?.getState().schema;\n\t\tconst readonly: boolean = this.config.readonly ?? false;\n\t\treturn {\n\t\t\ttoggleBold: () => !readonly && (schema ? isMarkAllowed(schema, 'bold') : false),\n\t\t\ttoggleItalic: () => !readonly && (schema ? isMarkAllowed(schema, 'italic') : false),\n\t\t\ttoggleUnderline: () => !readonly && (schema ? isMarkAllowed(schema, 'underline') : false),\n\t\t\tundo: () => !readonly && (this.view?.history.canUndo() ?? false),\n\t\t\tredo: () => !readonly && (this.view?.history.canRedo() ?? false),\n\t\t\tselectAll: () => this.canExecuteCommand('selectAll'),\n\t\t};\n\t}\n\n\t/** Returns whether a named command can be executed. */\n\tcanExecuteCommand(name: string): boolean {\n\t\treturn this.pluginManager?.canExecuteCommand(name) ?? false;\n\t}\n\n\t/** Executes a named command registered by a plugin. */\n\texecuteCommand(name: string): boolean {\n\t\treturn this.pluginManager?.executeCommand(name) ?? false;\n\t}\n\n\t/** Configures a plugin at runtime. */\n\tconfigurePlugin(pluginId: string, config: PluginConfig): void {\n\t\tthis.pluginManager?.configurePlugin(pluginId, config);\n\t}\n\n\t/** Returns a registered plugin service by typed key. */\n\tgetService<T>(key: ServiceKey<T>): T | undefined {\n\t\treturn this.pluginManager?.getService(key);\n\t}\n\n\t/** Subscribes to a plugin event. Returns an unsubscribe function. */\n\tonPluginEvent<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void {\n\t\treturn this.pluginManager?.onEvent(key, callback) ?? (() => {});\n\t}\n\n\t// --- State API ---\n\n\t/** Returns the current editor state. */\n\tgetState(): EditorState {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\treturn this.view.getState();\n\t}\n\n\t/** Dispatches a transaction (routed through middleware if any). */\n\tdispatch(tr: Transaction): void {\n\t\tif (!this.view || !this.pluginManager) return;\n\t\tif (\n\t\t\tthis.config.readonly &&\n\t\t\t!isAllowedInReadonly(tr) &&\n\t\t\t!this.pluginManager.isReadonlyBypassed()\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tthis.pluginManager.dispatchWithMiddleware(tr, this.view.getState(), (finalTr) =>\n\t\t\tthis.view?.dispatch(finalTr),\n\t\t);\n\t}\n\n\t// --- Event API ---\n\n\t/** Registers an event listener. */\n\ton<K extends keyof EventMap>(event: K, callback: EventCallback<EventMap[K]>): void {\n\t\tif (!this.eventListeners.has(event)) {\n\t\t\tthis.eventListeners.set(event, new Set());\n\t\t}\n\t\tthis.eventListeners.get(event)?.add(callback as EventCallback<unknown>);\n\t}\n\n\t/** Removes an event listener. */\n\toff<K extends keyof EventMap>(event: K, callback: EventCallback<EventMap[K]>): void {\n\t\tthis.eventListeners.get(event)?.delete(callback as EventCallback<unknown>);\n\t}\n\n\t// --- Lifecycle ---\n\n\t/** Waits for the editor to be ready. */\n\twhenReady(): Promise<void> {\n\t\treturn this.readyPromise;\n\t}\n\n\t/** Updates configuration at runtime. */\n\tconfigure(config: Partial<NotectlEditorConfig>): void {\n\t\tif (config.placeholder !== undefined && this.contentElement) {\n\t\t\tthis.contentElement.setAttribute('data-placeholder', config.placeholder);\n\t\t}\n\n\t\tif (config.readonly !== undefined && this.contentElement) {\n\t\t\tthis.contentElement.contentEditable = config.readonly ? 'false' : 'true';\n\t\t\tif (config.readonly) {\n\t\t\t\tthis.contentElement.setAttribute('aria-readonly', 'true');\n\t\t\t} else {\n\t\t\t\tthis.contentElement.removeAttribute('aria-readonly');\n\t\t\t}\n\t\t\tthis.pluginManager?.setReadOnly(config.readonly);\n\t\t}\n\n\t\tif ('paperSize' in config) {\n\t\t\tthis.applyPaperSize(config.paperSize);\n\t\t}\n\n\t\tthis.config = { ...this.config, ...config };\n\t}\n\n\t// --- Theme API ---\n\n\t/** Changes the theme at runtime. */\n\tsetTheme(theme: ThemePreset | Theme): void {\n\t\tthis.config = { ...this.config, theme };\n\t\tthis.themeController?.apply(theme);\n\t}\n\n\t/** Returns the current theme setting. */\n\tgetTheme(): ThemePreset | Theme {\n\t\treturn this.config.theme ?? ThemePreset.Light;\n\t}\n\n\t// --- Paper Size API ---\n\n\t/** Returns the currently configured paper size, or undefined if fluid layout. */\n\tgetPaperSize(): PaperSize | undefined {\n\t\treturn this.config.paperSize;\n\t}\n\n\t/** Cleans up the editor. Awaiting ensures async plugin teardown completes. */\n\tdestroy(): Promise<void> {\n\t\tthis.paperLayout?.destroy();\n\t\tthis.paperLayout = null;\n\t\tthis.teardownStyleRuntime();\n\t\tthis.themeController?.destroy();\n\t\tthis.themeController = null;\n\t\tthis.view?.destroy();\n\t\tconst pluginTeardown = this.pluginManager?.destroy() ?? Promise.resolve();\n\t\tthis.view = null;\n\t\tthis.pluginManager = null;\n\t\tthis.initialized = false;\n\t\tthis.editorWrapper?.remove();\n\t\tthis.editorWrapper = null;\n\t\tthis.contentElement = null;\n\t\tthis.topPluginContainer = null;\n\t\tthis.bottomPluginContainer = null;\n\t\tthis.announcer = null;\n\t\treturn pluginTeardown;\n\t}\n\n\t/**\n\t * Processes the declarative `toolbar` config: registers a ToolbarPlugin\n\t * with layout groups, then registers all plugins from the toolbar groups.\n\t * Accepts both the shorthand array and the full ToolbarConfig object.\n\t */\n\tprivate processToolbarConfig(): void {\n\t\tif (!this.pluginManager || !this.config.toolbar) return;\n\n\t\tconst toolbarCfg = this.config.toolbar;\n\t\tconst isShorthand: boolean = Array.isArray(toolbarCfg);\n\t\tconst pluginGroups: ReadonlyArray<ReadonlyArray<Plugin>> = isShorthand\n\t\t\t? (toolbarCfg as ReadonlyArray<ReadonlyArray<Plugin>>)\n\t\t\t: (toolbarCfg as ToolbarConfig).groups;\n\t\tconst overflow: ToolbarOverflowBehavior | undefined = isShorthand\n\t\t\t? undefined\n\t\t\t: (toolbarCfg as ToolbarConfig).overflow;\n\n\t\tconst groups: string[][] = [];\n\t\tfor (const group of pluginGroups) {\n\t\t\tconst pluginIds: string[] = [];\n\t\t\tfor (const plugin of group) {\n\t\t\t\tpluginIds.push(plugin.id);\n\t\t\t\tthis.pluginManager.register(plugin);\n\t\t\t}\n\t\t\tgroups.push(pluginIds);\n\t\t}\n\n\t\tconst layoutConfig: ToolbarLayoutConfig = { groups, overflow };\n\t\tthis.pluginManager.register(new ToolbarPlugin(layoutConfig));\n\t}\n\n\t/**\n\t * Auto-registers TextFormattingPlugin if no plugin with id 'text-formatting'\n\t * was explicitly registered. Uses the `features` config to determine which marks to enable.\n\t */\n\tprivate ensureTextFormattingPlugin(): void {\n\t\tif (!this.pluginManager) return;\n\n\t\tconst hasTextFormatting = this.pluginManager.get('text-formatting') !== undefined;\n\t\tif (hasTextFormatting) return;\n\n\t\tconst features: TextFormattingConfig = {\n\t\t\tbold: this.config.features?.bold ?? true,\n\t\t\titalic: this.config.features?.italic ?? true,\n\t\t\tunderline: this.config.features?.underline ?? true,\n\t\t};\n\n\t\tthis.pluginManager.register(new TextFormattingPlugin(features));\n\t}\n\n\t/** Auto-registers CaretNavigationPlugin if not explicitly provided. */\n\tprivate ensureCaretNavigationPlugin(): void {\n\t\tif (!this.pluginManager) return;\n\t\tif (this.pluginManager.get('caret-navigation') !== undefined) return;\n\t\tthis.pluginManager.register(new CaretNavigationPlugin());\n\t}\n\n\t/** Auto-registers GapCursorPlugin if not explicitly provided. */\n\tprivate ensureGapCursorPlugin(): void {\n\t\tif (!this.pluginManager) return;\n\t\tif (this.pluginManager.get('gap-cursor') !== undefined) return;\n\t\tthis.pluginManager.register(new GapCursorPlugin());\n\t}\n\n\tprivate applyPaperSize(paperSize: PaperSize | undefined): void {\n\t\tif (!this.editorWrapper || !this.contentElement) return;\n\n\t\tif (!paperSize) {\n\t\t\tthis.paperLayout?.apply(null);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.paperLayout) {\n\t\t\tthis.paperLayout = new PaperLayoutController(this.editorWrapper, this.contentElement);\n\t\t}\n\t\tthis.paperLayout.apply(paperSize);\n\t}\n\n\tprivate setupStyleRuntime(shadow: ShadowRoot): void {\n\t\tunregisterStyleRoot(shadow);\n\t\tthis.runtimeStyleSheet = createRuntimeStyleSheet();\n\n\t\tthis.themeController?.setRuntimeStyleSheets(\n\t\t\tthis.runtimeStyleSheet ? [this.runtimeStyleSheet] : [],\n\t\t);\n\n\t\tregisterStyleRoot(shadow, {\n\t\t\tnonce: this.config.styleNonce,\n\t\t\tsheet: this.runtimeStyleSheet,\n\t\t});\n\t}\n\n\tprivate teardownStyleRuntime(): void {\n\t\tconst shadow = this.shadowRoot;\n\t\tif (shadow) {\n\t\t\tunregisterStyleRoot(shadow);\n\t\t}\n\t\tthis.runtimeStyleSheet = null;\n\t\tthis.themeController?.setRuntimeStyleSheets([]);\n\t}\n\n\tprivate emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n\t\tconst listeners = this.eventListeners.get(event);\n\t\tif (listeners) {\n\t\t\tfor (const cb of listeners) {\n\t\t\t\t(cb as EventCallback<EventMap[K]>)(payload);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onStateChange(oldState: EditorState, newState: EditorState, tr: Transaction): void {\n\t\t// Clear announcer so plugin announcements can be detected\n\t\tif (this.announcer) this.announcer.textContent = '';\n\n\t\t// Notify plugins (with transaction) — plugins may call context.announce()\n\t\tthis.pluginManager?.notifyStateChange(oldState, newState, tr);\n\n\t\t// Update empty state\n\t\tthis.updateEmptyState();\n\n\t\t// Emit events\n\t\tthis.emit('stateChange', { oldState, newState, transaction: tr });\n\n\t\tif (!selectionsEqual(oldState.selection, newState.selection)) {\n\t\t\tthis.emit('selectionChange', { selection: newState.selection });\n\t\t}\n\n\t\t// Announce state changes for screen readers (skip if a plugin already announced)\n\t\tif (!this.announcer?.textContent) {\n\t\t\tconst announcement: string | null = buildAnnouncement(oldState, newState, tr);\n\t\t\tif (announcement && this.announcer) {\n\t\t\t\tthis.announcer.textContent = announcement;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate updateEmptyState(): void {\n\t\tif (!this.contentElement) return;\n\t\tthis.contentElement.classList.toggle('notectl-content--empty', this.isEmpty());\n\t}\n\n\tprivate replaceState(newState: EditorState): void {\n\t\tif (!this.view) return;\n\n\t\tthis.view.replaceState(newState);\n\t\tthis.updateEmptyState();\n\t}\n}\n\n// Register custom element (guarded for SSR / non-browser environments)\nif (typeof customElements !== 'undefined' && !customElements.get('notectl-editor')) {\n\tcustomElements.define('notectl-editor', NotectlEditor);\n}\n\n/** Factory function to create and configure a NotectlEditor instance. */\nexport async function createEditor(config?: NotectlEditorConfig): Promise<NotectlEditor> {\n\tconst editor = document.createElement('notectl-editor') as NotectlEditor;\n\tawait editor.init(config);\n\treturn editor;\n}\n","/**\n * EditorDOM: builds the editor's internal DOM structure.\n * Pure function — returns a struct of freshly created elements.\n */\n\nexport interface EditorDOMConfig {\n\treadonly readonly?: boolean;\n\treadonly placeholder?: string;\n}\n\nexport interface EditorDOMElements {\n\treadonly wrapper: HTMLElement;\n\treadonly content: HTMLElement;\n\treadonly topPluginContainer: HTMLElement;\n\treadonly bottomPluginContainer: HTMLElement;\n\treadonly announcer: HTMLElement;\n}\n\n/** Creates the editor DOM tree and returns references to all key elements. */\nexport function createEditorDOM(config: EditorDOMConfig): EditorDOMElements {\n\tconst wrapper: HTMLElement = document.createElement('div');\n\twrapper.className = 'notectl-editor';\n\n\tconst topPluginContainer: HTMLElement = document.createElement('div');\n\ttopPluginContainer.className = 'notectl-plugin-container--top';\n\ttopPluginContainer.setAttribute('data-notectl-no-print', '');\n\n\tconst content: HTMLElement = document.createElement('div');\n\tcontent.className = 'notectl-content';\n\tcontent.contentEditable = config.readonly ? 'false' : 'true';\n\tcontent.setAttribute('role', 'textbox');\n\tcontent.setAttribute('aria-multiline', 'true');\n\tcontent.setAttribute('aria-label', 'Rich text editor');\n\tif (config.readonly) {\n\t\tcontent.setAttribute('aria-readonly', 'true');\n\t}\n\tcontent.setAttribute('aria-description', 'Press Escape to exit the editor');\n\tcontent.setAttribute('data-placeholder', config.placeholder ?? 'Start typing...');\n\n\tconst bottomPluginContainer: HTMLElement = document.createElement('div');\n\tbottomPluginContainer.className = 'notectl-plugin-container--bottom';\n\tbottomPluginContainer.setAttribute('data-notectl-no-print', '');\n\n\t// Screen reader announcer\n\tconst announcer: HTMLElement = document.createElement('div');\n\tannouncer.className = 'notectl-sr-only';\n\tannouncer.setAttribute('data-notectl-no-print', '');\n\tannouncer.setAttribute('aria-live', 'polite');\n\tannouncer.setAttribute('aria-atomic', 'true');\n\n\twrapper.appendChild(topPluginContainer);\n\twrapper.appendChild(content);\n\twrapper.appendChild(bottomPluginContainer);\n\twrapper.appendChild(announcer);\n\n\treturn { wrapper, content, topPluginContainer, bottomPluginContainer, announcer };\n}\n","/**\n * Minimal preset: a lightweight editor with only font selection.\n */\n\nimport { FontPlugin } from '../plugins/font/FontPlugin.js';\nimport { STARTER_FONTS } from '../plugins/font/StarterFonts.js';\nimport type { MinimalPresetOptions, PresetConfig } from './PresetTypes.js';\n\n/**\n * Creates a minimal editor preset with font selection only.\n * CaretNavigation and GapCursor are auto-registered by the editor.\n */\nexport function createMinimalPreset(options?: MinimalPresetOptions): PresetConfig {\n\tconst fontPlugin: FontPlugin = new FontPlugin({\n\t\tfonts: STARTER_FONTS,\n\t\t...options?.font,\n\t});\n\n\treturn {\n\t\ttoolbar: [[fontPlugin]],\n\t\tplugins: [],\n\t};\n}\n","/**\n * Full preset: a fully-featured editor with all standard plugins.\n */\n\nimport { AlignmentPlugin } from '../plugins/alignment/AlignmentPlugin.js';\nimport { BlockquotePlugin } from '../plugins/blockquote/BlockquotePlugin.js';\nimport { CodeBlockPlugin } from '../plugins/code-block/CodeBlockPlugin.js';\nimport { FontSizePlugin } from '../plugins/font-size/FontSizePlugin.js';\nimport { FontPlugin } from '../plugins/font/FontPlugin.js';\nimport { STARTER_FONTS } from '../plugins/font/StarterFonts.js';\nimport { HardBreakPlugin } from '../plugins/hard-break/HardBreakPlugin.js';\nimport { HeadingPlugin } from '../plugins/heading/HeadingPlugin.js';\nimport { HighlightPlugin } from '../plugins/highlight/HighlightPlugin.js';\nimport { HorizontalRulePlugin } from '../plugins/horizontal-rule/HorizontalRulePlugin.js';\nimport { ImagePlugin } from '../plugins/image/ImagePlugin.js';\nimport { LinkPlugin } from '../plugins/link/LinkPlugin.js';\nimport { ListPlugin } from '../plugins/list/ListPlugin.js';\nimport { PrintPlugin } from '../plugins/print/PrintPlugin.js';\nimport { StrikethroughPlugin } from '../plugins/strikethrough/StrikethroughPlugin.js';\nimport { SuperSubPlugin } from '../plugins/super-sub/SuperSubPlugin.js';\nimport { TablePlugin } from '../plugins/table/TablePlugin.js';\nimport { TextColorPlugin } from '../plugins/text-color/TextColorPlugin.js';\nimport { TextFormattingPlugin } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport type { FullPresetOptions, PresetConfig } from './PresetTypes.js';\n\n/**\n * Creates a fully-featured editor preset with all standard plugins.\n *\n * Toolbar groups:\n * 1. Typography: Font, FontSize\n * 2. Inline marks: TextFormatting, Strikethrough, SuperSub\n * 3. Colors: TextColor, Highlight\n * 4. Block types: Heading, Blockquote, CodeBlock\n * 5. Paragraph layout: Alignment\n * 6. Lists: List\n * 7. Insert objects: Link, Table, HorizontalRule, Image\n * 8. Utility: Print\n */\nexport function createFullPreset(options?: FullPresetOptions): PresetConfig {\n\treturn {\n\t\ttoolbar: [\n\t\t\t[\n\t\t\t\tnew FontPlugin({ fonts: STARTER_FONTS, ...options?.font }),\n\t\t\t\tnew FontSizePlugin(options?.fontSize),\n\t\t\t],\n\t\t\t[\n\t\t\t\tnew TextFormattingPlugin(options?.textFormatting),\n\t\t\t\tnew StrikethroughPlugin(options?.strikethrough),\n\t\t\t\tnew SuperSubPlugin(options?.superSub),\n\t\t\t],\n\t\t\t[new TextColorPlugin(options?.textColor), new HighlightPlugin(options?.highlight)],\n\t\t\t[\n\t\t\t\tnew HeadingPlugin(options?.heading),\n\t\t\t\tnew BlockquotePlugin(options?.blockquote),\n\t\t\t\tnew CodeBlockPlugin(options?.codeBlock),\n\t\t\t],\n\t\t\t[new AlignmentPlugin(options?.alignment)],\n\t\t\t[new ListPlugin(options?.list)],\n\t\t\t[\n\t\t\t\tnew LinkPlugin(options?.link),\n\t\t\t\tnew TablePlugin(options?.table),\n\t\t\t\tnew HorizontalRulePlugin(options?.horizontalRule),\n\t\t\t\tnew ImagePlugin(options?.image),\n\t\t\t],\n\t\t\t[new PrintPlugin(options?.print)],\n\t\t],\n\t\tplugins: [new HardBreakPlugin()],\n\t};\n}\n"],"names":["SchemaRegistry","_nodeSpecs","Map","_markSpecs","_inlineNodeSpecs","spec","this","has","type","Error","set","get","delete","getNodeTypes","keys","getMarkTypes","getInlineNodeTypes","getBlockParseRules","results","parseHTML","rule","push","sort","a","b","priority","getMarkParseRules","getAllowedTags","tags","Set","values","sanitize","tag","add","getAllowedAttrs","attrs","attr","clear","canContain","registry","parentType","childType","parentSpec","getNodeSpec","content","childSpec","childGroup","group","allowed","allow","validateContent","childTypes","min","max","Number","POSITIVE_INFINITY","blockChildTypes","filter","t","length","registerBuiltinSpecs","registerNodeSpec","toDOM","node","createBlockElement","id","toHTML","_node","mapBlock","doc","blockId","fn","children","mapBlockInChildren","map","child","isBlockNode","mappedChildren","mapNodeByPath","path","rootId","mapNodeByPathRecursive","depth","targetId","newChildren","findAndTransformChildren","predicate","transform","changed","result","sliceInlineContent","nodes","from","to","pos","isInlineNode","nodeEnd","text","sliceFrom","Math","sliceTo","slice","createTextNode","marks","applyMarkToInlineContent","mark","newMarks","addMarkToSet","removeMarkFromSet","overlapStart","overlapEnd","beforeText","insideText","afterText","replaceInlineChildren","original","newInlineChildren","every","c","isTextNode","blockChildren","applyStep","step","block","inlineChildren","getInlineChildren","segments","offset","inserted","seg","localOffset","before","after","normalizeInlineContent","deleteFrom","deleteTo","remaining","transformed","some","blockIndex","findIndex","len","getBlockLength","nodesBeforeSplit","nodesAfterSplit","updatedBlock","newBlock","createBlockNode","newBlockId","splice","targetBlockId","sourceBlockId","targetIdx","sourceIdx","target","source","targetInline","sourceInline","mergedChildren","mergedBlock","nodeType","parentPath","index","parent","nodeId","inlineNode","invertStep","deletedText","deletedMarks","deletedSegments","targetLengthBefore","previousMarks","previousNodeType","previousAttrs","removedNode","invertTransaction","tr","steps","reverse","selectionBefore","selectionAfter","storedMarksAfter","metadata","origin","timestamp","Date","now","TransactionBuilder","selection","storedMarks","workingDoc","_readonlyAllowed","currentSelection","currentStoredMarks","advanceDoc","findNode","getBlockSegmentsInRange","getBlockText","getBlockMarksAtOffset","deleteText","targetBlock","mergeBlocks","resolveNodeByPath","join","getContentAtOffset","kind","readonlyAllowed","createNodeSelection","EditorState","schema","_blockMap","_blockOrder","options","defaultSchema","createDocument","firstBlock","createCollapsedSelection","sel","isNodeSelection","fallbackSelection","isGapCursor","anchor","validatePosition","head","createSelection","walk","blocks","order","isLeafBlock","findNodePath","parentId","json","createPosition","leaf","findFirstLeafBlock","nested","isSelectionOnlyTransaction","isAllowedInReadonly","HistoryManager","undoStack","redoStack","groupTimeoutMs","maxDepth","lastOrigin","lastGroup","isSameInputType","transactions","shift","state","pop","currentState","allSteps","i","inverted","apply","transaction","historyDirection","canUndo","canRedo","existing","incoming","lastTr","lastStepType","incomingStepType","deleteInDirection","config","deleteNodeSelection","isCollapsed","deleteSelectionCommand","getBlock","range","merge","deleteTextAt","setSelection","build","deleteBackward","mergeBlockBackward","_block","deleteForward","mergeBlockForward","KeyboardHandler","element","getState","dispatch","undo","redo","keymapRegistry","isReadOnly","compositionTracker","handleKeydown","onKeydown","bind","addEventListener","e","isComposing","handleNodeSelectionKeys","handleGapCursorKeys","descriptor","normalizeKeyDescriptor","navKeymaps","getKeymapsByPriority","navigation","handler","preventDefault","handleEscape","groups","keymaps","context","default","handleGapCursorArrowFallback","handleTab","metaKey","ctrlKey","key","toLowerCase","shiftKey","selectAll","altKey","navigateArrowIntoVoid","splitBlockCommand","deleteBackwardAtGap","deleteForwardAtGap","insertTextCommand","navigateFromGapCursor","selectionsEqual","blur","destroy","removeEventListener","parts","toUpperCase","buildMarkOrder","types","getMarkSpec","rank","serializeMarksToHTML","markOrder","html","escapeHTML","sortedMarks","styleParts","tagMarks","markSpec","toHTMLStyle","style","toHTMLString","serializeMarksToClassHTML","collector","declarations","getClassName","current","ClipboardHandler","schemaRegistry","syncSelection","handleCopy","onCopy","handleCut","onCut","isTextSelection","clipboardData","writeNodeSelectionToClipboard","writeTextSelectionToClipboard","blockData","setData","JSON","stringify","altText","alt","blockOrder","getBlockOrder","selectionRange","fromIdx","indexOf","toIdx","lines","richBlocks","bid","blockLen","start","end","sliced","plainText","htmlParts","serializeBlockRangeToHTML","childEnd","getInlineNodeSpec","inlineType","CompositionTracker","_composing","_activeBlockId","KeymapRegistry","_contextKeymaps","_navigationKeymaps","_defaultKeymaps","keymap","allKeymaps","Object","console","debug","keymapArrayForPriority","getKeymaps","arr","idx","InputRuleRegistry","_inputRules","getInputRules","FileHandlerRegistry","_fileHandlers","pattern","getFileHandlers","mimeType","handlers","entry","matchMimePattern","endsWith","prefix","startsWith","NodeViewRegistry","_nodeViews","factory","ToolbarRegistry","_toolbarItems","_toolbarItemPluginMap","item","pluginId","ids","items","getToolbarItems","BlockTypePickerRegistry","_entries","getBlockTypePickerEntries","getMarkRank","createMarkElement","document","createElement","CursorWrapper","wrapperElement","container","cleanup","wrapper","setAttribute","textNode","el","appendChild","domSel","getSelection","rangeCount","getRangeAt","insertNode","collapse","remove","GRID_NAV_KEYS","attachMenuKeyboard","focusedIndex","stopPropagation","Array","querySelectorAll","itemSelector","onClose","findNextDropdownItem","applyRovingTabindex","focus","onActivate","attachListboxKeyboard","onSelect","attachGridKeyboard","columns","totalCells","totalRows","ceil","cells","cellSelector","cell","currentRow","floor","currentCol","newRow","newCol","navigateGrid","newIdx","onNavigate","rowStart","rowEnd","EventBus","listeners","payload","listener","err","error","callback","size","PluginManager","plugins","commands","services","middlewares","registrations","eventBus","pluginStyleSheets","inputRuleRegistry","fileHandlerRegistry","nodeViewRegistry","toolbarRegistry","blockTypePickerRegistry","middlewareSorted","initOrder","initialized","initializing","readOnly","readonlyBypassActive","service","plugin","resolveOrder","createContext","init","onBeforeReady","onReady","oldState","newState","onStateChange","DecorationSet","empty","decorations","decos","isEmpty","finalDispatch","sorted","getSortedMiddleware","dispatched","next","currentTr","called","guardedNext","middleware","name","enableBypass","onConfigure","readonly","onReadOnlyChange","getPluginIds","getMiddlewareChain","on","reversed","destroyPlugin","cleanupRegistrations","reg","serviceId","unsub","unsubscribers","nodeSpecs","removeNodeSpec","markSpecs","removeMarkSpec","inlineNodeSpecs","removeInlineNodeSpec","nodeViews","removeNodeView","removeKeymap","inputRules","removeInputRule","itemId","toolbarItems","removeToolbarItem","fileHandlers","removeFileHandler","entryId","blockTypePickerEntries","removeBlockTypePickerEntry","sheet","stylesheets","pluginEventBus","emit","off","getContainer","getPluginContainer","registerCommand","executeCommand","getEventBus","registerMiddleware","registerService","getService","updateConfig","registerMarkSpec","registerNodeView","registerKeymap","registerInputRule","registerToolbarItem","registerInlineNodeSpec","registerFileHandler","registerBlockTypePickerEntry","getSchemaRegistry","getKeymapRegistry","getInputRuleRegistry","getFileHandlerRegistry","getNodeViewRegistry","getToolbarRegistry","getBlockTypePickerRegistry","registerStyleSheet","css","CSSStyleSheet","replaceSync","announce","hasAnnouncement","dep","dependencies","inDegree","dependents","deps","depList","queue","deg","newDeg","missing","includes","PRINT_LOCALE_EN","label","tooltip","shortcut","printingAnnouncement","PRINT_LOCALES","en","de","es","fr","zh","ru","ar","hi","resolveContent","value","MM_TO_PX","PaperSize","DINA4","DINA5","USLetter","USLegal","mmToPx","mm","round","PAPER_DIMENSIONS","widthMm","heightMm","widthPx","heightPx","CSS_SIZE_KEYWORDS","getPaperDimensions","dims","PAPER_MARGIN_TOP_PX","PAPER_MARGIN_HORIZONTAL_PX","PAPER_VIEWPORT_PADDING_PX","isValidPaperSize","getPaperCSSSize","keyword","PRINT_SERVICE_KEY","ServiceKey","BEFORE_PRINT","EventKey","AFTER_PRINT","NOOP_SERVICE","print","PrintPlugin","locale","resolvePluginLocale","rootNode","getRootNode","ShadowRoot","host","shadowRoot","mergeOptions","executePrint","beforeEvent","cancelled","finalOptions","title","lang","replace","adopted","adoptedStyleSheets","cssRules","cssText","theme","computed","getComputedStyle","tokens","prop","getPropertyValue","trim","paperSize","props","rules","printCSS","pageProps","margin","orientation","sizeParts","printRules","printBackground","customCSS","clone","querySelector","cloneNode","removeAttribute","selectionClasses","cls","classList","excludeBlockTypes","elements","pageBreakBefore","setStyleProperties","breakBefore","header","headerEl","className","innerHTML","insertBefore","firstChild","footer","footerEl","outerHTML","closest","getAttribute","documentElement","afterEvent","iframe","body","iframeDoc","contentDocument","removeChild","open","write","close","contentWindow","once","defaults","printLocale","keyBinding","showToolbarItem","formatShortcut","icon","command","ThemePreset","Light","Dark","System","LIGHT_THEME","primitives","background","foreground","mutedForeground","border","borderFocus","primary","primaryForeground","primaryMuted","surfaceRaised","surfaceOverlay","hoverBackground","activeBackground","danger","dangerMuted","success","shadow","focusRing","codeBlock","headerBackground","headerForeground","headerBorder","DARK_THEME","createTheme","base","overrides","toolbar","resolveTheme","VARIABLE_MAP","COMPONENT_FALLBACKS","resolvePath","split","part","generateThemeCSS","cssVar","fallback","createThemeStyleSheet","Locale","EN","DE","ES","FR","ZH","RU","AR","HI","BROWSER","fnv1aHash","input","hash","charCodeAt","imul","toString","padStart","CSSClassCollector","classMap","usedHashes","normalized","d","suffix","String","alignment","toCSS","toStyleMap","VALID_ALIGNMENTS","serializeDocumentToHTML","ctx","exportCtx","styleAttr","serializeBlocks","allowedTags","allowedAttrs","DOMPurify","ALLOWED_TAGS","ALLOWED_ATTR","serializeDocumentToCSS","filteredAttrs","styleMap","isNodeOfType","listItems","serializeListGroup","serializeBlock","stack","listType","indent","top","nextItem","nextIndent","stripTrailingLiClose","merged","prev","markSetsEqual","inlineSpec","getBlockChildren","align","getAlignmentClassName","firstTagEnd","existingClass","match","existingStyle","existingValue","test","parseHTMLToDocument","template","root","htmlEl","classes","toRemove","separator","blockRules","childNodes","Node","ELEMENT_NODE","tagName","parseListElement","matchBlockParseRule","inlineContent","parseElementToInlineContent","extractAlignment","TEXT_NODE","textContent","listEl","li","checkbox","isChecklist","checked","hasAttribute","resolvedType","liChild","liChildTag","skipNestedLists","walkElement","getInlineParseRules","currentMarks","markRules","inlineRules","getAttrs","createInlineNode","matchedTypes","m","markType","textAlign","alignValue","injectContentStyles","globalThis","getElementById","HTMLStyleElement","nonce","removeContentStyles","notectlSheets","WeakSet","adoptContentStyles","s","removeAdoptedStyles","InputHandler","handleBeforeInput","onBeforeInput","handleCompositionStart","onCompositionStart","handleCompositionEnd","onCompositionEnd","inputType","data","insertHardBreakCommand","findWordBoundaryBackward","findWordBoundaryForward","checkInputRules","_e","composedText","textBefore","exec","segmentsToText","reduce","acc","segmentsLength","gapInsertIndex","insertIndex","side","pasteBlocksAtGap","gap","builder","lastBlockId","insertAt","lastTextLen","newId","generateBlockId","textNodes","BLOCK_ELEMENTS","INLINE_ELEMENTS","HTMLParser","blockParseRules","markParseRules","parseContainer","resolveBlockType","pendingSegments","isBlockElement","flushPendingSegments","parseBlockElement","containsBlockDescendants","parseContainerWithMarks","marksFromElement","parseInlineNode","headingMatch","level","blockType","ensureSegments","parseInlineChildren","parseBlockWithLineBreaks","parseBlockquote","parseList","parseListItem","parsePreContent","parseTableAsParagraphs","blockMatch","matchBlockRule","hasCheckbox","resolvedListType","isCheckboxChecked","inlineSegments","nestedLists","normalizeSegments","nestedType","parentMarks","resolveMarks","childMarks","mergeMarks","upperTag","fw","fontWeight","numeric","parseInt","isNaN","href","additional","rawMarks","isMarkAllowed","isNodeTypeAllowed","segment","inheritedMarks","innerBlocks","prependMarks","FONT_SIZE_MAP","hasFontSizeInStyle","moveChildren","unwrap","parentNode","sanitizeAttrs","specAttrs","hasKeys","raw","PasteHandler","handlePaste","onPaste","blockJson","getData","handleBlockPaste","handleFilePaste","handleRichPaste","richJson","extractRichData","handleRichPasteFromJson","preTemplate","fonts","font","color","face","span","styles","mapped","setStyleText","replaceChild","normalizedHTML","sanitized","schemaFromRegistry","parser","totalLength","insertText","addDeleteSelectionSteps","insertBlockId","insertOffset","resolveInsertPoint","setBlockType","blockIdx","firstSlice","lastSlice","middleSlices","firstLen","splitOffset","tailBlockId","splitBlock","mid","lastLen","parse","extractTextFromHTML","parsed","typeName","anchorBlockId","cellId","findTableCellAncestor","cellPath","isArray","insertRichBlocksIntoCell","insertRichBlocksAtRoot","anchorBlock","anchorIndex","isAnchorEmpty","validateRichBlockData","removeNode","files","file","getAsFile","handled","matchFileHandlers","Promise","richEl","reconcile","oldBlocks","newBlocks","compositionBlockId","wrappers","oldBlockMap","HTMLElement","wrappedChild","toBlockId","newBlockIds","removeBlockElement","nv","oldBlockById","previousSibling","selectedNodeId","previousSelectedNodeId","existingEl","oldBlock","oldDecos","oldDecorations","find","newDecos","blockChanged","existingNv","update","contentDOM","updatedInlineDecos","findInline","renderBlockContent","dom","newEl","renderBlock","replaceBlockElement","insertAfterPreviousSibling","selectNode","deselectNode","wrapBlocks","oldAttrs","newAttrs","oldKeys","newKeys","oldChild","newChild","inlineAttrsEqual","oldArr","newArr","decorationArraysEqual","inlineDecos","getNodeViewFactory","nvSpec","isVoid","selectable","contentDOMChildren","getContentDOM","childEl","applyNodeDecorations","p","globalOffset","renderInlineNode","textFrom","textTo","splitSet","deco","dFrom","dTo","splits","localFrom","localTo","activeDecos","preserveSpaces","j","createDecorationElement","renderTextNode","lastChild","aKeys","bKeys","nodeName","class","entries","nodeDecos","appendStyleText","currentSpec","currentIds","nodeSpec","wSpec","blockIds","firstEl","parentElement","oldEl","nextSibling","EditorView","contentElement","inputHandler","keyboardHandler","pasteHandler","clipboardHandler","history","stateChangeCallbacks","handleSelectionChange","handleMousedown","handleDragover","handleDrop","handleCompositionStartForWrapper","handleCompositionEndForWrapper","isUpdating","pendingNodeSelectionClear","pendingGapCursorClear","getDecorations","navigationKeymap","cursorWrapper","goalColumn","preserveGoalColumn","maxHistoryDepth","syncSelectionFromDOM","onSelectionChange","onMousedown","onDragover","onDrop","reconcileOptions","syncSelectionToDOM","registerNavigationKeymaps","isActive","pushHistory","newDecorations","activeBlockId","cb","applyUpdate","readSelectionFromDOM","setStoredMarks","nearestBlockEl","contains","handleClickBelowContent","buildBlockPath","lastBlockEl","lastRect","getBoundingClientRect","clientY","bottom","lastBlock","leafBlockEl","unshift","dataTransfer","position","getPositionFromPoint","clientX","x","y","domPoint","domPositionFromPoint","domPositionToState","activeEl","activeElement","oldSelection","directions","ArrowLeft","ArrowRight","ArrowUp","ArrowDown","dir","handleNavigationArrow","direction","handleHorizontalArrow","handleVerticalArrow","logicalDirection","resolveLogicalHorizontalDirection","inlineSkipTr","skipInlineNode","validateSelectionAfterInlineSkip","endOfTextblock","navigateAcrossBlocks","visual","blockEl","getTextDirection","ownerDocument","caretRect","getCaretRectFromSelection","left","navigateVerticalWithGoalColumn","EDITOR_CSS","cachedStyleSheet","EditorThemeController","themeStyleSheet","systemThemeQuery","systemThemeHandler","pluginSheets","runtimeSheets","cleanupSystemThemeListener","setupSystemThemeListener","resolved","getSystemTheme","setThemeStyleSheet","sheets","refreshAdoptedStyleSheets","window","matchMedia","matches","PaperLayoutController","viewport","surface","viewportObserver","surfaceObserver","currentSize","currentPaperWidthPx","currentPaperHeightPx","currentScale","compensationFrameId","disable","enable","updateSurfaceDimensions","getPaperSize","bottomContainer","ResizeObserver","onViewportResize","contentRect","width","observe","onSurfaceResize","height","cancelAnimationFrame","disconnect","setStyleProperty","viewportWidth","availableWidth","scale","scheduleHeightCompensation","_height","requestAnimationFrame","updateHeightCompensation","surfaceHeight","scrollHeight","compensation","NotectlEditor","view","pluginManager","editorWrapper","topPluginContainer","bottomPluginContainer","announcer","eventListeners","readyPromiseResolve","readyPromise","preInitPlugins","themeController","paperLayout","runtimeStyleSheet","constructor","super","resolve","attachShadow","mode","observedAttributes","disconnectedCallback","setTimeout","isConnected","_oldValue","newValue","isReadonly","contentEditable","setReadOnly","configure","setupStyleRuntime","placeholder","localeService","LocaleService","LocaleServiceKey","processToolbarConfig","register","ensureTextFormattingPlugin","ensureCaretNavigationPlugin","ensureGapCursorPlugin","contentEl","pluginMgr","topContainer","create","collectDecorations","updateEmptyState","getPluginStyleSheets","setPluginStyleSheets","onEvent","event","autofocus","getJSON","replaceState","cssMode","pretty","formatHTML","setJSON","toggleBold","toggleItalic","toggleUnderline","can","canExecuteCommand","configurePlugin","isReadonlyBypassed","dispatchWithMiddleware","finalTr","whenReady","applyPaperSize","teardownStyleRuntime","pluginTeardown","toolbarCfg","isShorthand","pluginGroups","overflow","pluginIds","layoutConfig","ToolbarPlugin","features","bold","italic","underline","TextFormattingPlugin","CaretNavigationPlugin","GapCursorPlugin","unregisterStyleRoot","createRuntimeStyleSheet","setRuntimeStyleSheets","registerStyleRoot","styleNonce","notifyStateChange","announcement","buildAnnouncement","toggle","async","createEditor","editor","createMinimalPreset","FontPlugin","STARTER_FONTS","createFullPreset","FontSizePlugin","fontSize","textFormatting","StrikethroughPlugin","strikethrough","SuperSubPlugin","superSub","TextColorPlugin","textColor","HighlightPlugin","highlight","HeadingPlugin","heading","BlockquotePlugin","blockquote","CodeBlockPlugin","AlignmentPlugin","ListPlugin","list","LinkPlugin","link","TablePlugin","table","HorizontalRulePlugin","horizontalRule","ImagePlugin","image","HardBreakPlugin","customElements","define"],"mappings":"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"}