@notectl/core 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -148
- package/dist/chunks/AttrRegistry-DTsHyDVA.mjs +16 -0
- package/dist/chunks/AttrRegistry-DTsHyDVA.mjs.map +1 -0
- package/dist/chunks/Commands-DLP85Mp5.mjs +461 -0
- package/dist/chunks/Commands-DLP85Mp5.mjs.map +1 -0
- package/dist/chunks/Document-CI3iCwEP.mjs +177 -0
- package/dist/chunks/Document-CI3iCwEP.mjs.map +1 -0
- package/dist/chunks/HTMLUtils-0wvCRvJc.mjs +7 -0
- package/dist/chunks/HTMLUtils-0wvCRvJc.mjs.map +1 -0
- package/dist/chunks/NodeResolver-D68ZLXti.mjs +81 -0
- package/dist/chunks/NodeResolver-D68ZLXti.mjs.map +1 -0
- package/dist/chunks/NodeSpec-NZVvcCuH.mjs +8 -0
- package/dist/chunks/NodeSpec-NZVvcCuH.mjs.map +1 -0
- package/dist/chunks/Plugin-B9OZ6Y4c.mjs +15 -0
- package/dist/chunks/Plugin-B9OZ6Y4c.mjs.map +1 -0
- package/dist/chunks/Selection-D5ZjXoB7.mjs +44 -0
- package/dist/chunks/Selection-D5ZjXoB7.mjs.map +1 -0
- package/dist/chunks/ToolbarItem-ugDymuXi.mjs +7 -0
- package/dist/chunks/ToolbarItem-ugDymuXi.mjs.map +1 -0
- package/dist/chunks/ToolbarPlugin-D5VqeBPT.mjs +398 -0
- package/dist/chunks/ToolbarPlugin-D5VqeBPT.mjs.map +1 -0
- package/dist/chunks/TypeBrands-C09nE2qO.mjs +27 -0
- package/dist/chunks/TypeBrands-C09nE2qO.mjs.map +1 -0
- package/dist/chunks/color-picker-Csf0wx5a.mjs +5 -0
- package/dist/chunks/color-picker-Csf0wx5a.mjs.map +1 -0
- package/dist/chunks/index-CPPb-Jah.mjs +569 -0
- package/dist/chunks/index-CPPb-Jah.mjs.map +1 -0
- package/dist/commands/Commands.d.ts +71 -0
- package/dist/commands/Commands.d.ts.map +1 -0
- package/dist/commands/PasteCommand.d.ts +9 -0
- package/dist/commands/PasteCommand.d.ts.map +1 -0
- package/dist/decorations/Decoration.d.ts +76 -0
- package/dist/decorations/Decoration.d.ts.map +1 -0
- package/dist/decorations/PositionMapping.d.ts +9 -0
- package/dist/decorations/PositionMapping.d.ts.map +1 -0
- package/dist/editor/Announcer.d.ts +12 -0
- package/dist/editor/Announcer.d.ts.map +1 -0
- package/dist/editor/DocumentParser.d.ts +5 -0
- package/dist/editor/DocumentParser.d.ts.map +1 -0
- package/dist/editor/DocumentSerializer.d.ts +5 -0
- package/dist/editor/DocumentSerializer.d.ts.map +1 -0
- package/dist/editor/EditorDOM.d.ts +18 -0
- package/dist/editor/EditorDOM.d.ts.map +1 -0
- package/dist/editor/EditorThemeController.d.ts +21 -0
- package/dist/editor/EditorThemeController.d.ts.map +1 -0
- package/dist/editor/NotectlEditor.d.ts +131 -0
- package/dist/editor/NotectlEditor.d.ts.map +1 -0
- package/dist/editor/styles/base.d.ts +3 -0
- package/dist/editor/styles/base.d.ts.map +1 -0
- package/dist/editor/styles/code-block.d.ts +3 -0
- package/dist/editor/styles/code-block.d.ts.map +1 -0
- package/dist/editor/styles/color-picker.d.ts +3 -0
- package/dist/editor/styles/color-picker.d.ts.map +1 -0
- package/dist/editor/styles/font-select.d.ts +3 -0
- package/dist/editor/styles/font-select.d.ts.map +1 -0
- package/dist/editor/styles/font-size-select.d.ts +3 -0
- package/dist/editor/styles/font-size-select.d.ts.map +1 -0
- package/dist/editor/styles/heading-select.d.ts +3 -0
- package/dist/editor/styles/heading-select.d.ts.map +1 -0
- package/dist/editor/styles/image.d.ts +3 -0
- package/dist/editor/styles/image.d.ts.map +1 -0
- package/dist/editor/styles/list.d.ts +3 -0
- package/dist/editor/styles/list.d.ts.map +1 -0
- package/dist/editor/styles/reduced-motion.d.ts +3 -0
- package/dist/editor/styles/reduced-motion.d.ts.map +1 -0
- package/dist/editor/styles/table.d.ts +3 -0
- package/dist/editor/styles/table.d.ts.map +1 -0
- package/dist/editor/styles/toolbar.d.ts +3 -0
- package/dist/editor/styles/toolbar.d.ts.map +1 -0
- package/dist/editor/styles.d.ts +12 -0
- package/dist/editor/styles.d.ts.map +1 -0
- package/dist/editor/theme/ThemeEngine.d.ts +6 -0
- package/dist/editor/theme/ThemeEngine.d.ts.map +1 -0
- package/dist/editor/theme/ThemeTokens.d.ts +73 -0
- package/dist/editor/theme/ThemeTokens.d.ts.map +1 -0
- package/dist/fonts.d.ts +17 -0
- package/dist/fonts.d.ts.map +1 -0
- package/dist/fonts.mjs +7 -0
- package/dist/fonts.mjs.map +1 -0
- package/dist/index.d.ts +81 -2360
- package/dist/index.d.ts.map +1 -0
- package/dist/input/ClipboardHandler.d.ts +29 -0
- package/dist/input/ClipboardHandler.d.ts.map +1 -0
- package/dist/input/InputHandler.d.ts +32 -0
- package/dist/input/InputHandler.d.ts.map +1 -0
- package/dist/input/InputRule.d.ts +9 -0
- package/dist/input/InputRule.d.ts.map +1 -0
- package/dist/input/InternalClipboard.d.ts +23 -0
- package/dist/input/InternalClipboard.d.ts.map +1 -0
- package/dist/input/KeyboardHandler.d.ts +42 -0
- package/dist/input/KeyboardHandler.d.ts.map +1 -0
- package/dist/input/Keymap.d.ts +11 -0
- package/dist/input/Keymap.d.ts.map +1 -0
- package/dist/input/PasteHandler.d.ts +38 -0
- package/dist/input/PasteHandler.d.ts.map +1 -0
- package/dist/input/SourceNormalizer.d.ts +7 -0
- package/dist/input/SourceNormalizer.d.ts.map +1 -0
- package/dist/model/AttrRegistry.d.ts +39 -0
- package/dist/model/AttrRegistry.d.ts.map +1 -0
- package/dist/model/BuiltinSpecs.d.ts +4 -0
- package/dist/model/BuiltinSpecs.d.ts.map +1 -0
- package/dist/model/ContentModel.d.ts +12 -0
- package/dist/model/ContentModel.d.ts.map +1 -0
- package/dist/model/ContentSlice.d.ts +17 -0
- package/dist/model/ContentSlice.d.ts.map +1 -0
- package/dist/model/Document.d.ts +127 -0
- package/dist/model/Document.d.ts.map +1 -0
- package/dist/model/HTMLParser.d.ts +36 -0
- package/dist/model/HTMLParser.d.ts.map +1 -0
- package/dist/model/HTMLUtils.d.ts +6 -0
- package/dist/model/HTMLUtils.d.ts.map +1 -0
- package/dist/model/InlineNodeSpec.d.ts +20 -0
- package/dist/model/InlineNodeSpec.d.ts.map +1 -0
- package/dist/model/MarkSpec.d.ts +22 -0
- package/dist/model/MarkSpec.d.ts.map +1 -0
- package/dist/model/NodeResolver.d.ts +36 -0
- package/dist/model/NodeResolver.d.ts.map +1 -0
- package/dist/model/NodeSpec.d.ts +67 -0
- package/dist/model/NodeSpec.d.ts.map +1 -0
- package/dist/model/ParseRule.d.ts +11 -0
- package/dist/model/ParseRule.d.ts.map +1 -0
- package/dist/model/SanitizeConfig.d.ts +9 -0
- package/dist/model/SanitizeConfig.d.ts.map +1 -0
- package/dist/model/Schema.d.ts +17 -0
- package/dist/model/Schema.d.ts.map +1 -0
- package/dist/model/SchemaRegistry.d.ts +81 -0
- package/dist/model/SchemaRegistry.d.ts.map +1 -0
- package/dist/model/Selection.d.ts +52 -0
- package/dist/model/Selection.d.ts.map +1 -0
- package/dist/model/TypeBrands.d.ts +28 -0
- package/dist/model/TypeBrands.d.ts.map +1 -0
- package/dist/notectl-core.mjs +2576 -11104
- package/dist/notectl-core.mjs.map +1 -1
- package/dist/notectl-core.umd.js +6810 -0
- package/dist/notectl-core.umd.js.map +1 -0
- package/dist/plugins/EventBus.d.ts +13 -0
- package/dist/plugins/EventBus.d.ts.map +1 -0
- package/dist/plugins/Plugin.d.ts +85 -0
- package/dist/plugins/Plugin.d.ts.map +1 -0
- package/dist/plugins/PluginManager.d.ts +66 -0
- package/dist/plugins/PluginManager.d.ts.map +1 -0
- package/dist/plugins/alignment/AlignmentPlugin.d.ts +48 -0
- package/dist/plugins/alignment/AlignmentPlugin.d.ts.map +1 -0
- package/dist/plugins/alignment/index.d.ts +2 -0
- package/dist/plugins/alignment/index.d.ts.map +1 -0
- package/dist/plugins/alignment.mjs +92 -0
- package/dist/plugins/alignment.mjs.map +1 -0
- package/dist/plugins/blockquote/BlockquotePlugin.d.ts +30 -0
- package/dist/plugins/blockquote/BlockquotePlugin.d.ts.map +1 -0
- package/dist/plugins/blockquote/index.d.ts +2 -0
- package/dist/plugins/blockquote/index.d.ts.map +1 -0
- package/dist/plugins/blockquote.mjs +58 -0
- package/dist/plugins/blockquote.mjs.map +1 -0
- package/dist/plugins/code-block/CodeBlockNodeView.d.ts +5 -0
- package/dist/plugins/code-block/CodeBlockNodeView.d.ts.map +1 -0
- package/dist/plugins/code-block/CodeBlockPlugin.d.ts +135 -0
- package/dist/plugins/code-block/CodeBlockPlugin.d.ts.map +1 -0
- package/dist/plugins/code-block/index.d.ts +2 -0
- package/dist/plugins/code-block/index.d.ts.map +1 -0
- package/dist/plugins/code-block.mjs +6 -0
- package/dist/plugins/code-block.mjs.map +1 -0
- package/dist/plugins/font/FontPlugin.d.ts +85 -0
- package/dist/plugins/font/FontPlugin.d.ts.map +1 -0
- package/dist/plugins/font/StarterFonts.d.ts +10 -0
- package/dist/plugins/font/StarterFonts.d.ts.map +1 -0
- package/dist/plugins/font/index.d.ts +2 -0
- package/dist/plugins/font/index.d.ts.map +1 -0
- package/dist/plugins/font-size/FontSizePlugin.d.ts +65 -0
- package/dist/plugins/font-size/FontSizePlugin.d.ts.map +1 -0
- package/dist/plugins/font-size/index.d.ts +2 -0
- package/dist/plugins/font-size/index.d.ts.map +1 -0
- package/dist/plugins/font-size.mjs +220 -0
- package/dist/plugins/font-size.mjs.map +1 -0
- package/dist/plugins/font.mjs +186 -0
- package/dist/plugins/font.mjs.map +1 -0
- package/dist/plugins/hard-break/HardBreakPlugin.d.ts +16 -0
- package/dist/plugins/hard-break/HardBreakPlugin.d.ts.map +1 -0
- package/dist/plugins/hard-break/index.d.ts +2 -0
- package/dist/plugins/hard-break/index.d.ts.map +1 -0
- package/dist/plugins/hard-break.mjs +28 -0
- package/dist/plugins/hard-break.mjs.map +1 -0
- package/dist/plugins/heading/BlockTypePickerEntry.d.ts +20 -0
- package/dist/plugins/heading/BlockTypePickerEntry.d.ts.map +1 -0
- package/dist/plugins/heading/HeadingPlugin.d.ts +78 -0
- package/dist/plugins/heading/HeadingPlugin.d.ts.map +1 -0
- package/dist/plugins/heading/index.d.ts +3 -0
- package/dist/plugins/heading/index.d.ts.map +1 -0
- package/dist/plugins/heading.mjs +188 -0
- package/dist/plugins/heading.mjs.map +1 -0
- package/dist/plugins/highlight/HighlightPlugin.d.ts +37 -0
- package/dist/plugins/highlight/HighlightPlugin.d.ts.map +1 -0
- package/dist/plugins/highlight/index.d.ts +2 -0
- package/dist/plugins/highlight/index.d.ts.map +1 -0
- package/dist/plugins/highlight.mjs +126 -0
- package/dist/plugins/highlight.mjs.map +1 -0
- package/dist/plugins/horizontal-rule/HorizontalRulePlugin.d.ts +29 -0
- package/dist/plugins/horizontal-rule/HorizontalRulePlugin.d.ts.map +1 -0
- package/dist/plugins/horizontal-rule/index.d.ts +2 -0
- package/dist/plugins/horizontal-rule/index.d.ts.map +1 -0
- package/dist/plugins/horizontal-rule.mjs +59 -0
- package/dist/plugins/horizontal-rule.mjs.map +1 -0
- package/dist/plugins/image/ImageCommands.d.ts +26 -0
- package/dist/plugins/image/ImageCommands.d.ts.map +1 -0
- package/dist/plugins/image/ImageNodeView.d.ts +6 -0
- package/dist/plugins/image/ImageNodeView.d.ts.map +1 -0
- package/dist/plugins/image/ImagePlugin.d.ts +43 -0
- package/dist/plugins/image/ImagePlugin.d.ts.map +1 -0
- package/dist/plugins/image/ImageUpload.d.ts +48 -0
- package/dist/plugins/image/ImageUpload.d.ts.map +1 -0
- package/dist/plugins/image/index.d.ts +3 -0
- package/dist/plugins/image/index.d.ts.map +1 -0
- package/dist/plugins/image.mjs +381 -0
- package/dist/plugins/image.mjs.map +1 -0
- package/dist/plugins/link/LinkPlugin.d.ts +32 -0
- package/dist/plugins/link/LinkPlugin.d.ts.map +1 -0
- package/dist/plugins/link/index.d.ts +2 -0
- package/dist/plugins/link/index.d.ts.map +1 -0
- package/dist/plugins/link.mjs +127 -0
- package/dist/plugins/link.mjs.map +1 -0
- package/dist/plugins/list/ListPlugin.d.ts +51 -0
- package/dist/plugins/list/ListPlugin.d.ts.map +1 -0
- package/dist/plugins/list/index.d.ts +2 -0
- package/dist/plugins/list/index.d.ts.map +1 -0
- package/dist/plugins/list.mjs +193 -0
- package/dist/plugins/list.mjs.map +1 -0
- package/dist/plugins/strikethrough/StrikethroughPlugin.d.ts +23 -0
- package/dist/plugins/strikethrough/StrikethroughPlugin.d.ts.map +1 -0
- package/dist/plugins/strikethrough/index.d.ts +2 -0
- package/dist/plugins/strikethrough/index.d.ts.map +1 -0
- package/dist/plugins/strikethrough.mjs +35 -0
- package/dist/plugins/strikethrough.mjs.map +1 -0
- package/dist/plugins/super-sub/SuperSubPlugin.d.ts +44 -0
- package/dist/plugins/super-sub/SuperSubPlugin.d.ts.map +1 -0
- package/dist/plugins/super-sub/index.d.ts +2 -0
- package/dist/plugins/super-sub/index.d.ts.map +1 -0
- package/dist/plugins/super-sub.mjs +81 -0
- package/dist/plugins/super-sub.mjs.map +1 -0
- package/dist/plugins/table/TableCommands.d.ts +50 -0
- package/dist/plugins/table/TableCommands.d.ts.map +1 -0
- package/dist/plugins/table/TableControls.d.ts +10 -0
- package/dist/plugins/table/TableControls.d.ts.map +1 -0
- package/dist/plugins/table/TableControlsDOM.d.ts +18 -0
- package/dist/plugins/table/TableControlsDOM.d.ts.map +1 -0
- package/dist/plugins/table/TableControlsLayout.d.ts +34 -0
- package/dist/plugins/table/TableControlsLayout.d.ts.map +1 -0
- package/dist/plugins/table/TableHelpers.d.ts +39 -0
- package/dist/plugins/table/TableHelpers.d.ts.map +1 -0
- package/dist/plugins/table/TableNavigation.d.ts +4 -0
- package/dist/plugins/table/TableNavigation.d.ts.map +1 -0
- package/dist/plugins/table/TableNodeViews.d.ts +18 -0
- package/dist/plugins/table/TableNodeViews.d.ts.map +1 -0
- package/dist/plugins/table/TablePlugin.d.ts +39 -0
- package/dist/plugins/table/TablePlugin.d.ts.map +1 -0
- package/dist/plugins/table/TableSelection.d.ts +26 -0
- package/dist/plugins/table/TableSelection.d.ts.map +1 -0
- package/dist/plugins/table/TableTestUtils.d.ts +45 -0
- package/dist/plugins/table/TableTestUtils.d.ts.map +1 -0
- package/dist/plugins/table/index.d.ts +4 -0
- package/dist/plugins/table/index.d.ts.map +1 -0
- package/dist/plugins/table.mjs +663 -0
- package/dist/plugins/table.mjs.map +1 -0
- package/dist/plugins/text-color/TextColorPlugin.d.ts +37 -0
- package/dist/plugins/text-color/TextColorPlugin.d.ts.map +1 -0
- package/dist/plugins/text-color/index.d.ts +2 -0
- package/dist/plugins/text-color/index.d.ts.map +1 -0
- package/dist/plugins/text-color.mjs +126 -0
- package/dist/plugins/text-color.mjs.map +1 -0
- package/dist/plugins/text-formatting/TextFormattingPlugin.d.ts +34 -0
- package/dist/plugins/text-formatting/TextFormattingPlugin.d.ts.map +1 -0
- package/dist/plugins/text-formatting/index.d.ts +2 -0
- package/dist/plugins/text-formatting/index.d.ts.map +1 -0
- package/dist/plugins/text-formatting.mjs +52 -0
- package/dist/plugins/text-formatting.mjs.map +1 -0
- package/dist/plugins/toolbar/ToolbarItem.d.ts +66 -0
- package/dist/plugins/toolbar/ToolbarItem.d.ts.map +1 -0
- package/dist/plugins/toolbar/ToolbarKeyboardNav.d.ts +25 -0
- package/dist/plugins/toolbar/ToolbarKeyboardNav.d.ts.map +1 -0
- package/dist/plugins/toolbar/ToolbarPlugin.d.ts +47 -0
- package/dist/plugins/toolbar/ToolbarPlugin.d.ts.map +1 -0
- package/dist/plugins/toolbar/ToolbarPopupController.d.ts +25 -0
- package/dist/plugins/toolbar/ToolbarPopupController.d.ts.map +1 -0
- package/dist/plugins/toolbar/ToolbarRenderers.d.ts +19 -0
- package/dist/plugins/toolbar/ToolbarRenderers.d.ts.map +1 -0
- package/dist/plugins/toolbar/ToolbarTooltip.d.ts +17 -0
- package/dist/plugins/toolbar/ToolbarTooltip.d.ts.map +1 -0
- package/dist/plugins/toolbar/index.d.ts +4 -0
- package/dist/plugins/toolbar/index.d.ts.map +1 -0
- package/dist/plugins/toolbar.mjs +8 -0
- package/dist/plugins/toolbar.mjs.map +1 -0
- package/dist/state/EditorState.d.ts +40 -0
- package/dist/state/EditorState.d.ts.map +1 -0
- package/dist/state/History.d.ts +38 -0
- package/dist/state/History.d.ts.map +1 -0
- package/dist/state/StepApplication.d.ts +5 -0
- package/dist/state/StepApplication.d.ts.map +1 -0
- package/dist/state/Transaction.d.ts +185 -0
- package/dist/state/Transaction.d.ts.map +1 -0
- package/dist/test/PluginTestUtils.d.ts +127 -0
- package/dist/test/PluginTestUtils.d.ts.map +1 -0
- package/dist/test/TestUtils.d.ts +153 -0
- package/dist/test/TestUtils.d.ts.map +1 -0
- package/dist/view/EditorView.d.ts +74 -0
- package/dist/view/EditorView.d.ts.map +1 -0
- package/dist/view/NodeView.d.ts +18 -0
- package/dist/view/NodeView.d.ts.map +1 -0
- package/dist/view/Reconciler.d.ts +23 -0
- package/dist/view/Reconciler.d.ts.map +1 -0
- package/dist/view/SelectionSync.d.ts +8 -0
- package/dist/view/SelectionSync.d.ts.map +1 -0
- package/package.json +112 -11
- package/dist/notectl-core.js +0 -1463
- package/dist/notectl-core.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notectl-core.mjs","sources":["../src/model/Document.ts","../src/model/Selection.ts","../src/model/Schema.ts","../src/model/TypeBrands.ts","../src/model/AttrRegistry.ts","../src/model/NodeSpec.ts","../src/model/HTMLUtils.ts","../src/model/SchemaRegistry.ts","../src/model/NodeResolver.ts","../src/model/ContentModel.ts","../src/model/BuiltinSpecs.ts","../src/state/StepApplication.ts","../src/state/Transaction.ts","../src/state/EditorState.ts","../src/state/History.ts","../src/commands/Commands.ts","../src/input/KeyboardHandler.ts","../src/input/InternalClipboard.ts","../src/input/ClipboardHandler.ts","../src/plugins/Plugin.ts","../src/plugins/EventBus.ts","../src/decorations/PositionMapping.ts","../src/decorations/Decoration.ts","../src/plugins/PluginManager.ts","../src/plugins/toolbar/ToolbarKeyboardNav.ts","../src/plugins/toolbar/ToolbarRenderers.ts","../src/plugins/toolbar/ToolbarPopupController.ts","../src/plugins/toolbar/ToolbarTooltip.ts","../src/plugins/toolbar/ToolbarPlugin.ts","../src/plugins/toolbar/ToolbarItem.ts","../src/plugins/text-formatting/TextFormattingPlugin.ts","../src/plugins/heading/HeadingPlugin.ts","../src/plugins/link/LinkPlugin.ts","../src/plugins/list/ListPlugin.ts","../src/plugins/blockquote/BlockquotePlugin.ts","../src/plugins/strikethrough/StrikethroughPlugin.ts","../src/plugins/text-color/TextColorPlugin.ts","../src/plugins/horizontal-rule/HorizontalRulePlugin.ts","../src/plugins/alignment/AlignmentPlugin.ts","../src/plugins/font/FontPlugin.ts","../src/plugins/font-size/FontSizePlugin.ts","../src/plugins/font/StarterFonts.ts","../src/plugins/table/TableHelpers.ts","../src/plugins/table/TableCommands.ts","../src/plugins/table/TableNavigation.ts","../src/plugins/table/TableControls.ts","../src/plugins/table/TableNodeViews.ts","../src/plugins/table/TableSelection.ts","../src/plugins/table/TablePlugin.ts","../src/plugins/highlight/HighlightPlugin.ts","../src/plugins/super-sub/SuperSubPlugin.ts","../src/plugins/image/ImageCommands.ts","../src/plugins/image/ImageNodeView.ts","../src/plugins/image/ImageUpload.ts","../src/plugins/image/ImagePlugin.ts","../src/plugins/hard-break/HardBreakPlugin.ts","../src/plugins/code-block/CodeBlockNodeView.ts","../src/plugins/code-block/CodeBlockPlugin.ts","../src/editor/theme/ThemeTokens.ts","../src/editor/theme/ThemeEngine.ts","../src/input/InputHandler.ts","../src/model/ContentSlice.ts","../src/commands/PasteCommand.ts","../src/model/HTMLParser.ts","../src/input/PasteHandler.ts","../src/view/Reconciler.ts","../src/view/SelectionSync.ts","../src/view/EditorView.ts","../src/editor/styles.ts","../src/editor/NotectlEditor.ts"],"sourcesContent":["/**\n * Core document model types for the Notectl editor.\n * All types are deeply readonly — mutations create new instances.\n */\n\nimport type { BlockId, InlineTypeName, MarkTypeName, NodeTypeName } from './TypeBrands.js';\n\n// --- Mark Types ---\n\n/** @deprecated Use {@link MarkTypeName} for new code. */\nexport type MarkType = MarkTypeName;\n\nexport interface Mark {\n\treadonly type: MarkTypeName;\n\treadonly attrs?: Readonly<Record<string, string | number | boolean>>;\n}\n\nexport interface BoldMark extends Mark {\n\treadonly type: MarkTypeName & 'bold';\n}\n\nexport interface ItalicMark extends Mark {\n\treadonly type: MarkTypeName & 'italic';\n}\n\nexport interface UnderlineMark extends Mark {\n\treadonly type: MarkTypeName & 'underline';\n}\n\n// --- Node Types ---\n\n/** @deprecated Use {@link NodeTypeName} for new code. */\nexport type NodeType = NodeTypeName;\n\nexport interface BlockAttrs {\n\treadonly [key: string]: string | number | boolean;\n}\n\nexport interface TextNode {\n\treadonly type: 'text';\n\treadonly text: string;\n\treadonly marks: readonly Mark[];\n}\n\n/** Atomic inline element (width 1 in offset space). */\nexport interface InlineNode {\n\treadonly type: 'inline';\n\treadonly inlineType: InlineTypeName;\n\treadonly attrs: Readonly<Record<string, string | number | boolean>>;\n}\n\n/** A child of a BlockNode: text, inline element, or nested block. */\nexport type ChildNode = TextNode | InlineNode | BlockNode;\n\nexport interface BlockNode {\n\treadonly id: BlockId;\n\treadonly type: NodeTypeName;\n\treadonly attrs?: BlockAttrs;\n\treadonly children: readonly ChildNode[];\n}\n\nexport interface Document {\n\treadonly children: readonly BlockNode[];\n}\n\n// --- Text Segment (for mark-preserving undo) ---\n\nexport interface TextSegment {\n\treadonly text: string;\n\treadonly marks: readonly Mark[];\n}\n\n/** A content segment: either text (with marks) or an inline node. */\nexport type ContentSegment =\n\t| { readonly kind: 'text'; readonly text: string; readonly marks: readonly Mark[] }\n\t| { readonly kind: 'inline'; readonly node: InlineNode };\n\n/** Extracts TextNode segments within a block for the given offset range. */\nexport function getBlockSegmentsInRange(\n\tblock: BlockNode,\n\tfrom: number,\n\tto: number,\n): readonly TextSegment[] {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tconst segments: TextSegment[] = [];\n\tlet pos = 0;\n\n\tfor (const child of inlineChildren) {\n\t\tconst childWidth: number = isInlineNode(child) ? 1 : child.text.length;\n\t\tconst childEnd: number = pos + childWidth;\n\n\t\tif (childEnd <= from || pos >= to) {\n\t\t\tpos = childEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isInlineNode(child)) {\n\t\t\t// InlineNodes are skipped for TextSegment extraction\n\t\t\tpos = childEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst sliceFrom: number = Math.max(0, from - pos);\n\t\tconst sliceTo: number = Math.min(child.text.length, to - pos);\n\t\tconst text: string = child.text.slice(sliceFrom, sliceTo);\n\n\t\tif (text.length > 0) {\n\t\t\tsegments.push({ text, marks: child.marks });\n\t\t}\n\n\t\tpos = childEnd;\n\t}\n\n\treturn segments;\n}\n\n/** Returns content segments (text and inline) for a block range. */\nexport function getBlockContentSegmentsInRange(\n\tblock: BlockNode,\n\tfrom: number,\n\tto: number,\n): readonly ContentSegment[] {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tconst segments: ContentSegment[] = [];\n\tlet pos = 0;\n\n\tfor (const child of inlineChildren) {\n\t\tconst childWidth: number = isInlineNode(child) ? 1 : child.text.length;\n\t\tconst childEnd: number = pos + childWidth;\n\n\t\tif (childEnd <= from || pos >= to) {\n\t\t\tpos = childEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isInlineNode(child)) {\n\t\t\tsegments.push({ kind: 'inline', node: child });\n\t\t} else {\n\t\t\tconst sliceFrom: number = Math.max(0, from - pos);\n\t\t\tconst sliceTo: number = Math.min(child.text.length, to - pos);\n\t\t\tconst text: string = child.text.slice(sliceFrom, sliceTo);\n\t\t\tif (text.length > 0) {\n\t\t\t\tsegments.push({ kind: 'text', text, marks: child.marks });\n\t\t\t}\n\t\t}\n\n\t\tpos = childEnd;\n\t}\n\n\treturn segments;\n}\n\n// --- Type Guards ---\n\n/** Checks whether a value is a {@link TextNode}. */\nexport function isTextNode(node: unknown): node is TextNode {\n\treturn (\n\t\ttypeof node === 'object' &&\n\t\tnode !== null &&\n\t\t(node as TextNode).type === 'text' &&\n\t\ttypeof (node as TextNode).text === 'string'\n\t);\n}\n\n/** Checks whether a value is an {@link InlineNode}. */\nexport function isInlineNode(node: unknown): node is InlineNode {\n\treturn (\n\t\ttypeof node === 'object' &&\n\t\tnode !== null &&\n\t\t(node as InlineNode).type === 'inline' &&\n\t\ttypeof (node as InlineNode).inlineType === 'string'\n\t);\n}\n\n/** Checks whether a value is a {@link BlockNode}. */\nexport function isBlockNode(node: unknown): node is BlockNode {\n\treturn (\n\t\ttypeof node === 'object' &&\n\t\tnode !== null &&\n\t\ttypeof (node as BlockNode).id === 'string' &&\n\t\ttypeof (node as BlockNode).type === 'string' &&\n\t\t(node as BlockNode).type !== ('text' as string) &&\n\t\t(node as BlockNode).type !== ('inline' as string) &&\n\t\tArray.isArray((node as BlockNode).children)\n\t);\n}\n\n// --- Child Node Helpers ---\n\n/** Returns true if a block has only inline content (TextNodes and InlineNodes). */\nexport function isLeafBlock(node: BlockNode): boolean {\n\treturn node.children.every((c) => isTextNode(c) || isInlineNode(c));\n}\n\n/** Returns only the TextNode children of a block. */\nexport function getTextChildren(node: BlockNode): readonly TextNode[] {\n\treturn node.children.filter((c): c is TextNode => isTextNode(c));\n}\n\n/** Returns the inline content children (TextNode | InlineNode) of a block. */\nexport function getInlineChildren(node: BlockNode): readonly (TextNode | InlineNode)[] {\n\treturn node.children.filter((c): c is TextNode | InlineNode => isTextNode(c) || isInlineNode(c));\n}\n\n/** Returns only the BlockNode children of a block. */\nexport function getBlockChildren(node: BlockNode): readonly BlockNode[] {\n\treturn node.children.filter((c): c is BlockNode => isBlockNode(c));\n}\n\n// --- Factory Functions ---\n\n/** Generates a unique block ID using crypto.randomUUID(). */\nexport function generateBlockId(): BlockId {\n\treturn `block-${crypto.randomUUID()}` as BlockId;\n}\n\n/** Creates a new empty {@link Document} with a single empty paragraph. */\nexport function createDocument(children?: readonly BlockNode[]): Document {\n\treturn {\n\t\tchildren: children ?? [createBlockNode('paragraph' as NodeTypeName)],\n\t};\n}\n\n/** Creates a new {@link BlockNode}. */\nexport function createBlockNode(\n\ttype: NodeTypeName,\n\tchildren?: readonly ChildNode[],\n\tid?: BlockId,\n\tattrs?: BlockAttrs,\n): BlockNode {\n\treturn {\n\t\tid: id ?? generateBlockId(),\n\t\ttype,\n\t\t...(attrs ? { attrs } : {}),\n\t\tchildren: children ?? [createTextNode('')],\n\t};\n}\n\n/** Creates a new {@link TextNode}. */\nexport function createTextNode(text: string, marks?: readonly Mark[]): TextNode {\n\treturn {\n\t\ttype: 'text',\n\t\ttext,\n\t\tmarks: marks ?? [],\n\t};\n}\n\n/** Creates a new {@link InlineNode}. */\nexport function createInlineNode(\n\tinlineType: InlineTypeName,\n\tattrs?: Readonly<Record<string, string | number | boolean>>,\n): InlineNode {\n\treturn {\n\t\ttype: 'inline',\n\t\tinlineType,\n\t\tattrs: attrs ?? {},\n\t};\n}\n\n// --- Utility Functions ---\n\n/** Extracts plain text from a block (InlineNodes are skipped). */\nexport function getBlockText(block: BlockNode): string {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet text = '';\n\tfor (const child of inlineChildren) {\n\t\tif (isTextNode(child)) {\n\t\t\ttext += child.text;\n\t\t}\n\t}\n\treturn text;\n}\n\n/** Returns the length of a block's inline content (InlineNodes count as 1). */\nexport function getBlockLength(block: BlockNode): number {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet len = 0;\n\tfor (const child of inlineChildren) {\n\t\tlen += isInlineNode(child) ? 1 : child.text.length;\n\t}\n\treturn len;\n}\n\n/** Returns the marks active at the given offset (empty for InlineNode offsets). */\nexport function getBlockMarksAtOffset(block: BlockNode, offset: number): readonly Mark[] {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet pos = 0;\n\n\tfor (const child of inlineChildren) {\n\t\tif (isInlineNode(child)) {\n\t\t\tif (offset === pos) return [];\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst end: number = pos + child.text.length;\n\t\tif (offset >= pos && offset < end) {\n\t\t\treturn child.marks;\n\t\t}\n\t\tif (offset === pos && child.text.length === 0) {\n\t\t\treturn child.marks;\n\t\t}\n\t\tpos = end;\n\t}\n\n\t// Fall back to last text child's marks\n\tfor (let i: number = inlineChildren.length - 1; i >= 0; i--) {\n\t\tconst child: TextNode | InlineNode | undefined = inlineChildren[i];\n\t\tif (child && isTextNode(child)) {\n\t\t\treturn child.marks;\n\t\t}\n\t}\n\treturn [];\n}\n\n/** Checks whether two marks are equal by type and attrs. */\nexport function marksEqual(a: Mark, b: Mark): boolean {\n\tif (a.type !== b.type) return false;\n\tconst aAttrs = a.attrs;\n\tconst bAttrs = b.attrs;\n\tif (!aAttrs && !bAttrs) return true;\n\tif (!aAttrs || !bAttrs) return false;\n\tconst aKeys = Object.keys(aAttrs);\n\tconst bKeys = Object.keys(bAttrs);\n\tif (aKeys.length !== bKeys.length) return false;\n\treturn aKeys.every((key) => aAttrs[key] === bAttrs[key]);\n}\n\n/** Checks whether two mark arrays contain the same marks (order-independent). */\nexport function markSetsEqual(a: readonly Mark[], b: readonly Mark[]): boolean {\n\tif (a.length !== b.length) return false;\n\treturn a.every((markA) => b.some((markB) => marksEqual(markA, markB)));\n}\n\n/** Returns true if the mark set contains a mark of the given type. */\nexport function hasMark(marks: readonly Mark[], markType: MarkTypeName): boolean {\n\treturn marks.some((m) => m.type === markType);\n}\n\n/** Adds a mark to a mark set (no duplicates). */\nexport function addMarkToSet(marks: readonly Mark[], mark: Mark): readonly Mark[] {\n\tif (hasMark(marks, mark.type)) return marks;\n\treturn [...marks, mark];\n}\n\n/** Removes a mark type from a mark set. */\nexport function removeMarkFromSet(marks: readonly Mark[], markType: MarkTypeName): readonly Mark[] {\n\treturn marks.filter((m) => m.type !== markType);\n}\n\n/**\n * Normalizes text nodes within a block: merges adjacent nodes with identical marks,\n * removes empty text nodes (keeping at least one).\n */\nexport function normalizeTextNodes(nodes: readonly TextNode[]): readonly TextNode[] {\n\tif (nodes.length === 0) return [createTextNode('')];\n\n\tconst result: TextNode[] = [];\n\tfor (const node of nodes) {\n\t\tconst prev: TextNode | undefined = result[result.length - 1];\n\t\tif (prev && markSetsEqual(prev.marks, node.marks)) {\n\t\t\tresult[result.length - 1] = createTextNode(prev.text + node.text, prev.marks);\n\t\t} else if (node.text.length > 0 || result.length === 0) {\n\t\t\tresult.push(node);\n\t\t}\n\t}\n\n\treturn result.length === 0 ? [createTextNode('')] : result;\n}\n\n/**\n * Normalizes mixed inline content: merges adjacent TextNodes with same marks,\n * removes empty TextNodes adjacent to InlineNodes, preserves InlineNodes as-is.\n * Guarantees at least one TextNode exists if all text is empty.\n */\nexport function normalizeInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n): readonly (TextNode | InlineNode)[] {\n\tif (nodes.length === 0) return [createTextNode('')];\n\n\t// Fast path: no InlineNodes, delegate to normalizeTextNodes\n\tif (nodes.every((n): n is TextNode => isTextNode(n))) {\n\t\treturn normalizeTextNodes(nodes);\n\t}\n\n\tconst result: (TextNode | InlineNode)[] = [];\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tresult.push(node);\n\t\t\tcontinue;\n\t\t}\n\t\t// TextNode: try to merge with previous TextNode\n\t\tconst prev: TextNode | InlineNode | undefined = result[result.length - 1];\n\t\tif (prev && isTextNode(prev) && markSetsEqual(prev.marks, node.marks)) {\n\t\t\tresult[result.length - 1] = createTextNode(prev.text + node.text, prev.marks);\n\t\t} else if (node.text.length > 0 || result.length === 0) {\n\t\t\tresult.push(node);\n\t\t}\n\t}\n\n\t// Remove empty TextNodes that are adjacent to InlineNodes\n\tconst cleaned: (TextNode | InlineNode)[] = result.filter((node, i) => {\n\t\tif (isInlineNode(node)) return true;\n\t\tif (node.text.length > 0) return true;\n\t\t// Keep if it's the only node\n\t\tif (result.length === 1) return true;\n\t\t// Remove empty TextNode if adjacent to InlineNode\n\t\tconst prev: TextNode | InlineNode | undefined = result[i - 1];\n\t\tconst next: TextNode | InlineNode | undefined = result[i + 1];\n\t\tif ((prev && isInlineNode(prev)) || (next && isInlineNode(next))) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t});\n\n\t// Ensure at least one TextNode exists\n\tif (cleaned.length === 0) return [createTextNode('')];\n\tif (!cleaned.some((n) => isTextNode(n))) {\n\t\treturn [createTextNode(''), ...cleaned];\n\t}\n\n\treturn cleaned;\n}\n\n/** Yields each inline child with its offset range. InlineNodes have width 1. */\nexport function* walkInlineContent(children: readonly (TextNode | InlineNode)[]): Generator<{\n\treadonly child: TextNode | InlineNode;\n\treadonly from: number;\n\treadonly to: number;\n}> {\n\tlet pos = 0;\n\tfor (const child of children) {\n\t\tconst width: number = isInlineNode(child) ? 1 : child.text.length;\n\t\tyield { child, from: pos, to: pos + width };\n\t\tpos += width;\n\t}\n}\n\n/** Returns the content at a specific offset: text char, inline node, or null. */\nexport function getContentAtOffset(\n\tblock: BlockNode,\n\toffset: number,\n):\n\t| { readonly kind: 'text'; readonly char: string; readonly marks: readonly Mark[] }\n\t| { readonly kind: 'inline'; readonly node: InlineNode }\n\t| null {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\n\tfor (const { child, from } of walkInlineContent(inlineChildren)) {\n\t\tif (isInlineNode(child)) {\n\t\t\tif (offset === from) return { kind: 'inline', node: child };\n\t\t\tcontinue;\n\t\t}\n\t\tconst localOffset: number = offset - from;\n\t\tif (localOffset >= 0 && localOffset < child.text.length) {\n\t\t\treturn {\n\t\t\t\tkind: 'text',\n\t\t\t\tchar: child.text[localOffset] ?? '',\n\t\t\t\tmarks: child.marks,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * Selection model for the Notectl editor.\n * A selection is defined by an anchor and head position within the document.\n */\n\nimport type { BlockId } from './TypeBrands.js';\n\nexport interface Position {\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\t/** Path from root block to leaf block (optional, for nested structures). */\n\treadonly path?: readonly BlockId[];\n}\n\nexport interface Selection {\n\treadonly anchor: Position;\n\treadonly head: Position;\n}\n\nexport interface SelectionRange {\n\treadonly from: Position;\n\treadonly to: Position;\n}\n\n/** A selection that selects an entire node (e.g. void blocks, table selection). */\nexport interface NodeSelection {\n\treadonly type: 'node';\n\treadonly nodeId: BlockId;\n\treadonly path: readonly BlockId[];\n}\n\n/** Union type representing either a text selection or a node selection. */\nexport type EditorSelection = Selection | NodeSelection;\n\n/** Creates a NodeSelection for the given block. */\nexport function createNodeSelection(nodeId: BlockId, path: readonly BlockId[]): NodeSelection {\n\treturn { type: 'node', nodeId, path };\n}\n\n/** Type guard: returns true if the selection is a NodeSelection. */\nexport function isNodeSelection(sel: EditorSelection): sel is NodeSelection {\n\treturn 'type' in sel && sel.type === 'node';\n}\n\n/** Type guard: returns true if the selection is a text Selection. */\nexport function isTextSelection(sel: EditorSelection): sel is Selection {\n\treturn !isNodeSelection(sel);\n}\n\n/** Compares two EditorSelections for equality. */\nexport function selectionsEqual(a: EditorSelection, b: EditorSelection): boolean {\n\tif (isNodeSelection(a) && isNodeSelection(b)) {\n\t\treturn a.nodeId === b.nodeId;\n\t}\n\tif (isTextSelection(a) && isTextSelection(b)) {\n\t\treturn (\n\t\t\ta.anchor.blockId === b.anchor.blockId &&\n\t\t\ta.anchor.offset === b.anchor.offset &&\n\t\t\ta.head.blockId === b.head.blockId &&\n\t\t\ta.head.offset === b.head.offset\n\t\t);\n\t}\n\treturn false;\n}\n\n/** Creates a Position, optionally with a path. */\nexport function createPosition(\n\tblockId: BlockId,\n\toffset: number,\n\tpath?: readonly BlockId[],\n): Position {\n\treturn path ? { blockId, offset, path } : { blockId, offset };\n}\n\n/** Creates a selection with distinct anchor and head. */\nexport function createSelection(anchor: Position, head: Position): Selection {\n\treturn { anchor, head };\n}\n\n/** Creates a collapsed selection (cursor) at the given position. */\nexport function createCollapsedSelection(blockId: BlockId, offset: number): Selection {\n\tconst pos: Position = { blockId, offset };\n\treturn { anchor: pos, head: pos };\n}\n\n/** Returns true if the selection is collapsed (cursor with no range). NodeSelection is never collapsed. */\nexport function isCollapsed(sel: EditorSelection): boolean {\n\tif (isNodeSelection(sel)) return false;\n\treturn sel.anchor.blockId === sel.head.blockId && sel.anchor.offset === sel.head.offset;\n}\n\n/**\n * Returns true if the selection direction is forward (anchor before head).\n * When anchor and head are in the same block, compares offsets.\n * Cross-block ordering uses document order (not determinable here — caller provides block order).\n * For NodeSelection, always returns true.\n */\nexport function isForward(sel: EditorSelection, blockOrder?: readonly BlockId[]): boolean {\n\tif (isNodeSelection(sel)) return true;\n\tif (sel.anchor.blockId === sel.head.blockId) {\n\t\treturn sel.anchor.offset <= sel.head.offset;\n\t}\n\tif (blockOrder) {\n\t\tconst anchorIdx = blockOrder.indexOf(sel.anchor.blockId);\n\t\tconst headIdx = blockOrder.indexOf(sel.head.blockId);\n\t\treturn anchorIdx <= headIdx;\n\t}\n\treturn true;\n}\n\n/**\n * Returns a normalized range where `from` is always before `to`.\n * Throws for NodeSelection — use isNodeSelection() guard first.\n */\nexport function selectionRange(sel: Selection, blockOrder?: readonly BlockId[]): SelectionRange {\n\tif (isForward(sel, blockOrder)) {\n\t\treturn { from: sel.anchor, to: sel.head };\n\t}\n\treturn { from: sel.head, to: sel.anchor };\n}\n","/**\n * Schema definition for the Notectl editor.\n * Defines which node types and marks are allowed.\n */\n\nimport type { NodeSpec } from './NodeSpec.js';\nimport type { SchemaRegistry } from './SchemaRegistry.js';\n\nexport interface Schema {\n\treadonly nodeTypes: readonly string[];\n\treadonly markTypes: readonly string[];\n\t/** Looks up the full NodeSpec for a given type. Available when created via schemaFromRegistry. */\n\treadonly getNodeSpec?: (type: string) => NodeSpec | undefined;\n}\n\n/** Creates the default schema with paragraph nodes and bold/italic/underline marks. */\nexport function defaultSchema(): Schema {\n\treturn {\n\t\tnodeTypes: ['paragraph'],\n\t\tmarkTypes: ['bold', 'italic', 'underline'],\n\t\tgetNodeSpec: () => undefined,\n\t};\n}\n\n/** Derives a Schema from a SchemaRegistry's registered specs. */\nexport function schemaFromRegistry(registry: SchemaRegistry): Schema {\n\treturn {\n\t\tnodeTypes: registry.getNodeTypes(),\n\t\tmarkTypes: registry.getMarkTypes(),\n\t\tgetNodeSpec: (type: string) => registry.getNodeSpec(type),\n\t};\n}\n\n/** Checks whether the given mark type is allowed by the schema. */\nexport function isMarkAllowed(schema: Schema, markType: string): boolean {\n\treturn schema.markTypes.includes(markType);\n}\n\n/** Checks whether the given node type is allowed by the schema. */\nexport function isNodeTypeAllowed(schema: Schema, nodeType: string): boolean {\n\treturn schema.nodeTypes.includes(nodeType);\n}\n","/**\n * Branded (nominal) types for semantic string distinctions.\n * Prevents accidental interchange of structurally identical IDs.\n */\n\ndeclare const __brand: unique symbol;\ntype Brand<T, B extends string> = T & { readonly [__brand]: B };\n\n/** Unique identifier for a block node in the document tree. */\nexport type BlockId = Brand<string, 'BlockId'>;\n\n/** Semantic name for a node type (e.g. 'paragraph', 'heading'). */\nexport type NodeTypeName = Brand<string, 'NodeTypeName'>;\n\n/** Semantic name for a mark type (e.g. 'bold', 'link'). */\nexport type MarkTypeName = Brand<string, 'MarkTypeName'>;\n\n/** Unique identifier for a plugin. */\nexport type PluginId = Brand<string, 'PluginId'>;\n\n/** Registered command name. */\nexport type CommandName = Brand<string, 'CommandName'>;\n\n/** Semantic name for an inline node type (e.g. 'image', 'mention'). */\nexport type InlineTypeName = Brand<string, 'InlineTypeName'>;\n\n// --- Constructor Functions ---\n\nexport function blockId(id: string): BlockId {\n\treturn id as BlockId;\n}\n\nexport function nodeType(name: string): NodeTypeName {\n\treturn name as NodeTypeName;\n}\n\nexport function markType(name: string): MarkTypeName {\n\treturn name as MarkTypeName;\n}\n\nexport function pluginId(id: string): PluginId {\n\treturn id as PluginId;\n}\n\nexport function commandName(name: string): CommandName {\n\treturn name as CommandName;\n}\n\nexport function inlineType(name: string): InlineTypeName {\n\treturn name as InlineTypeName;\n}\n","/**\n * Module-augmentable attribute registries for type-safe node/mark attributes.\n *\n * Plugins extend these interfaces via `declare module`:\n * @example\n * declare module '../../model/AttrRegistry.js' {\n * interface NodeAttrRegistry {\n * heading: { level: HeadingLevel; align?: BlockAlignment };\n * }\n * }\n */\n\nimport type { BlockAlignment } from '../plugins/alignment/AlignmentPlugin.js';\nimport type { BlockNode, InlineNode, Mark } from './Document.js';\nimport { isInlineNode } from './Document.js';\n\n/** Plugins augment this interface to register typed node attributes. */\nexport interface NodeAttrRegistry {\n\tparagraph: { align?: BlockAlignment };\n}\n\n/** Plugins augment this interface to register typed mark attributes. */\nexport interface MarkAttrRegistry {\n\tbold: Record<string, never>;\n\titalic: Record<string, never>;\n\tunderline: Record<string, never>;\n}\n\n/** Resolves typed attributes for known node types, falls back for unknown. */\nexport type NodeAttrsFor<T extends string> = T extends keyof NodeAttrRegistry\n\t? NodeAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Resolves typed attributes for known mark types, falls back for unknown. */\nexport type MarkAttrsFor<T extends string> = T extends keyof MarkAttrRegistry\n\t? MarkAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Narrows a BlockNode to a typed variant with known attributes. */\nexport function isNodeOfType<T extends keyof NodeAttrRegistry>(\n\tnode: BlockNode,\n\ttype: T,\n): node is BlockNode & { readonly type: T; readonly attrs: NodeAttrRegistry[T] } {\n\treturn (node.type as string) === type;\n}\n\n/** Narrows a Mark to a typed variant with known attributes. */\nexport function isMarkOfType<T extends keyof MarkAttrRegistry>(\n\tmark: Mark,\n\ttype: T,\n): mark is Mark & { readonly type: T; readonly attrs: MarkAttrRegistry[T] } {\n\treturn (mark.type as string) === type;\n}\n\n// --- InlineNode Attribute Registry ---\n\n/** Plugins augment this interface to register typed inline node attributes. */\n// biome-ignore lint/suspicious/noEmptyInterface: module augmentation requires interface\nexport interface InlineNodeAttrRegistry {}\n\n/** Resolves typed attributes for known inline node types, falls back for unknown. */\nexport type InlineNodeAttrsFor<T extends string> = T extends keyof InlineNodeAttrRegistry\n\t? InlineNodeAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Narrows an InlineNode to a typed variant with known attributes. */\nexport function isInlineNodeOfType<T extends keyof InlineNodeAttrRegistry>(\n\tnode: InlineNode,\n\tinlineNodeType: T,\n): node is InlineNode & {\n\treadonly inlineType: T;\n\treadonly attrs: InlineNodeAttrRegistry[T];\n} {\n\treturn isInlineNode(node) && (node.inlineType as string) === inlineNodeType;\n}\n","/**\n * NodeSpec: defines how a block-node type behaves and renders to the DOM.\n */\n\nimport type { NodeAttrsFor } from './AttrRegistry.js';\nimport type { BlockNode } from './Document.js';\nimport type { ParseRule } from './ParseRule.js';\nimport type { SanitizeConfig } from './SanitizeConfig.js';\nimport type { BlockId } from './TypeBrands.js';\n\nexport interface AttrSpec {\n\treadonly default?: string | number | boolean;\n}\n\n/** Describes a wrapper element that groups consecutive blocks of the same kind. */\nexport interface WrapperSpec {\n\t/** The HTML tag for the wrapper element (e.g., 'ul', 'ol'). */\n\treadonly tag: string;\n\t/** A key to group consecutive blocks. Blocks with the same key share a wrapper. */\n\treadonly key: string;\n\t/** Optional CSS class for the wrapper element. */\n\treadonly className?: string;\n\t/** Optional attributes for the wrapper element. */\n\treadonly attrs?: Readonly<Record<string, string>>;\n}\n\n/** Describes which children a node type is allowed to contain. */\nexport interface ContentRule {\n\t/** Allowed child types or group names. */\n\treadonly allow: readonly string[];\n\treadonly min?: number;\n\treadonly max?: number;\n}\n\n/** Creates an HTMLElement with the required `data-block-id` attribute. */\nexport function createBlockElement(tag: string, blockId: BlockId): HTMLElement {\n\tconst el = document.createElement(tag);\n\tel.setAttribute('data-block-id', blockId);\n\treturn el;\n}\n\nexport interface NodeSpec<T extends string = string> {\n\treadonly type: T;\n\t/** Renders the block to a DOM element. Must set `data-block-id` on the root. */\n\ttoDOM(node: Omit<BlockNode, 'attrs'> & { readonly attrs: NodeAttrsFor<T> }): HTMLElement;\n\treadonly attrs?: Readonly<Record<string, AttrSpec>>;\n\t/** If true, the node contains no editable text (e.g. Image, HR). */\n\treadonly isVoid?: boolean;\n\t/** Content model: which children this node can contain. */\n\treadonly content?: ContentRule;\n\t/** Group membership: 'block' | 'inline' | custom. */\n\treadonly group?: string;\n\t/** If true, selection cannot cross this node's boundary (e.g. table_cell). */\n\treadonly isolating?: boolean;\n\t/** If true, node can be selected as an object via mouse interaction. */\n\treadonly selectable?: boolean;\n\t/**\n\t * Mark types that are incompatible with this block type.\n\t * When a block is converted to this type, marks listed here\n\t * are stripped from the block's inline content.\n\t */\n\treadonly excludeMarks?: readonly string[];\n\t/** Serializes the block to an HTML string. `content` is the pre-serialized inline children. */\n\treadonly toHTML?: (node: BlockNode, content: string) => string;\n\t/** Rules for matching HTML elements to this block type during parsing. */\n\treadonly parseHTML?: readonly ParseRule[];\n\t/** Tags and attributes this spec needs through DOMPurify sanitization. */\n\treadonly sanitize?: SanitizeConfig;\n\t/**\n\t * If provided, the Reconciler groups consecutive blocks with the same\n\t * wrapper key into a shared wrapper element. Useful for semantic list\n\t * wrappers (`<ul>`, `<ol>`) around `<li>` block elements.\n\t */\n\twrapper?(node: Omit<BlockNode, 'attrs'> & { readonly attrs: NodeAttrsFor<T> }): WrapperSpec;\n}\n","/**\n * HTML string escaping utilities shared across serialization and parsing.\n */\n\n/** Escapes special HTML characters in text content. */\nexport function escapeHTML(text: string): string {\n\treturn text\n\t\t.replace(/&/g, '&')\n\t\t.replace(/</g, '<')\n\t\t.replace(/>/g, '>')\n\t\t.replace(/\"/g, '"');\n}\n","/**\n * SchemaRegistry: central registry for node specs, mark specs, node views,\n * keymaps, input rules, and toolbar items registered by plugins.\n */\n\nimport type { InputRule } from '../input/InputRule.js';\nimport type { Keymap } from '../input/Keymap.js';\nimport type { BlockTypePickerEntry } from '../plugins/heading/BlockTypePickerEntry.js';\nimport type { ToolbarItem } from '../plugins/toolbar/ToolbarItem.js';\nimport type { NodeViewFactory } from '../view/NodeView.js';\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\n/** Handler for files pasted or dropped into the editor. */\nexport type FileHandler = (\n\tfiles: readonly File[],\n\tposition: import('./Selection.js').Position | null,\n) => boolean | Promise<boolean>;\n\nexport interface FileHandlerEntry {\n\treadonly pattern: string;\n\treadonly handler: FileHandler;\n}\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\tprivate readonly _nodeViews = new Map<string, NodeViewFactory>();\n\tprivate readonly _keymaps: Keymap[] = [];\n\tprivate readonly _inputRules: InputRule[] = [];\n\tprivate readonly _toolbarItems = new Map<string, ToolbarItem>();\n\tprivate readonly _toolbarItemPluginMap = new Map<string, string[]>();\n\tprivate readonly _fileHandlers: FileHandlerEntry[] = [];\n\tprivate readonly _blockTypePickerEntries = new Map<string, BlockTypePickerEntry>();\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// --- NodeView ---\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\t// --- Keymap ---\n\n\tregisterKeymap(keymap: Keymap): void {\n\t\tfor (const key of Object.keys(keymap)) {\n\t\t\tfor (const existing of this._keymaps) {\n\t\t\t\tif (key in existing) {\n\t\t\t\t\tconsole.warn(\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._keymaps.push(keymap);\n\t}\n\n\tgetKeymaps(): readonly Keymap[] {\n\t\treturn this._keymaps;\n\t}\n\n\tremoveKeymap(keymap: Keymap): void {\n\t\tconst idx = this._keymaps.indexOf(keymap);\n\t\tif (idx !== -1) this._keymaps.splice(idx, 1);\n\t}\n\n\t// --- 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\t// --- ToolbarItem ---\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\t// --- FileHandler ---\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\t// --- BlockTypePickerEntry ---\n\n\tregisterBlockTypePickerEntry(entry: BlockTypePickerEntry): void {\n\t\tif (this._blockTypePickerEntries.has(entry.id)) {\n\t\t\tthrow new Error(`BlockTypePickerEntry with id \"${entry.id}\" is already registered.`);\n\t\t}\n\t\tthis._blockTypePickerEntries.set(entry.id, entry);\n\t}\n\n\tgetBlockTypePickerEntries(): readonly BlockTypePickerEntry[] {\n\t\treturn [...this._blockTypePickerEntries.values()].sort((a, b) => a.priority - b.priority);\n\t}\n\n\tremoveBlockTypePickerEntry(id: string): void {\n\t\tthis._blockTypePickerEntries.delete(id);\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\tthis._nodeViews.clear();\n\t\tthis._keymaps.length = 0;\n\t\tthis._inputRules.length = 0;\n\t\tthis._toolbarItems.clear();\n\t\tthis._toolbarItemPluginMap.clear();\n\t\tthis._fileHandlers.length = 0;\n\t\tthis._blockTypePickerEntries.clear();\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 * Utilities for resolving nodes by path within the document tree.\n * Supports both flat and recursive (nested) document structures.\n */\n\nimport type { BlockNode, Document } from './Document.js';\nimport { isBlockNode } from './Document.js';\n\n/**\n * Resolves a node in the document tree by its path (array of block IDs).\n * The path traces the lineage from the root block down to the target.\n */\nexport function resolveNodeByPath(doc: Document, path: readonly string[]): BlockNode | undefined {\n\tif (path.length === 0) return undefined;\n\n\tlet current: BlockNode | undefined = doc.children.find((b) => b.id === path[0]);\n\tif (!current) return undefined;\n\n\tfor (let i = 1; i < path.length; i++) {\n\t\tconst childId = path[i];\n\t\tif (!childId) return undefined;\n\t\tconst next: BlockNode | undefined = current?.children.find(\n\t\t\t(c): c is BlockNode => isBlockNode(c) && c.id === childId,\n\t\t);\n\t\tif (!next) return undefined;\n\t\tcurrent = next;\n\t}\n\n\treturn current;\n}\n\n/**\n * Resolves the parent of a node at the given path.\n * Returns the parent container (Document or BlockNode) and the child's index within it.\n */\nexport function resolveParentByPath(\n\tdoc: Document,\n\tpath: readonly string[],\n): { parent: Document | BlockNode; index: number } | undefined {\n\tif (path.length === 0) return undefined;\n\n\tif (path.length === 1) {\n\t\tconst index = doc.children.findIndex((b) => b.id === path[0]);\n\t\tif (index === -1) return undefined;\n\t\treturn { parent: doc, index };\n\t}\n\n\tconst parentPath = path.slice(0, -1);\n\tconst parent = resolveNodeByPath(doc, parentPath);\n\tif (!parent) return undefined;\n\n\tconst childId = path[path.length - 1];\n\tif (!childId) return undefined;\n\tconst index = parent.children.findIndex(\n\t\t(c): c is BlockNode => isBlockNode(c) && c.id === childId,\n\t);\n\tif (index === -1) return undefined;\n\n\treturn { parent, index };\n}\n\n/**\n * Finds the path (array of block IDs) to a node by its ID.\n * Performs recursive DFS through the document tree.\n */\nexport function findNodePath(doc: Document, nodeId: string): string[] | undefined {\n\tfor (const block of doc.children) {\n\t\tif (block.id === nodeId) return [nodeId];\n\n\t\tconst subPath = findNodePathInBlock(block, nodeId);\n\t\tif (subPath) return [block.id, ...subPath];\n\t}\n\treturn undefined;\n}\n\nfunction findNodePathInBlock(block: BlockNode, nodeId: string): string[] | undefined {\n\tfor (const child of block.children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tif (child.id === nodeId) return [nodeId];\n\n\t\tconst subPath = findNodePathInBlock(child, nodeId);\n\t\tif (subPath) return [child.id, ...subPath];\n\t}\n\treturn undefined;\n}\n\n/**\n * Walks all block nodes in the document tree in depth-first order.\n * Visits every BlockNode, including nested ones, with their full path.\n */\nexport function walkNodes(\n\tdoc: Document,\n\tcallback: (node: BlockNode, path: string[]) => void,\n): void {\n\tfor (const block of doc.children) {\n\t\twalkNodeRecursive(block, [block.id], callback);\n\t}\n}\n\nfunction walkNodeRecursive(\n\tnode: BlockNode,\n\tpath: string[],\n\tcallback: (node: BlockNode, path: string[]) => void,\n): void {\n\tcallback(node, path);\n\tfor (const child of node.children) {\n\t\tif (isBlockNode(child)) {\n\t\t\twalkNodeRecursive(child, [...path, child.id], callback);\n\t\t}\n\t}\n}\n\n/**\n * Finds a block node by ID anywhere in the document tree (recursive DFS).\n */\nexport function findNode(doc: Document, nodeId: string): BlockNode | undefined {\n\tfor (const block of doc.children) {\n\t\tif (block.id === nodeId) return block;\n\t\tconst found = findNodeInBlock(block, nodeId);\n\t\tif (found) return found;\n\t}\n\treturn undefined;\n}\n\nfunction findNodeInBlock(block: BlockNode, nodeId: string): BlockNode | undefined {\n\tfor (const child of block.children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tif (child.id === nodeId) return child;\n\t\tconst found = findNodeInBlock(child, nodeId);\n\t\tif (found) return found;\n\t}\n\treturn undefined;\n}\n\n/**\n * Finds a block node and returns it together with its path.\n */\nexport function findNodeWithPath(\n\tdoc: Document,\n\tnodeId: string,\n): { node: BlockNode; path: string[] } | undefined {\n\tconst path = findNodePath(doc, nodeId);\n\tif (!path) return undefined;\n\tconst node = resolveNodeByPath(doc, path);\n\tif (!node) return undefined;\n\treturn { node, path };\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 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 Mark,\n\ttype TextNode,\n\ttype TextSegment,\n\taddMarkToSet,\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgetBlockLength,\n\tgetInlineChildren,\n\tisBlockNode,\n\tisInlineNode,\n\tisTextNode,\n\tnormalizeInlineContent,\n\tremoveMarkFromSet,\n} from '../model/Document.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\t// Try at top level first\n\tconst blockIndex: number = doc.children.findIndex((b) => b.id === step.blockId);\n\n\tif (blockIndex !== -1) {\n\t\tconst block: BlockNode | undefined = doc.children[blockIndex];\n\t\tif (!block) return doc;\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 newChildren: BlockNode[] = [...doc.children];\n\t\tnewChildren.splice(blockIndex, 1, updatedBlock, newBlock);\n\t\treturn { children: newChildren };\n\t}\n\n\t// Recurse into block children\n\treturn {\n\t\tchildren: doc.children.map((child) => {\n\t\t\tconst mapped: BlockNode | null = splitBlockRecursive(child, step);\n\t\t\treturn mapped ?? child;\n\t\t}),\n\t};\n}\n\nfunction splitBlockRecursive(node: BlockNode, step: SplitBlockStep): BlockNode | null {\n\tconst idx: number = node.children.findIndex((c) => isBlockNode(c) && c.id === step.blockId);\n\tif (idx !== -1) {\n\t\tconst block: BlockNode = node.children[idx] 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 newChildren: ChildNode[] = [...node.children] as ChildNode[];\n\t\tnewChildren.splice(idx, 1, updatedBlock, newBlock);\n\t\treturn { ...node, children: newChildren };\n\t}\n\n\t// Recurse deeper\n\tlet changed = false;\n\tconst newChildren: ChildNode[] = node.children.map((child) => {\n\t\tif (!isBlockNode(child)) return child;\n\t\tconst mapped: BlockNode | null = splitBlockRecursive(child, step);\n\t\tif (mapped) {\n\t\t\tchanged = true;\n\t\t\treturn mapped;\n\t\t}\n\t\treturn child;\n\t});\n\n\treturn changed ? { ...node, children: newChildren } : null;\n}\n\nfunction applyMergeBlocks(doc: Document, step: MergeBlocksStep): Document {\n\t// Try at top level first\n\tconst targetIndex: number = doc.children.findIndex((b) => b.id === step.targetBlockId);\n\tconst sourceIndex: number = doc.children.findIndex((b) => b.id === step.sourceBlockId);\n\n\tif (targetIndex !== -1 && sourceIndex !== -1) {\n\t\tconst target: BlockNode | undefined = doc.children[targetIndex];\n\t\tconst source: BlockNode | undefined = doc.children[sourceIndex];\n\t\tif (!target || !source) return doc;\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 newChildren: readonly BlockNode[] = doc.children.filter(\n\t\t\t(b) => b.id !== step.sourceBlockId,\n\t\t);\n\t\treturn {\n\t\t\tchildren: newChildren.map((b) => (b.id === step.targetBlockId ? mergedBlock : b)),\n\t\t};\n\t}\n\n\t// Recurse into block children\n\treturn {\n\t\tchildren: doc.children.map((child) => {\n\t\t\tconst mapped: BlockNode | null = mergeBlocksRecursive(child, step);\n\t\t\treturn mapped ?? child;\n\t\t}),\n\t};\n}\n\nfunction mergeBlocksRecursive(node: BlockNode, step: MergeBlocksStep): BlockNode | null {\n\tconst targetIdx: number = node.children.findIndex(\n\t\t(c) => isBlockNode(c) && c.id === step.targetBlockId,\n\t);\n\tconst sourceIdx: number = node.children.findIndex(\n\t\t(c) => isBlockNode(c) && c.id === step.sourceBlockId,\n\t);\n\n\tif (targetIdx !== -1 && sourceIdx !== -1) {\n\t\tconst target: BlockNode = node.children[targetIdx] as BlockNode;\n\t\tconst source: BlockNode = node.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[] = node.children.filter(\n\t\t\t(c) => !isBlockNode(c) || c.id !== step.sourceBlockId,\n\t\t);\n\t\tconst result: ChildNode[] = filtered.map((c) =>\n\t\t\tisBlockNode(c) && c.id === step.targetBlockId ? mergedBlock : c,\n\t\t);\n\t\treturn { ...node, children: result };\n\t}\n\n\t// Recurse deeper\n\tlet changed = false;\n\tconst newChildren: ChildNode[] = node.children.map((child) => {\n\t\tif (!isBlockNode(child)) return child;\n\t\tconst mapped: BlockNode | null = mergeBlocksRecursive(child, step);\n\t\tif (mapped) {\n\t\t\tchanged = true;\n\t\t\treturn mapped;\n\t\t}\n\t\treturn child;\n\t});\n\n\treturn changed ? { ...node, children: newChildren } : null;\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\n// --- Helpers ---\n\nfunction mapBlock(doc: Document, blockId: string, fn: (block: BlockNode) => BlockNode): Document {\n\treturn {\n\t\tchildren: mapBlockInChildren(doc.children, blockId, fn) as BlockNode[],\n\t};\n}\n\nfunction 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 * Replaces the inline content children of a ChildNode array,\n * preserving any BlockNode children in their original positions.\n */\nfunction 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/**\n * Inserts text into mixed inline content at the given offset.\n * Handles both TextNode and InlineNode children.\n */\nfunction 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 */\nfunction 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 */\nfunction 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 */\nfunction 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 */\nfunction 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. */\nfunction 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. */\nfunction 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. */\nfunction 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\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/**\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 */\nfunction 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\nfunction 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 * 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}\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\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/** 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},\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\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(): object {\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 block\n\t\tconst firstBlock = doc.children[0];\n\t\tif (!firstBlock) return sel;\n\t\treturn createCollapsedSelection(firstBlock.id, 0);\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/** 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 * 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\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 * Editor commands for formatting, text manipulation, and history.\n */\n\nimport {\n\ttype BlockNode,\n\ttype Mark,\n\ttype MarkType,\n\tcreateBlockNode,\n\tcreateInlineNode,\n\tcreateTextNode,\n\tgenerateBlockId,\n\tgetBlockLength,\n\tgetBlockMarksAtOffset,\n\tgetContentAtOffset,\n\tgetInlineChildren,\n\thasMark,\n\tisBlockNode,\n\tisTextNode,\n} from '../model/Document.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport { isMarkAllowed } from '../model/Schema.js';\nimport type { NodeSelection } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tcreateSelection,\n\tisCollapsed,\n\tisNodeSelection,\n\tselectionRange,\n} from '../model/Selection.js';\nimport { type BlockId, inlineType, markType as mkType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport type { TransactionBuilder } from '../state/Transaction.js';\n\n// --- Feature Configuration ---\n\nexport interface FeatureConfig {\n\treadonly bold: boolean;\n\treadonly italic: boolean;\n\treadonly underline: boolean;\n}\n\nconst defaultFeatures: FeatureConfig = { bold: true, italic: true, underline: true };\n\n// --- Void Block Helpers ---\n\n/** Returns true if the block with the given ID is a void block (e.g. image, HR). */\nexport function isVoidBlock(state: EditorState, bid: BlockId): boolean {\n\tconst block = state.getBlock(bid);\n\tif (!block) return false;\n\tconst getNodeSpec = state.schema.getNodeSpec;\n\tif (!getNodeSpec) return false;\n\treturn getNodeSpec(block.type)?.isVoid === true;\n}\n\n/**\n * Deletes the void block targeted by a NodeSelection and places cursor\n * on the adjacent block. If it's the only block, replaces with empty paragraph.\n */\nexport function deleteNodeSelection(state: EditorState, sel: NodeSelection): Transaction | null {\n\tconst path = findNodePath(state.doc, sel.nodeId);\n\tif (!path) return null;\n\n\t// Determine parent path (all elements except the last)\n\tconst parentPath: BlockId[] = path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\n\t// Determine index among siblings\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) => 'id' in c && c.id === sel.nodeId);\n\tif (index < 0) return null;\n\n\tconst builder = state.transaction('input');\n\n\t// If this is the only block in the document, insert empty paragraph first\n\tif (siblings.length === 1 && parentPath.length === 0) {\n\t\tconst newId = generateBlockId();\n\t\tbuilder.insertNode(\n\t\t\tparentPath,\n\t\t\t0,\n\t\t\tcreateBlockNode(\n\t\t\t\t'paragraph' as import('../model/TypeBrands.js').NodeTypeName,\n\t\t\t\t[createTextNode('')],\n\t\t\t\tnewId,\n\t\t\t),\n\t\t);\n\t\tbuilder.removeNode(parentPath, 1);\n\t\tbuilder.setSelection(createCollapsedSelection(newId, 0));\n\t\treturn builder.build();\n\t}\n\n\tbuilder.removeNode(parentPath, index);\n\n\t// Find where to place cursor: prefer previous sibling leaf, else next sibling leaf.\n\tconst prevSibling = siblings[index - 1];\n\tif (prevSibling && isBlockNode(prevSibling)) {\n\t\tconst prevLeafId = findLastLeafBlockId(prevSibling);\n\t\tif (prevLeafId) {\n\t\t\tconst prevLeaf = state.getBlock(prevLeafId);\n\t\t\tconst prevLen = prevLeaf ? getBlockLength(prevLeaf) : 0;\n\t\t\tbuilder.setSelection(createCollapsedSelection(prevLeafId, prevLen));\n\t\t}\n\t} else {\n\t\tconst nextSibling = siblings[index + 1];\n\t\tif (nextSibling && isBlockNode(nextSibling)) {\n\t\t\tconst nextLeafId = findFirstLeafBlockId(nextSibling);\n\t\t\tif (nextLeafId) {\n\t\t\t\tbuilder.setSelection(createCollapsedSelection(nextLeafId, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn builder.build();\n}\n\nfunction findFirstLeafBlockId(node: BlockNode): BlockId {\n\tlet current: BlockNode = node;\n\twhile (true) {\n\t\tconst firstBlockChild = current.children.find((child): child is BlockNode =>\n\t\t\tisBlockNode(child),\n\t\t);\n\t\tif (!firstBlockChild) return current.id;\n\t\tcurrent = firstBlockChild;\n\t}\n}\n\nfunction findLastLeafBlockId(node: BlockNode): BlockId {\n\tlet current: BlockNode = node;\n\twhile (true) {\n\t\tlet lastBlockChild: BlockNode | undefined;\n\t\tfor (let i = current.children.length - 1; i >= 0; i--) {\n\t\t\tconst child = current.children[i];\n\t\t\tif (child && isBlockNode(child)) {\n\t\t\t\tlastBlockChild = child;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!lastBlockChild) return current.id;\n\t\tcurrent = lastBlockChild;\n\t}\n}\n\n// --- Mark Commands ---\n\n/**\n * Toggles a mark on the current selection.\n * If collapsed, toggles stored marks. If range, applies/removes from text.\n */\nexport function toggleMark(\n\tstate: EditorState,\n\tmarkType: MarkType,\n\tfeatures: FeatureConfig = defaultFeatures,\n): Transaction | null {\n\tif (isFeatureGated(markType, features)) return null;\n\tif (!isMarkAllowed(state.schema, markType)) return null;\n\tif (isNodeSelection(state.selection)) return null;\n\n\tconst mark: Mark = { type: markType };\n\tconst sel = state.selection;\n\n\tif (isCollapsed(sel)) {\n\t\t// Toggle stored marks\n\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\tif (!anchorBlock) return null;\n\t\tconst currentMarks = state.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\tconst hasIt = hasMark(currentMarks, markType);\n\t\tconst newMarks = hasIt\n\t\t\t? currentMarks.filter((m) => m.type !== markType)\n\t\t\t: [...currentMarks, mark];\n\n\t\treturn state\n\t\t\t.transaction('command')\n\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t}\n\n\t// Range selection — apply/remove mark to all blocks in range\n\tconst blockOrder = state.getBlockOrder();\n\tconst range = selectionRange(sel, blockOrder);\n\tconst builder = state.transaction('command');\n\n\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t// Determine if we should add or remove\n\tconst shouldRemove = isMarkActiveInRange(state, markType);\n\n\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\tconst blockId = blockOrder[i];\n\t\tif (!blockId) continue;\n\t\tconst block = state.getBlock(blockId);\n\t\tif (!block) continue;\n\t\tconst blockLen = getBlockLength(block);\n\n\t\tconst from = i === fromIdx ? range.from.offset : 0;\n\t\tconst to = i === toIdx ? range.to.offset : blockLen;\n\n\t\tif (from === to) continue;\n\n\t\tif (shouldRemove) {\n\t\t\tbuilder.removeMark(blockId, from, to, mark);\n\t\t} else {\n\t\t\tbuilder.addMark(blockId, from, to, mark);\n\t\t}\n\t}\n\n\tbuilder.setSelection(sel);\n\treturn builder.build();\n}\n\n/** Checks if a mark is active across the entire selection range. */\nfunction isMarkActiveInRange(state: EditorState, markType: MarkType): boolean {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return false;\n\tconst blockOrder = state.getBlockOrder();\n\tconst range = selectionRange(sel, blockOrder);\n\n\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\tconst blockId = blockOrder[i];\n\t\tif (!blockId) continue;\n\t\tconst block = state.getBlock(blockId);\n\t\tif (!block) continue;\n\t\tconst blockLen = getBlockLength(block);\n\t\tconst from = i === fromIdx ? range.from.offset : 0;\n\t\tconst to = i === toIdx ? range.to.offset : blockLen;\n\n\t\tif (!isMarkActiveInBlock(block, from, to, markType)) return false;\n\t}\n\n\treturn true;\n}\n\nfunction isMarkActiveInBlock(\n\tblock: BlockNode,\n\tfrom: number,\n\tto: number,\n\tmarkType: MarkType,\n): boolean {\n\tif (from === to) return false;\n\tlet pos = 0;\n\tfor (const child of getInlineChildren(block)) {\n\t\tif (isTextNode(child)) {\n\t\t\tconst childEnd = pos + child.text.length;\n\t\t\tif (childEnd > from && pos < to) {\n\t\t\t\tif (!hasMark(child.marks, markType)) return false;\n\t\t\t}\n\t\t\tpos = childEnd;\n\t\t} else {\n\t\t\t// InlineNode: skip (width 1, no marks)\n\t\t\tpos += 1;\n\t\t}\n\t}\n\treturn true;\n}\n\nexport function toggleBold(state: EditorState, features?: FeatureConfig): Transaction | null {\n\treturn toggleMark(state, mkType('bold'), features);\n}\n\nexport function toggleItalic(state: EditorState, features?: FeatureConfig): Transaction | null {\n\treturn toggleMark(state, mkType('italic'), features);\n}\n\nexport function toggleUnderline(state: EditorState, features?: FeatureConfig): Transaction | null {\n\treturn toggleMark(state, mkType('underline'), features);\n}\n\n// --- Text Commands ---\n\n/** Inserts text at the current selection, replacing any selected range. */\nexport function insertTextCommand(\n\tstate: EditorState,\n\ttext: string,\n\torigin: 'input' | 'paste' = 'input',\n): Transaction {\n\tconst sel = state.selection;\n\n\t// NodeSelection: insert paragraph after void block with the text\n\tif (isNodeSelection(sel)) {\n\t\treturn insertTextAfterNodeSelection(state, sel, text, origin);\n\t}\n\n\tconst builder = state.transaction(origin);\n\tconst marks = resolveActiveMarks(state);\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst range = isCollapsed(sel) ? null : selectionRange(sel, state.getBlockOrder());\n\tconst insertBlockId = range ? range.from.blockId : sel.anchor.blockId;\n\tconst insertOffset = range ? range.from.offset : sel.anchor.offset;\n\n\tbuilder.insertText(insertBlockId, insertOffset, text, marks);\n\tbuilder.setSelection(createCollapsedSelection(insertBlockId, insertOffset + text.length));\n\n\treturn builder.build();\n}\n\n/** Deletes the current selection. */\nexport function deleteSelectionCommand(state: EditorState): Transaction | null {\n\tif (isNodeSelection(state.selection)) {\n\t\treturn deleteNodeSelection(state, state.selection);\n\t}\n\tif (isCollapsed(state.selection)) return null;\n\n\tconst builder = state.transaction('input');\n\taddDeleteSelectionSteps(state, builder);\n\n\tconst range = selectionRange(state.selection, state.getBlockOrder());\n\tbuilder.setSelection(createCollapsedSelection(range.from.blockId, range.from.offset));\n\n\treturn builder.build();\n}\n\n/** Handles backspace key. */\nexport function deleteBackward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) {\n\t\treturn deleteNodeSelection(state, sel);\n\t}\n\n\tif (!isCollapsed(sel)) {\n\t\treturn deleteSelectionCommand(state);\n\t}\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\n\tif (sel.anchor.offset > 0) {\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.deleteTextAt(block.id, sel.anchor.offset - 1, sel.anchor.offset)\n\t\t\t.setSelection(createCollapsedSelection(block.id, sel.anchor.offset - 1))\n\t\t\t.build();\n\t}\n\n\t// At start of block — merge with previous\n\treturn mergeBlockBackward(state);\n}\n\n/** Handles delete key. */\nexport function deleteForward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) {\n\t\treturn deleteNodeSelection(state, sel);\n\t}\n\n\tif (!isCollapsed(sel)) {\n\t\treturn deleteSelectionCommand(state);\n\t}\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\n\tconst blockLen = getBlockLength(block);\n\n\tif (sel.anchor.offset < blockLen) {\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.deleteTextAt(block.id, sel.anchor.offset, sel.anchor.offset + 1)\n\t\t\t.setSelection(createCollapsedSelection(block.id, sel.anchor.offset))\n\t\t\t.build();\n\t}\n\n\t// At end of block — merge with next\n\treturn mergeBlockForward(state);\n}\n\n/** Handles Ctrl+Backspace: delete word backward. */\nexport function deleteWordBackward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) {\n\t\treturn deleteNodeSelection(state, sel);\n\t}\n\n\tif (!isCollapsed(sel)) {\n\t\treturn deleteSelectionCommand(state);\n\t}\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\n\tif (sel.anchor.offset === 0) {\n\t\treturn mergeBlockBackward(state);\n\t}\n\n\tconst wordStart = findWordBoundaryBackward(block, sel.anchor.offset);\n\n\treturn state\n\t\t.transaction('input')\n\t\t.deleteTextAt(block.id, wordStart, sel.anchor.offset)\n\t\t.setSelection(createCollapsedSelection(block.id, wordStart))\n\t\t.build();\n}\n\n/** Handles Ctrl+Delete: delete word forward. */\nexport function deleteWordForward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) {\n\t\treturn deleteNodeSelection(state, sel);\n\t}\n\n\tif (!isCollapsed(sel)) {\n\t\treturn deleteSelectionCommand(state);\n\t}\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\n\tconst blockLen = getBlockLength(block);\n\tif (sel.anchor.offset === blockLen) {\n\t\treturn mergeBlockForward(state);\n\t}\n\n\tconst wordEnd = findWordBoundaryForward(block, sel.anchor.offset);\n\n\treturn state\n\t\t.transaction('input')\n\t\t.deleteTextAt(block.id, sel.anchor.offset, wordEnd)\n\t\t.setSelection(createCollapsedSelection(block.id, sel.anchor.offset))\n\t\t.build();\n}\n\n/** Handles Cmd+Backspace: delete to start of line/block. */\nexport function deleteSoftLineBackward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) {\n\t\treturn deleteNodeSelection(state, sel);\n\t}\n\n\tif (!isCollapsed(sel)) {\n\t\treturn deleteSelectionCommand(state);\n\t}\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\n\tif (sel.anchor.offset === 0) {\n\t\treturn mergeBlockBackward(state);\n\t}\n\n\treturn state\n\t\t.transaction('input')\n\t\t.deleteTextAt(block.id, 0, sel.anchor.offset)\n\t\t.setSelection(createCollapsedSelection(block.id, 0))\n\t\t.build();\n}\n\n/** Handles Cmd+Delete: delete to end of line/block. */\nexport function deleteSoftLineForward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) {\n\t\treturn deleteNodeSelection(state, sel);\n\t}\n\n\tif (!isCollapsed(sel)) {\n\t\treturn deleteSelectionCommand(state);\n\t}\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\n\tconst blockLen = getBlockLength(block);\n\tif (sel.anchor.offset === blockLen) {\n\t\treturn mergeBlockForward(state);\n\t}\n\n\treturn state\n\t\t.transaction('input')\n\t\t.deleteTextAt(block.id, sel.anchor.offset, blockLen)\n\t\t.setSelection(createCollapsedSelection(block.id, sel.anchor.offset))\n\t\t.build();\n}\n\n/** Splits the current block at the cursor position (Enter key). */\nexport function splitBlockCommand(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\n\t// NodeSelection: insert empty paragraph after the void block\n\tif (isNodeSelection(sel)) {\n\t\treturn insertParagraphAfterNodeSelection(state, sel);\n\t}\n\n\tconst builder = state.transaction('input');\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst blockId = isCollapsed(sel)\n\t\t? sel.anchor.blockId\n\t\t: selectionRange(sel, state.getBlockOrder()).from.blockId;\n\tconst offset = isCollapsed(sel)\n\t\t? sel.anchor.offset\n\t\t: selectionRange(sel, state.getBlockOrder()).from.offset;\n\n\tconst newBlockId = generateBlockId();\n\n\t// splitBlock operates at the same level in the tree — the StepApplication\n\t// handles this correctly because it looks up the block by ID recursively.\n\tbuilder.splitBlock(blockId, offset, newBlockId);\n\tbuilder.setSelection(createCollapsedSelection(newBlockId, 0));\n\n\treturn builder.build();\n}\n\n/** Inserts a hard line break (InlineNode) at the current cursor position. */\nexport function insertHardBreakCommand(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) return null;\n\n\tconst builder = state.transaction('input');\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst range = isCollapsed(sel) ? null : selectionRange(sel, state.getBlockOrder());\n\tconst insertBlockId: BlockId = range ? range.from.blockId : sel.anchor.blockId;\n\tconst insertOffset: number = range ? range.from.offset : sel.anchor.offset;\n\n\tconst hardBreak = createInlineNode(inlineType('hard_break'));\n\tbuilder.insertInlineNode(insertBlockId, insertOffset, hardBreak);\n\tbuilder.setSelection(createCollapsedSelection(insertBlockId, insertOffset + 1));\n\n\treturn builder.build();\n}\n\n/** Checks whether two blocks share the same parent in the document tree. */\nexport function sharesParent(state: EditorState, blockIdA: BlockId, blockIdB: BlockId): boolean {\n\tconst pathA = state.getNodePath(blockIdA);\n\tconst pathB = state.getNodePath(blockIdB);\n\tif (!pathA || !pathB) return false;\n\tif (pathA.length !== pathB.length) return false;\n\t// Compare parent paths (all but last element)\n\tfor (let i = 0; i < pathA.length - 1; i++) {\n\t\tif (pathA[i] !== pathB[i]) return false;\n\t}\n\treturn true;\n}\n\n/** Checks whether a block is inside an isolating node (e.g. table_cell). */\nexport function isInsideIsolating(state: EditorState, blockId: BlockId): boolean {\n\tconst getNodeSpec = state.schema.getNodeSpec;\n\tif (!getNodeSpec) return false;\n\tconst path = state.getNodePath(blockId);\n\tif (!path || path.length <= 1) return false;\n\n\t// Check ancestors (not the block itself)\n\tfor (let i = 0; i < path.length - 1; i++) {\n\t\tconst ancestorId = path[i];\n\t\tif (!ancestorId) continue;\n\t\tconst ancestor = state.getBlock(ancestorId);\n\t\tif (!ancestor) continue;\n\t\tconst spec = getNodeSpec(ancestor.type);\n\t\tif (spec?.isolating) return true;\n\t}\n\treturn false;\n}\n\nfunction isIsolatingBlock(state: EditorState, blockId: BlockId): boolean {\n\tconst getNodeSpec = state.schema.getNodeSpec;\n\tif (!getNodeSpec) return false;\n\tconst block = state.getBlock(blockId);\n\tif (!block) return false;\n\treturn getNodeSpec(block.type)?.isolating === true;\n}\n\n/**\n * Merges the current block with the previous block, respecting\n * isolating boundaries and void blocks.\n */\nexport function mergeBlockBackward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return null;\n\tconst blockOrder = state.getBlockOrder();\n\tconst blockIdx = blockOrder.indexOf(sel.anchor.blockId);\n\n\tif (blockIdx <= 0) return null;\n\n\tconst prevBlockId = blockOrder[blockIdx - 1];\n\tif (!prevBlockId) return null;\n\n\t// Never merge isolating blocks directly (e.g. table cells).\n\tif (isIsolatingBlock(state, sel.anchor.blockId) || isIsolatingBlock(state, prevBlockId)) {\n\t\treturn null;\n\t}\n\n\t// Prevent merge across isolating boundaries\n\tif (!sharesParent(state, sel.anchor.blockId, prevBlockId)) {\n\t\tif (isInsideIsolating(state, sel.anchor.blockId)) return null;\n\t}\n\n\t// If previous block is void, select it instead of merging\n\tif (isVoidBlock(state, prevBlockId)) {\n\t\tconst path = findNodePath(state.doc, prevBlockId) ?? [];\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createNodeSelection(prevBlockId, path as BlockId[]))\n\t\t\t.build();\n\t}\n\n\tconst prevBlock = state.getBlock(prevBlockId);\n\tif (!prevBlock) return null;\n\tconst prevLen = getBlockLength(prevBlock);\n\n\treturn state\n\t\t.transaction('input')\n\t\t.mergeBlocksAt(prevBlockId, sel.anchor.blockId)\n\t\t.setSelection(createCollapsedSelection(prevBlockId, prevLen))\n\t\t.build();\n}\n\n/**\n * Merges the next block into the current block, respecting\n * isolating boundaries and void blocks.\n */\nfunction mergeBlockForward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return null;\n\tconst blockOrder = state.getBlockOrder();\n\tconst blockIdx = blockOrder.indexOf(sel.anchor.blockId);\n\n\tif (blockIdx >= blockOrder.length - 1) return null;\n\n\tconst nextBlockId = blockOrder[blockIdx + 1];\n\tif (!nextBlockId) return null;\n\n\t// Never merge isolating blocks directly (e.g. table cells).\n\tif (isIsolatingBlock(state, sel.anchor.blockId) || isIsolatingBlock(state, nextBlockId)) {\n\t\treturn null;\n\t}\n\n\t// Prevent merge across isolating boundaries\n\tif (!sharesParent(state, sel.anchor.blockId, nextBlockId)) {\n\t\tif (isInsideIsolating(state, sel.anchor.blockId)) return null;\n\t}\n\n\t// If next block is void, select it instead of merging\n\tif (isVoidBlock(state, nextBlockId)) {\n\t\tconst path = findNodePath(state.doc, nextBlockId) ?? [];\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createNodeSelection(nextBlockId, path as BlockId[]))\n\t\t\t.build();\n\t}\n\n\treturn state\n\t\t.transaction('input')\n\t\t.mergeBlocksAt(sel.anchor.blockId, nextBlockId)\n\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, sel.anchor.offset))\n\t\t.build();\n}\n\n/** Selects all content in the editor. */\nexport function selectAll(state: EditorState): Transaction {\n\tconst blocks = state.doc.children;\n\tconst firstBlock = blocks[0];\n\tconst lastBlock = blocks[blocks.length - 1];\n\tif (!firstBlock || !lastBlock)\n\t\treturn state.transaction('command').setSelection(state.selection).build();\n\tconst lastBlockLen = getBlockLength(lastBlock);\n\n\treturn state\n\t\t.transaction('command')\n\t\t.setSelection(\n\t\t\tcreateSelection(\n\t\t\t\t{ blockId: firstBlock.id, offset: 0 },\n\t\t\t\t{ blockId: lastBlock.id, offset: lastBlockLen },\n\t\t\t),\n\t\t)\n\t\t.build();\n}\n\n// --- Check Commands ---\n\n/** Checks if a mark is active at the current selection. */\nexport function isMarkActive(state: EditorState, markType: MarkType): boolean {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return false;\n\n\tif (isCollapsed(sel)) {\n\t\tif (state.storedMarks) {\n\t\t\treturn hasMark(state.storedMarks, markType);\n\t\t}\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\treturn hasMark(marks, markType);\n\t}\n\n\treturn isMarkActiveInRange(state, markType);\n}\n\n// --- Internal Helpers ---\n\nfunction resolveActiveMarks(state: EditorState): readonly Mark[] {\n\tif (state.storedMarks) return state.storedMarks;\n\tif (isNodeSelection(state.selection)) return [];\n\n\tconst block = state.getBlock(state.selection.anchor.blockId);\n\tif (!block) return [];\n\n\treturn getBlockMarksAtOffset(block, state.selection.anchor.offset);\n}\n\nexport function addDeleteSelectionSteps(state: EditorState, builder: TransactionBuilder): void {\n\tif (isNodeSelection(state.selection)) return;\n\tconst blockOrder = state.getBlockOrder();\n\tconst range = selectionRange(state.selection, blockOrder);\n\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\tif (fromIdx === toIdx) {\n\t\tbuilder.deleteTextAt(range.from.blockId, range.from.offset, range.to.offset);\n\t} else {\n\t\tconst firstBlock = state.getBlock(range.from.blockId);\n\t\tif (!firstBlock) return;\n\t\tconst firstLen = getBlockLength(firstBlock);\n\n\t\t// Delete from the end of first block\n\t\tif (range.from.offset < firstLen) {\n\t\t\tbuilder.deleteTextAt(range.from.blockId, range.from.offset, firstLen);\n\t\t}\n\n\t\t// Delete from start of last block\n\t\tif (range.to.offset > 0) {\n\t\t\tbuilder.deleteTextAt(range.to.blockId, 0, range.to.offset);\n\t\t}\n\n\t\t// Delete middle blocks entirely and merge last into first\n\t\tfor (let i = fromIdx + 1; i < toIdx; i++) {\n\t\t\tconst midBlockId = blockOrder[i];\n\t\t\tif (!midBlockId) continue;\n\t\t\tconst midBlock = state.getBlock(midBlockId);\n\t\t\tif (!midBlock) continue;\n\t\t\tconst midLen = getBlockLength(midBlock);\n\t\t\tif (midLen > 0) {\n\t\t\t\tbuilder.deleteTextAt(midBlockId, 0, midLen);\n\t\t\t}\n\t\t\tbuilder.mergeBlocksAt(range.from.blockId, midBlockId);\n\t\t}\n\n\t\t// Merge last block into first\n\t\tbuilder.mergeBlocksAt(range.from.blockId, range.to.blockId);\n\t}\n}\n\n/**\n * Finds the word boundary backward from the given offset.\n * InlineNodes act as word boundaries.\n */\nfunction findWordBoundaryBackward(block: BlockNode, offset: number): number {\n\tlet pos = offset - 1;\n\t// Skip trailing whitespace\n\twhile (pos >= 0) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (!content || content.kind === 'inline') break;\n\t\tif (!/\\s/.test(content.char)) break;\n\t\tpos--;\n\t}\n\t// If at InlineNode, delete just it (treat as word boundary)\n\tif (pos >= 0) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (content?.kind === 'inline') return pos;\n\t}\n\t// Skip word characters until whitespace or InlineNode\n\twhile (pos >= 0) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (!content || content.kind === 'inline') break;\n\t\tif (/\\s/.test(content.char)) break;\n\t\tpos--;\n\t}\n\treturn pos + 1;\n}\n\n/**\n * Finds the word boundary forward from the given offset.\n * InlineNodes act as word boundaries.\n */\nfunction findWordBoundaryForward(block: BlockNode, offset: number): number {\n\tconst len = getBlockLength(block);\n\tlet pos = offset;\n\t// Skip word characters first\n\twhile (pos < len) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (!content || content.kind === 'inline') break;\n\t\tif (/\\s/.test(content.char)) break;\n\t\tpos++;\n\t}\n\t// If at InlineNode and haven't moved, delete just the InlineNode\n\tif (pos === offset && pos < len) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (content?.kind === 'inline') return pos + 1;\n\t}\n\t// Skip trailing whitespace\n\twhile (pos < len) {\n\t\tconst content = getContentAtOffset(block, pos);\n\t\tif (!content || content.kind === 'inline') break;\n\t\tif (!/\\s/.test(content.char)) break;\n\t\tpos++;\n\t}\n\treturn pos;\n}\n\nfunction isFeatureGated(type: MarkType, features: FeatureConfig): boolean {\n\tconst key = type as string;\n\tif (key === 'bold') return !features.bold;\n\tif (key === 'italic') return !features.italic;\n\tif (key === 'underline') return !features.underline;\n\treturn false;\n}\n\n/** Inserts a new paragraph after a NodeSelection-targeted void block. */\nfunction insertParagraphAfterNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n): Transaction | null {\n\tconst path = findNodePath(state.doc, sel.nodeId);\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) => 'id' in c && c.id === sel.nodeId);\n\tif (index < 0) return null;\n\n\tconst newId = generateBlockId();\n\tconst builder = state.transaction('input');\n\tbuilder.insertNode(\n\t\tparentPath,\n\t\tindex + 1,\n\t\tcreateBlockNode(\n\t\t\t'paragraph' as import('../model/TypeBrands.js').NodeTypeName,\n\t\t\t[createTextNode('')],\n\t\t\tnewId,\n\t\t),\n\t);\n\tbuilder.setSelection(createCollapsedSelection(newId, 0));\n\treturn builder.build();\n}\n\n/** Inserts text in a new paragraph after a NodeSelection-targeted void block. */\nfunction insertTextAfterNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n\ttext: string,\n\torigin: 'input' | 'paste',\n): Transaction {\n\tconst path = findNodePath(state.doc, sel.nodeId);\n\tconst parentPath: BlockId[] = path && 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) => 'id' in c && c.id === sel.nodeId);\n\n\tconst newId = generateBlockId();\n\tconst builder = state.transaction(origin);\n\n\tconst insertIdx = index >= 0 ? index + 1 : siblings.length;\n\tbuilder.insertNode(\n\t\tparentPath,\n\t\tinsertIdx,\n\t\tcreateBlockNode(\n\t\t\t'paragraph' as import('../model/TypeBrands.js').NodeTypeName,\n\t\t\t[createTextNode('')],\n\t\t\tnewId,\n\t\t),\n\t);\n\tbuilder.insertText(newId, 0, text, []);\n\tbuilder.setSelection(createCollapsedSelection(newId, text.length));\n\treturn builder.build();\n}\n\n/**\n * Navigates arrow keys into/out of void blocks.\n * Returns a transaction if navigation should create a NodeSelection, or null.\n */\nexport function navigateArrowIntoVoid(\n\tstate: EditorState,\n\tdirection: 'left' | 'right' | 'up' | 'down',\n): Transaction | null {\n\tconst sel = state.selection;\n\tconst blockOrder = state.getBlockOrder();\n\n\t// If currently on a NodeSelection, navigate away from it\n\tif (isNodeSelection(sel)) {\n\t\tconst nodeIdx = blockOrder.indexOf(sel.nodeId);\n\t\tif (direction === 'left' || direction === 'up') {\n\t\t\t// Move to end of previous block\n\t\t\tif (nodeIdx > 0) {\n\t\t\t\tconst prevId = blockOrder[nodeIdx - 1];\n\t\t\t\tif (!prevId) return null;\n\t\t\t\tif (isVoidBlock(state, prevId)) {\n\t\t\t\t\tconst path = findNodePath(state.doc, prevId) ?? [];\n\t\t\t\t\treturn state\n\t\t\t\t\t\t.transaction('input')\n\t\t\t\t\t\t.setSelection(createNodeSelection(prevId, path as BlockId[]))\n\t\t\t\t\t\t.build();\n\t\t\t\t}\n\t\t\t\tconst prevBlock = state.getBlock(prevId);\n\t\t\t\tconst prevLen = prevBlock ? getBlockLength(prevBlock) : 0;\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createCollapsedSelection(prevId, prevLen))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\t// right or down\n\t\tif (nodeIdx < blockOrder.length - 1) {\n\t\t\tconst nextId = blockOrder[nodeIdx + 1];\n\t\t\tif (!nextId) return null;\n\t\t\tif (isVoidBlock(state, nextId)) {\n\t\t\t\tconst path = findNodePath(state.doc, nextId) ?? [];\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createNodeSelection(nextId, path as BlockId[]))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t\treturn state.transaction('input').setSelection(createCollapsedSelection(nextId, 0)).build();\n\t\t}\n\t\treturn null;\n\t}\n\n\t// Text selection: check if navigating into a void block\n\tif (!isCollapsed(sel)) return null;\n\n\tconst blockIdx = blockOrder.indexOf(sel.anchor.blockId);\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\tconst blockLen = getBlockLength(block);\n\n\tif (direction === 'right' || direction === 'down') {\n\t\tif (sel.anchor.offset === blockLen && blockIdx < blockOrder.length - 1) {\n\t\t\tconst nextId = blockOrder[blockIdx + 1];\n\t\t\tif (nextId && isVoidBlock(state, nextId)) {\n\t\t\t\tconst path = findNodePath(state.doc, nextId) ?? [];\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createNodeSelection(nextId, path as BlockId[]))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (direction === 'left' || direction === 'up') {\n\t\tif (sel.anchor.offset === 0 && blockIdx > 0) {\n\t\t\tconst prevId = blockOrder[blockIdx - 1];\n\t\t\tif (prevId && isVoidBlock(state, prevId)) {\n\t\t\t\tconst path = findNodePath(state.doc, prevId) ?? [];\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createNodeSelection(prevId, path as BlockId[]))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\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\tdeleteNodeSelection,\n\tinsertTextCommand,\n\tnavigateArrowIntoVoid,\n\tselectAll,\n\tsplitBlockCommand,\n} from '../commands/Commands.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { isNodeSelection } from '../model/Selection.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport type { DispatchFn, GetStateFn, RedoFn, UndoFn } from './InputHandler.js';\n\nexport interface KeyboardHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tundo: UndoFn;\n\tredo: RedoFn;\n\tschemaRegistry?: SchemaRegistry;\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 schemaRegistry?: SchemaRegistry;\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.schemaRegistry = options.schemaRegistry;\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// Handle NodeSelection keys before plugin keymaps\n\t\tif (this.handleNodeSelectionKeys(e)) return;\n\n\t\t// Handle arrow key navigation into void blocks\n\t\tif (this.handleArrowIntoVoid(e)) return;\n\n\t\t// Try plugin keymaps first (last registered has highest precedence)\n\t\tif (this.schemaRegistry) {\n\t\t\tconst descriptor = normalizeKeyDescriptor(e);\n\t\t\tconst keymaps = this.schemaRegistry.getKeymaps();\n\t\t\t// Iterate in reverse so later-registered keymaps take precedence\n\t\t\tfor (let i = keymaps.length - 1; i >= 0; i--) {\n\t\t\t\tconst handler = keymaps[i]?.[descriptor];\n\t\t\t\tif (handler?.()) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\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\n\t\tif (key === 'ArrowLeft' || key === 'ArrowUp' || key === 'ArrowRight' || key === 'ArrowDown') {\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\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\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 * 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\t/** Handles arrow key navigation from text blocks into adjacent void blocks. */\n\tprivate handleArrowIntoVoid(e: KeyboardEvent): boolean {\n\t\tconst key = e.key;\n\t\tif (key !== 'ArrowLeft' && key !== 'ArrowRight' && key !== 'ArrowUp' && key !== 'ArrowDown') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Don't intercept modified arrows (selection extension, word jump)\n\t\tif (e.shiftKey || e.metaKey || e.ctrlKey || e.altKey) return false;\n\n\t\tconst state = this.getState();\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\n\t\tconst tr = navigateArrowIntoVoid(state, direction);\n\t\tif (tr) {\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\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 * 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 type { BlockNode, Mark } from '../model/Document.js';\nimport {\n\tgetBlockLength,\n\tgetBlockText,\n\tgetInlineChildren,\n\tisInlineNode,\n\tisTextNode,\n} 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 {\n\tisCollapsed,\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}\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 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\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// 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\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// 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 (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 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));\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(block: BlockNode, start: number, end: number): 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) {\n\t\t\t\t\tparts.push(this.serializeTextWithMarks(text, child.marks));\n\t\t\t\t}\n\t\t\t}\n\t\t\t// InlineNodes are skipped for text/html serialization (same as plain text)\n\n\t\t\tpos = childEnd;\n\t\t}\n\n\t\treturn parts.join('');\n\t}\n\n\t/** Wraps escaped text in mark HTML tags using MarkSpec.toHTMLString when available. */\n\tprivate serializeTextWithMarks(text: string, marks: readonly Mark[]): string {\n\t\tif (marks.length === 0 || !this.schemaRegistry) {\n\t\t\treturn escapeHTML(text);\n\t\t}\n\n\t\t// Sort marks by rank (lowest rank = closest to text content = applied first)\n\t\tconst sorted: readonly Mark[] = [...marks].sort((a, b) => {\n\t\t\tconst specA: MarkSpec | undefined = this.schemaRegistry?.getMarkSpec(a.type);\n\t\t\tconst specB: MarkSpec | undefined = this.schemaRegistry?.getMarkSpec(b.type);\n\t\t\treturn (specA?.rank ?? 100) - (specB?.rank ?? 100);\n\t\t});\n\n\t\tlet html: string = escapeHTML(text);\n\t\t// Apply marks from innermost (lowest rank) to outermost (highest rank)\n\t\tfor (const mark of sorted) {\n\t\t\tconst spec: MarkSpec | undefined = this.schemaRegistry?.getMarkSpec(mark.type);\n\t\t\tif (spec?.toHTMLString) {\n\t\t\t\thtml = spec.toHTMLString(mark, html);\n\t\t\t}\n\t\t}\n\t\treturn html;\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 * Plugin system types for the Notectl editor.\n */\n\nimport type { DecorationSet } from '../decorations/Decoration.js';\nimport type { InputRule } from '../input/InputRule.js';\nimport type { Keymap } from '../input/Keymap.js';\nimport type { InlineNodeSpec } from '../model/InlineNodeSpec.js';\nimport type { MarkSpec } from '../model/MarkSpec.js';\nimport type { NodeSpec } from '../model/NodeSpec.js';\nimport type { FileHandler } from '../model/SchemaRegistry.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport type { NodeViewFactory } from '../view/NodeView.js';\nimport type { BlockTypePickerEntry } from './heading/BlockTypePickerEntry.js';\nimport type { ToolbarItem } from './toolbar/ToolbarItem.js';\n\n// --- Type-Safe Keys ---\n\n/** Type-safe event key for compile-time payload checking. */\nexport class EventKey<T> {\n\tdeclare readonly _type: T;\n\tconstructor(public readonly id: string) {}\n}\n\n/** Type-safe service key for compile-time type checking. */\nexport class ServiceKey<T> {\n\tdeclare readonly _type: T;\n\tconstructor(public readonly id: string) {}\n}\n\n// --- Command System ---\n\nexport type CommandHandler = () => boolean;\n\nexport interface CommandEntry {\n\treadonly name: string;\n\treadonly handler: CommandHandler;\n\treadonly pluginId: string;\n}\n\n// --- Event System ---\n\nexport type PluginEventCallback<T = unknown> = (payload: T) => void;\n\nexport interface PluginEventBus {\n\temit<T>(key: EventKey<T>, payload: T): void;\n\ton<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void;\n\toff<T>(key: EventKey<T>, callback: PluginEventCallback<T>): void;\n}\n\n// --- Configuration ---\n\nexport type PluginConfig = Record<string, unknown>;\n\n// --- Middleware ---\n\nexport type MiddlewareNext = (tr: Transaction) => void;\nexport type TransactionMiddleware = (\n\ttr: Transaction,\n\tstate: EditorState,\n\tnext: MiddlewareNext,\n) => void;\n\n// --- Plugin Context ---\n\nexport interface PluginContext {\n\tgetState(): EditorState;\n\tdispatch(transaction: Transaction): void;\n\tgetContainer(): HTMLElement;\n\tgetPluginContainer(position: 'top' | 'bottom'): HTMLElement;\n\tregisterCommand(name: string, handler: CommandHandler): void;\n\texecuteCommand(name: string): boolean;\n\tgetEventBus(): PluginEventBus;\n\tregisterMiddleware(middleware: TransactionMiddleware, priority?: number): void;\n\tregisterService<T>(key: ServiceKey<T>, service: T): void;\n\tgetService<T>(key: ServiceKey<T>): T | undefined;\n\tupdateConfig(config: PluginConfig): void;\n\n\t// --- Schema Extension ---\n\tregisterNodeSpec<T extends string>(spec: NodeSpec<T>): void;\n\tregisterMarkSpec<T extends string>(spec: MarkSpec<T>): void;\n\tregisterNodeView(type: string, factory: NodeViewFactory): void;\n\tregisterKeymap(keymap: Keymap): void;\n\tregisterInputRule(rule: InputRule): void;\n\tregisterToolbarItem(item: ToolbarItem): void;\n\tregisterInlineNodeSpec<T extends string>(spec: InlineNodeSpec<T>): void;\n\tregisterFileHandler(pattern: string, handler: FileHandler): void;\n\tregisterBlockTypePickerEntry(entry: BlockTypePickerEntry): void;\n\tgetSchemaRegistry(): SchemaRegistry;\n\n\t/** Pushes a screen reader announcement via the editor's aria-live region. */\n\tannounce(text: string): void;\n}\n\n// --- Plugin Interface ---\n\nexport interface Plugin<TConfig extends Record<string, unknown> = Record<string, unknown>> {\n\treadonly id: string;\n\treadonly name: string;\n\treadonly priority?: number;\n\treadonly dependencies?: readonly string[];\n\n\tinit(context: PluginContext): void | Promise<void>;\n\tdestroy?(): void | Promise<void>;\n\tonStateChange?(oldState: EditorState, newState: EditorState, tr: Transaction): void;\n\tonConfigure?(config: TConfig): void;\n\t/** Called after ALL plugins have been initialized. */\n\tonReady?(): void | Promise<void>;\n\t/**\n\t * Returns decorations for the given state.\n\t * Called after state.apply() but BEFORE reconciliation.\n\t * Plugins should cache and only recompute when needed.\n\t */\n\tdecorations?(state: EditorState, tr?: Transaction): DecorationSet;\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 * Pure functions for mapping decorations through transaction steps.\n * Handles position adjustments when the document changes — insertions,\n * deletions, splits, merges, and structural node removal.\n */\n\nimport type {\n\tDeleteTextStep,\n\tInsertTextStep,\n\tMergeBlocksStep,\n\tRemoveNodeStep,\n\tSplitBlockStep,\n\tStep,\n} from '../state/Transaction.js';\nimport type {\n\tDecoration,\n\tInlineDecoration,\n\tNodeDecoration,\n\tWidgetDecoration,\n} from './Decoration.js';\n\n/**\n * Maps a single decoration through a step.\n * Returns the mapped decoration, an array (when a split produces two),\n * or null if the decoration was deleted by the step.\n */\nexport function mapDecorationThroughStep(\n\tdeco: Decoration,\n\tstep: Step,\n): Decoration | readonly Decoration[] | null {\n\tswitch (deco.type) {\n\t\tcase 'inline':\n\t\t\treturn mapInline(deco, step);\n\t\tcase 'widget':\n\t\t\treturn mapWidget(deco, step);\n\t\tcase 'node':\n\t\t\treturn mapNode(deco, step);\n\t}\n}\n\nfunction mapInline(\n\tdeco: InlineDecoration,\n\tstep: Step,\n): InlineDecoration | readonly InlineDecoration[] | null {\n\tswitch (step.type) {\n\t\tcase 'insertText':\n\t\t\treturn mapInlineInsert(deco, step);\n\t\tcase 'deleteText':\n\t\t\treturn mapInlineDelete(deco, step);\n\t\tcase 'splitBlock':\n\t\t\treturn mapInlineSplit(deco, step);\n\t\tcase 'mergeBlocks':\n\t\t\treturn mapInlineMerge(deco, step);\n\t\tcase 'removeNode':\n\t\t\treturn removeIfBlockDeleted(deco, step);\n\t\tdefault:\n\t\t\treturn deco;\n\t}\n}\n\nfunction mapWidget(deco: WidgetDecoration, step: Step): WidgetDecoration | null {\n\tswitch (step.type) {\n\t\tcase 'insertText':\n\t\t\treturn mapWidgetInsert(deco, step);\n\t\tcase 'deleteText':\n\t\t\treturn mapWidgetDelete(deco, step);\n\t\tcase 'splitBlock':\n\t\t\treturn mapWidgetSplit(deco, step);\n\t\tcase 'mergeBlocks':\n\t\t\treturn mapWidgetMerge(deco, step);\n\t\tcase 'removeNode':\n\t\t\treturn removeIfBlockDeleted(deco, step);\n\t\tdefault:\n\t\t\treturn deco;\n\t}\n}\n\nfunction mapNode(deco: NodeDecoration, step: Step): NodeDecoration | null {\n\tswitch (step.type) {\n\t\tcase 'mergeBlocks':\n\t\t\treturn mapNodeMerge(deco, step);\n\t\tcase 'removeNode':\n\t\t\treturn removeIfBlockDeleted(deco, step);\n\t\tdefault:\n\t\t\treturn deco;\n\t}\n}\n\n// --- InsertText ---\n\nfunction mapInlineInsert(deco: InlineDecoration, step: InsertTextStep): InlineDecoration {\n\tif (deco.blockId !== step.blockId) return deco;\n\n\tconst len: number = step.text.length;\n\t// from: assoc=-1 (stays at boundary — only shifts if insertion is strictly before)\n\tconst newFrom: number = deco.from > step.offset ? deco.from + len : deco.from;\n\t// to: assoc=1 (moves past insertion — shifts if insertion is at or before)\n\tconst newTo: number = deco.to >= step.offset ? deco.to + len : deco.to;\n\n\tif (newFrom === deco.from && newTo === deco.to) return deco;\n\treturn { ...deco, from: newFrom, to: newTo };\n}\n\nfunction mapWidgetInsert(deco: WidgetDecoration, step: InsertTextStep): WidgetDecoration {\n\tif (deco.blockId !== step.blockId) return deco;\n\n\tconst len: number = step.text.length;\n\t// At boundary: side=-1 means \"before insertion\" (assoc=-1, stays), side=1 means \"after\" (moves)\n\tif (deco.offset > step.offset) {\n\t\treturn { ...deco, offset: deco.offset + len };\n\t}\n\tif (deco.offset === step.offset && deco.side >= 1) {\n\t\treturn { ...deco, offset: deco.offset + len };\n\t}\n\treturn deco;\n}\n\n// --- DeleteText ---\n\nfunction mapInlineDelete(deco: InlineDecoration, step: DeleteTextStep): InlineDecoration | null {\n\tif (deco.blockId !== step.blockId) return deco;\n\n\tconst delLen: number = step.to - step.from;\n\tconst newFrom: number = clampAndShift(deco.from, step.from, step.to, delLen);\n\tconst newTo: number = clampAndShift(deco.to, step.from, step.to, delLen);\n\n\tif (newFrom >= newTo) return null;\n\tif (newFrom === deco.from && newTo === deco.to) return deco;\n\treturn { ...deco, from: newFrom, to: newTo };\n}\n\nfunction mapWidgetDelete(deco: WidgetDecoration, step: DeleteTextStep): WidgetDecoration | null {\n\tif (deco.blockId !== step.blockId) return deco;\n\n\t// Widget strictly inside deleted range → deleted\n\tif (deco.offset > step.from && deco.offset < step.to) return null;\n\n\tconst delLen: number = step.to - step.from;\n\tif (deco.offset >= step.to) {\n\t\treturn { ...deco, offset: deco.offset - delLen };\n\t}\n\treturn deco;\n}\n\n// --- SplitBlock ---\n\nfunction mapInlineSplit(\n\tdeco: InlineDecoration,\n\tstep: SplitBlockStep,\n): InlineDecoration | readonly InlineDecoration[] {\n\tif (deco.blockId !== step.blockId) return deco;\n\n\t// Entirely before split point → unchanged\n\tif (deco.to <= step.offset) return deco;\n\n\t// Entirely after split point → move to new block, adjust offsets\n\tif (deco.from >= step.offset) {\n\t\treturn {\n\t\t\t...deco,\n\t\t\tblockId: step.newBlockId,\n\t\t\tfrom: deco.from - step.offset,\n\t\t\tto: deco.to - step.offset,\n\t\t};\n\t}\n\n\t// Spanning the split point → split into two decorations\n\tconst left: InlineDecoration = { ...deco, to: step.offset };\n\tconst right: InlineDecoration = {\n\t\t...deco,\n\t\tblockId: step.newBlockId,\n\t\tfrom: 0,\n\t\tto: deco.to - step.offset,\n\t};\n\treturn [left, right];\n}\n\nfunction mapWidgetSplit(deco: WidgetDecoration, step: SplitBlockStep): WidgetDecoration {\n\tif (deco.blockId !== step.blockId) return deco;\n\n\t// Before split → stays\n\tif (deco.offset < step.offset) return deco;\n\n\t// After split → new block\n\tif (deco.offset > step.offset) {\n\t\treturn {\n\t\t\t...deco,\n\t\t\tblockId: step.newBlockId,\n\t\t\toffset: deco.offset - step.offset,\n\t\t};\n\t}\n\n\t// At boundary: side determines which block\n\tif (deco.side >= 1) {\n\t\treturn {\n\t\t\t...deco,\n\t\t\tblockId: step.newBlockId,\n\t\t\toffset: 0,\n\t\t};\n\t}\n\treturn deco;\n}\n\n// --- MergeBlocks ---\n\nfunction mapInlineMerge(deco: InlineDecoration, step: MergeBlocksStep): InlineDecoration {\n\tif (deco.blockId !== step.sourceBlockId) return deco;\n\n\treturn {\n\t\t...deco,\n\t\tblockId: step.targetBlockId,\n\t\tfrom: deco.from + step.targetLengthBefore,\n\t\tto: deco.to + step.targetLengthBefore,\n\t};\n}\n\nfunction mapWidgetMerge(deco: WidgetDecoration, step: MergeBlocksStep): WidgetDecoration {\n\tif (deco.blockId !== step.sourceBlockId) return deco;\n\n\treturn {\n\t\t...deco,\n\t\tblockId: step.targetBlockId,\n\t\toffset: deco.offset + step.targetLengthBefore,\n\t};\n}\n\nfunction mapNodeMerge(deco: NodeDecoration, step: MergeBlocksStep): NodeDecoration | null {\n\t// Source block disappears → delete its node decoration\n\tif (deco.blockId === step.sourceBlockId) return null;\n\treturn deco;\n}\n\n// --- RemoveNode ---\n\nfunction removeIfBlockDeleted<T extends Decoration>(deco: T, step: RemoveNodeStep): T | null {\n\tif (deco.blockId === step.removedNode.id) return null;\n\treturn deco;\n}\n\n// --- Helpers ---\n\nfunction clampAndShift(pos: number, delFrom: number, delTo: number, delLen: number): number {\n\tif (pos <= delFrom) return pos;\n\tif (pos >= delTo) return pos - delLen;\n\treturn delFrom;\n}\n","/**\n * Decoration types and DecorationSet for transient, view-only annotations.\n * Decorations are NOT part of the document model and do NOT affect undo/redo.\n */\n\nimport type { BlockId } from '../model/TypeBrands.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { mapDecorationThroughStep } from './PositionMapping.js';\n\n// --- Decoration Attrs ---\n\nexport interface DecorationAttrs {\n\treadonly class?: string;\n\treadonly style?: string;\n\treadonly nodeName?: string;\n\treadonly [key: string]: string | undefined;\n}\n\n// --- Decoration Types ---\n\nexport interface InlineDecoration {\n\treadonly type: 'inline';\n\treadonly blockId: BlockId;\n\treadonly from: number;\n\treadonly to: number;\n\treadonly attrs: DecorationAttrs;\n}\n\nexport interface NodeDecoration {\n\treadonly type: 'node';\n\treadonly blockId: BlockId;\n\treadonly attrs: DecorationAttrs;\n}\n\nexport interface WidgetDecoration {\n\treadonly type: 'widget';\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n\treadonly toDOM: () => HTMLElement;\n\treadonly side: -1 | 1;\n\treadonly key?: string;\n}\n\nexport type Decoration = InlineDecoration | NodeDecoration | WidgetDecoration;\n\n// --- Factory Functions ---\n\n/** Creates an inline decoration for a text range within a block. */\nexport function inline(\n\tblockId: BlockId,\n\tfrom: number,\n\tto: number,\n\tattrs: DecorationAttrs,\n): InlineDecoration {\n\treturn { type: 'inline', blockId, from, to, attrs };\n}\n\n/** Creates a node decoration that applies to a whole block element. */\nexport function node(blockId: BlockId, attrs: DecorationAttrs): NodeDecoration {\n\treturn { type: 'node', blockId, attrs };\n}\n\n/** Creates a widget decoration that inserts a DOM element at a position. */\nexport function widget(\n\tblockId: BlockId,\n\toffset: number,\n\ttoDOM: () => HTMLElement,\n\toptions?: { readonly side?: -1 | 1; readonly key?: string },\n): WidgetDecoration {\n\treturn {\n\t\ttype: 'widget',\n\t\tblockId,\n\t\toffset,\n\t\ttoDOM,\n\t\tside: options?.side ?? -1,\n\t\tkey: options?.key,\n\t};\n}\n\n// --- DecorationSet ---\n\n/**\n * Immutable set of decorations indexed by block ID.\n * Provides efficient lookup and merging of decoration collections.\n */\nexport class DecorationSet {\n\tstatic readonly empty: DecorationSet = new DecorationSet(new Map());\n\n\tprivate constructor(private readonly byBlock: ReadonlyMap<BlockId, readonly Decoration[]>) {}\n\n\t/** Creates a DecorationSet from a flat array of decorations. */\n\tstatic create(decorations: readonly Decoration[]): DecorationSet {\n\t\tif (decorations.length === 0) return DecorationSet.empty;\n\n\t\tconst map = new Map<BlockId, Decoration[]>();\n\t\tfor (const deco of decorations) {\n\t\t\tconst existing = map.get(deco.blockId);\n\t\t\tif (existing) {\n\t\t\t\texisting.push(deco);\n\t\t\t} else {\n\t\t\t\tmap.set(deco.blockId, [deco]);\n\t\t\t}\n\t\t}\n\t\treturn new DecorationSet(map);\n\t}\n\n\t/** Returns all decorations for a given block. */\n\tfind(blockId: BlockId): readonly Decoration[] {\n\t\treturn this.byBlock.get(blockId) ?? [];\n\t}\n\n\t/** Returns only inline decorations for a given block. */\n\tfindInline(blockId: BlockId): readonly InlineDecoration[] {\n\t\tconst decos = this.byBlock.get(blockId);\n\t\tif (!decos) return [];\n\t\treturn decos.filter((d): d is InlineDecoration => d.type === 'inline');\n\t}\n\n\t/** Returns only node decorations for a given block. */\n\tfindNode(blockId: BlockId): readonly NodeDecoration[] {\n\t\tconst decos = this.byBlock.get(blockId);\n\t\tif (!decos) return [];\n\t\treturn decos.filter((d): d is NodeDecoration => d.type === 'node');\n\t}\n\n\t/** Returns only widget decorations for a given block. */\n\tfindWidget(blockId: BlockId): readonly WidgetDecoration[] {\n\t\tconst decos = this.byBlock.get(blockId);\n\t\tif (!decos) return [];\n\t\treturn decos.filter((d): d is WidgetDecoration => d.type === 'widget');\n\t}\n\n\t/** Returns a new DecorationSet with the given decorations added. */\n\tadd(decorations: readonly Decoration[]): DecorationSet {\n\t\tif (decorations.length === 0) return this;\n\t\tif (this.isEmpty) return DecorationSet.create(decorations);\n\n\t\tconst map = new Map<BlockId, Decoration[]>();\n\t\tfor (const [bid, decos] of this.byBlock) {\n\t\t\tmap.set(bid, [...decos]);\n\t\t}\n\t\tfor (const deco of decorations) {\n\t\t\tconst existing = map.get(deco.blockId);\n\t\t\tif (existing) {\n\t\t\t\texisting.push(deco);\n\t\t\t} else {\n\t\t\t\tmap.set(deco.blockId, [deco]);\n\t\t\t}\n\t\t}\n\t\treturn new DecorationSet(map);\n\t}\n\n\t/** Returns a new DecorationSet with decorations matching the predicate removed. */\n\tremove(predicate: (d: Decoration) => boolean): DecorationSet {\n\t\tconst map = new Map<BlockId, Decoration[]>();\n\t\tlet changed = false;\n\n\t\tfor (const [bid, decos] of this.byBlock) {\n\t\t\tconst filtered = decos.filter((d) => !predicate(d));\n\t\t\tif (filtered.length !== decos.length) changed = true;\n\t\t\tif (filtered.length > 0) {\n\t\t\t\tmap.set(bid, filtered);\n\t\t\t}\n\t\t}\n\n\t\tif (!changed) return this;\n\t\tif (map.size === 0) return DecorationSet.empty;\n\t\treturn new DecorationSet(map);\n\t}\n\n\t/** Returns a new DecorationSet merging this set with another. */\n\tmerge(other: DecorationSet): DecorationSet {\n\t\tif (other.isEmpty) return this;\n\t\tif (this.isEmpty) return other;\n\n\t\tconst map = new Map<BlockId, Decoration[]>();\n\t\tfor (const [bid, decos] of this.byBlock) {\n\t\t\tmap.set(bid, [...decos]);\n\t\t}\n\t\tfor (const [bid, decos] of other.byBlock) {\n\t\t\tconst existing = map.get(bid);\n\t\t\tif (existing) {\n\t\t\t\texisting.push(...decos);\n\t\t\t} else {\n\t\t\t\tmap.set(bid, [...decos]);\n\t\t\t}\n\t\t}\n\t\treturn new DecorationSet(map);\n\t}\n\n\t/** Checks equality — reference first, then structural comparison. */\n\tequals(other: DecorationSet): boolean {\n\t\tif (this === other) return true;\n\t\tif (this.byBlock.size !== other.byBlock.size) return false;\n\n\t\tfor (const [bid, decos] of this.byBlock) {\n\t\t\tconst otherDecos = other.byBlock.get(bid);\n\t\t\tif (!otherDecos) return false;\n\t\t\tif (!decorationArraysEqual(decos, otherDecos)) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** True if the set contains no decorations. */\n\tget isEmpty(): boolean {\n\t\treturn this.byBlock.size === 0;\n\t}\n\n\t/**\n\t * Maps decorations through document changes described by a transaction.\n\t * Decorations that become invalid (e.g. fully deleted range) are removed.\n\t * Decorations that span a split point are split into two.\n\t */\n\tmap(tr: Transaction): DecorationSet {\n\t\tif (this.isEmpty || tr.steps.length === 0) return this;\n\n\t\tlet mapped: Decoration[] = [];\n\t\tfor (const decos of this.byBlock.values()) {\n\t\t\tfor (const d of decos) {\n\t\t\t\tmapped.push(d);\n\t\t\t}\n\t\t}\n\n\t\tfor (const step of tr.steps) {\n\t\t\tconst next: Decoration[] = [];\n\t\t\tfor (const deco of mapped) {\n\t\t\t\tconst result = mapDecorationThroughStep(deco, step);\n\t\t\t\tif (result === null) continue;\n\t\t\t\tif (Array.isArray(result)) {\n\t\t\t\t\tfor (const r of result) {\n\t\t\t\t\t\tnext.push(r);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tnext.push(result as Decoration);\n\t\t\t\t}\n\t\t\t}\n\t\t\tmapped = next;\n\t\t}\n\n\t\tif (mapped.length === 0) return DecorationSet.empty;\n\t\treturn DecorationSet.create(mapped);\n\t}\n}\n\n// --- Helpers ---\n\n/** Compares two decoration arrays for structural equality. */\nexport function decorationArraysEqual(a: readonly Decoration[], b: readonly Decoration[]): boolean {\n\tif (a === b) return true;\n\tif (a.length !== b.length) return false;\n\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst ai = a[i];\n\t\tconst bi = b[i];\n\t\tif (!ai || !bi || !decorationsEqual(ai, bi)) return false;\n\t}\n\treturn true;\n}\n\n/** Compares two individual decorations for structural equality. */\nfunction decorationsEqual(a: Decoration, b: Decoration): boolean {\n\tif (a.type !== b.type) return false;\n\tif (a.blockId !== b.blockId) return false;\n\n\tswitch (a.type) {\n\t\tcase 'inline': {\n\t\t\tconst bi = b as InlineDecoration;\n\t\t\treturn a.from === bi.from && a.to === bi.to && attrsEqual(a.attrs, bi.attrs);\n\t\t}\n\t\tcase 'node': {\n\t\t\tconst bn = b as NodeDecoration;\n\t\t\treturn attrsEqual(a.attrs, bn.attrs);\n\t\t}\n\t\tcase 'widget': {\n\t\t\tconst bw = b as WidgetDecoration;\n\t\t\treturn (\n\t\t\t\ta.offset === bw.offset && a.side === bw.side && a.key === bw.key && a.toDOM === bw.toDOM\n\t\t\t);\n\t\t}\n\t}\n}\n\n/** Compares two DecorationAttrs objects. */\nfunction attrsEqual(a: DecorationAttrs, b: DecorationAttrs): boolean {\n\tif (a === b) return true;\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 * 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 { InputRule } from '../input/InputRule.js';\nimport type { Keymap } from '../input/Keymap.js';\nimport { type FileHandler, SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { EventBus } from './EventBus.js';\nimport type {\n\tCommandEntry,\n\tCommandHandler,\n\tMiddlewareNext,\n\tPlugin,\n\tPluginConfig,\n\tPluginContext,\n\tPluginEventBus,\n\tServiceKey,\n\tTransactionMiddleware,\n} from './Plugin.js';\n\nconst DEFAULT_PRIORITY = 100;\n\ninterface MiddlewareEntry {\n\tmiddleware: TransactionMiddleware;\n\tpriority: number;\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}\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/** 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\treadonly schemaRegistry = new SchemaRegistry();\n\tprivate middlewareSorted: MiddlewareEntry[] | null = null;\n\tprivate initOrder: string[] = [];\n\tprivate initialized = false;\n\tprivate initializing = false;\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 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/** Executes a named command. Returns false if command not found. */\n\texecuteCommand(name: string): boolean {\n\t\tconst entry = this.commands.get(name);\n\t\tif (!entry) return false;\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}\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 all registered plugin IDs. */\n\tgetPluginIds(): string[] {\n\t\treturn [...this.plugins.keys()];\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/** 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.eventBus.clear();\n\t\tthis.registrations.clear();\n\t\tthis.schemaRegistry.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\t\tfor (const type of reg.nodeViews) this.schemaRegistry.removeNodeView(type);\n\t\tfor (const keymap of reg.keymaps) this.schemaRegistry.removeKeymap(keymap);\n\t\tfor (const rule of reg.inputRules) this.schemaRegistry.removeInputRule(rule);\n\t\tfor (const itemId of reg.toolbarItems) this.schemaRegistry.removeToolbarItem(itemId);\n\t\tfor (const handler of reg.fileHandlers) {\n\t\t\tthis.schemaRegistry.removeFileHandler(handler);\n\t\t}\n\t\tfor (const id of reg.blockTypePickerEntries) {\n\t\t\tthis.schemaRegistry.removeBlockTypePickerEntry(id);\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};\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\n\t\t\tregisterCommand: (name: string, handler: CommandHandler) => {\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\tthis.commands.set(name, { name, handler, pluginId });\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, priority = DEFAULT_PRIORITY) => {\n\t\t\t\tconst entry: MiddlewareEntry = { 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.schemaRegistry.registerNodeView(type, factory);\n\t\t\t\treg.nodeViews.push(type);\n\t\t\t},\n\n\t\t\tregisterKeymap: (keymap) => {\n\t\t\t\tthis.schemaRegistry.registerKeymap(keymap);\n\t\t\t\treg.keymaps.push(keymap);\n\t\t\t},\n\n\t\t\tregisterInputRule: (rule) => {\n\t\t\t\tthis.schemaRegistry.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.schemaRegistry.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.schemaRegistry.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.schemaRegistry.registerBlockTypePickerEntry(entry);\n\t\t\t\treg.blockTypePickerEntries.push(entry.id);\n\t\t\t},\n\n\t\t\tgetSchemaRegistry: () => this.schemaRegistry,\n\n\t\t\tannounce: (text: string) => {\n\t\t\t\toptions.announce?.(text);\n\t\t\t},\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","/**\n * Keyboard navigation helpers for the toolbar (WAI-ARIA Toolbar pattern).\n * Pure functions that operate on arrays of buttons and DOM elements.\n */\n\n/** Returns indices of all enabled buttons. */\nexport function getEnabledIndices(buttons: readonly HTMLButtonElement[]): number[] {\n\tconst result: number[] = [];\n\tfor (let i = 0; i < buttons.length; i++) {\n\t\tif (!buttons[i]?.disabled) {\n\t\t\tresult.push(i);\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Finds the next enabled button index in the given direction (wraps around). */\nexport function findNextEnabled(\n\tbuttons: readonly HTMLButtonElement[],\n\tcurrent: number,\n\tdirection: 1 | -1,\n): number {\n\tconst len = buttons.length;\n\tif (len === 0) return -1;\n\n\tlet index = current;\n\tfor (let i = 0; i < len; i++) {\n\t\tindex = (index + direction + len) % len;\n\t\tif (!buttons[index]?.disabled) {\n\t\t\treturn index;\n\t\t}\n\t}\n\treturn current;\n}\n\n/** Finds the first enabled button index. */\nexport function findFirstEnabled(buttons: readonly HTMLButtonElement[]): number {\n\tfor (let i = 0; i < buttons.length; i++) {\n\t\tif (!buttons[i]?.disabled) return i;\n\t}\n\treturn -1;\n}\n\n/** Finds the last enabled button index. */\nexport function findLastEnabled(buttons: readonly HTMLButtonElement[]): number {\n\tfor (let i = buttons.length - 1; i >= 0; i--) {\n\t\tif (!buttons[i]?.disabled) return i;\n\t}\n\treturn -1;\n}\n\n/**\n * Applies roving tabindex: sets tabindex=\"0\" on the focused button,\n * tabindex=\"-1\" on all others.\n */\nexport function applyRovingTabindex(\n\tbuttons: readonly HTMLButtonElement[],\n\tfocusedIndex: number,\n): void {\n\tfor (let i = 0; i < buttons.length; i++) {\n\t\tconst btn = buttons[i];\n\t\tif (btn) {\n\t\t\tbtn.setAttribute('tabindex', i === focusedIndex ? '0' : '-1');\n\t\t}\n\t}\n}\n\n/** Navigates dropdown items with arrow keys (wraps around). */\nexport function findNextDropdownItem(\n\titems: readonly HTMLElement[],\n\tcurrent: number,\n\tdirection: 1 | -1,\n): number {\n\tconst len = items.length;\n\tif (len === 0) return -1;\n\treturn (current + direction + len) % len;\n}\n\n/**\n * Navigates a grid of cells with arrow keys.\n * Returns the new [row, col] position.\n */\nexport function navigateGrid(\n\trow: number,\n\tcol: number,\n\tmaxRows: number,\n\tmaxCols: number,\n\tkey: 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight',\n): [number, number] {\n\tswitch (key) {\n\t\tcase 'ArrowUp':\n\t\t\treturn [row > 1 ? row - 1 : maxRows, col];\n\t\tcase 'ArrowDown':\n\t\t\treturn [row < maxRows ? row + 1 : 1, col];\n\t\tcase 'ArrowLeft':\n\t\t\treturn [row, col > 1 ? col - 1 : maxCols];\n\t\tcase 'ArrowRight':\n\t\t\treturn [row, col < maxCols ? col + 1 : 1];\n\t}\n}\n","/**\n * ToolbarRenderers: pure rendering functions for toolbar popup content.\n * Grid pickers, dropdown menus, and separator elements.\n */\n\nimport type { DropdownConfig, GridPickerConfig } from './ToolbarItem.js';\n\nconst HIGHLIGHTED_CLASS = 'notectl-grid-picker__cell--highlighted';\n\n/**\n * Renders a grid picker into the given container.\n * Calls `onClose` after a cell is selected so the popup can be dismissed.\n */\nexport function renderGridPicker(\n\tcontainer: HTMLElement,\n\tconfig: GridPickerConfig,\n\tonClose: () => void,\n): void {\n\tcontainer.className += ' notectl-grid-picker';\n\n\tconst grid: HTMLDivElement = document.createElement('div');\n\tgrid.className = 'notectl-grid-picker__grid';\n\tgrid.setAttribute('role', 'grid');\n\tgrid.style.display = 'grid';\n\tgrid.style.gridTemplateColumns = `repeat(${config.maxCols}, 1fr)`;\n\tgrid.style.gap = '2px';\n\tgrid.style.padding = '8px';\n\n\tconst label: HTMLDivElement = document.createElement('div');\n\tlabel.className = 'notectl-grid-picker__label';\n\tlabel.textContent = '1 x 1';\n\tlabel.style.textAlign = 'center';\n\tlabel.style.padding = '4px';\n\tlabel.style.fontSize = '12px';\n\tlabel.setAttribute('aria-live', 'polite');\n\n\tfor (let r = 1; r <= config.maxRows; r++) {\n\t\tfor (let c = 1; c <= config.maxCols; c++) {\n\t\t\tconst cell: HTMLDivElement = document.createElement('div');\n\t\t\tcell.className = 'notectl-grid-picker__cell';\n\t\t\tcell.setAttribute('role', 'gridcell');\n\t\t\tcell.setAttribute('tabindex', '-1');\n\t\t\tcell.setAttribute('aria-label', `${r} x ${c}`);\n\t\t\tcell.style.width = '20px';\n\t\t\tcell.style.height = '20px';\n\t\t\tcell.style.border = '1px solid #ccc';\n\t\t\tcell.style.cursor = 'pointer';\n\t\t\tcell.setAttribute('data-row', String(r));\n\t\t\tcell.setAttribute('data-col', String(c));\n\n\t\t\tcell.addEventListener('mouseenter', () => {\n\t\t\t\thighlightCells(grid, r, c);\n\t\t\t\tlabel.textContent = `${r} x ${c}`;\n\t\t\t});\n\n\t\t\tcell.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tconfig.onSelect(r, c);\n\t\t\t\tonClose();\n\t\t\t});\n\n\t\t\tcell.addEventListener('click', () => {\n\t\t\t\tconfig.onSelect(r, c);\n\t\t\t\tonClose();\n\t\t\t});\n\n\t\t\tgrid.appendChild(cell);\n\t\t}\n\t}\n\n\tcontainer.appendChild(grid);\n\tcontainer.appendChild(label);\n}\n\n/**\n * Highlights grid cells up to the given row/col and updates the label.\n * Used by both mouse hover and keyboard navigation.\n */\nexport function highlightCells(grid: HTMLElement, targetRow: number, targetCol: number): void {\n\tconst cells: NodeListOf<Element> = grid.querySelectorAll('.notectl-grid-picker__cell');\n\tfor (const cell of cells) {\n\t\tconst r: number = Number(cell.getAttribute('data-row'));\n\t\tconst c: number = Number(cell.getAttribute('data-col'));\n\t\tcell.classList.toggle(HIGHLIGHTED_CLASS, r <= targetRow && c <= targetCol);\n\t}\n}\n\n/**\n * Renders a dropdown menu into the given container.\n * Calls `onClose` after an item is activated so the popup can be dismissed.\n */\nexport function renderDropdown(\n\tcontainer: HTMLElement,\n\tconfig: DropdownConfig,\n\texecuteCommand: (command: string) => void,\n\tonClose: () => void,\n): void {\n\tcontainer.classList.add('notectl-dropdown');\n\tcontainer.setAttribute('role', 'menu');\n\n\tfor (const item of config.items) {\n\t\tconst btn: HTMLButtonElement = document.createElement('button');\n\t\tbtn.type = 'button';\n\t\tbtn.className = 'notectl-dropdown__item';\n\t\tbtn.setAttribute('role', 'menuitem');\n\t\tbtn.setAttribute('tabindex', '-1');\n\n\t\tif (item.icon) {\n\t\t\tconst iconSpan: HTMLSpanElement = document.createElement('span');\n\t\t\ticonSpan.className = 'notectl-dropdown__item-icon';\n\t\t\ticonSpan.innerHTML = item.icon;\n\t\t\tbtn.appendChild(iconSpan);\n\t\t}\n\n\t\tconst labelSpan: HTMLSpanElement = document.createElement('span');\n\t\tlabelSpan.className = 'notectl-dropdown__item-label';\n\t\tlabelSpan.textContent = item.label;\n\t\tbtn.appendChild(labelSpan);\n\n\t\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\texecuteCommand(item.command);\n\t\t\tonClose();\n\t\t});\n\n\t\tbtn.addEventListener('click', () => {\n\t\t\texecuteCommand(item.command);\n\t\t\tonClose();\n\t\t});\n\n\t\tcontainer.appendChild(btn);\n\t}\n}\n\n/** Creates a toolbar group separator element. */\nexport function createSeparator(): HTMLSpanElement {\n\tconst sep: HTMLSpanElement = document.createElement('span');\n\tsep.className = 'notectl-toolbar-separator';\n\tsep.setAttribute('role', 'separator');\n\treturn sep;\n}\n","/**\n * ToolbarPopupController: manages popup lifecycle, positioning, keyboard\n * navigation, and auto-close for toolbar popups (grid pickers, dropdowns,\n * and custom popups).\n */\n\nimport type { PluginContext } from '../Plugin.js';\nimport type { ToolbarItem } from './ToolbarItem.js';\nimport { findNextDropdownItem, navigateGrid } from './ToolbarKeyboardNav.js';\nimport { highlightCells, renderDropdown, renderGridPicker } from './ToolbarRenderers.js';\n\nexport class ToolbarPopupController {\n\tprivate activePopup: HTMLElement | null = null;\n\tprivate activePopupButton: HTMLButtonElement | null = null;\n\tprivate closePopupHandler: ((e: MouseEvent) => void) | null = null;\n\tprivate readonly getActiveElement: () => Element | null;\n\n\tconstructor(getActiveElement: () => Element | null) {\n\t\tthis.getActiveElement = getActiveElement;\n\t}\n\n\t/** Whether a popup is currently open. */\n\tisOpen(): boolean {\n\t\treturn this.activePopup !== null;\n\t}\n\n\t/** Toggles a popup for the given toolbar button. */\n\ttoggle(button: HTMLButtonElement, item: ToolbarItem, context: PluginContext): void {\n\t\tif (this.activePopup) {\n\t\t\tthis.close();\n\t\t\treturn;\n\t\t}\n\n\t\tconst popup: HTMLDivElement = document.createElement('div');\n\t\tpopup.className = 'notectl-toolbar-popup';\n\n\t\tswitch (item.popupType) {\n\t\t\tcase 'gridPicker':\n\t\t\t\trenderGridPicker(popup, item.popupConfig, () => this.close());\n\t\t\t\tbreak;\n\t\t\tcase 'dropdown':\n\t\t\t\trenderDropdown(\n\t\t\t\t\tpopup,\n\t\t\t\t\titem.popupConfig,\n\t\t\t\t\t(cmd: string) => context.executeCommand(cmd),\n\t\t\t\t\t() => this.close(),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase 'custom':\n\t\t\t\titem.renderPopup(popup, context);\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis.positionAndAppend(popup, button);\n\n\t\tthis.activePopup = popup;\n\t\tthis.activePopupButton = button;\n\t\tbutton.classList.add('notectl-toolbar-btn--popup-open');\n\t\tbutton.setAttribute('aria-expanded', 'true');\n\n\t\tthis.focusFirstItem(popup);\n\n\t\tpopup.addEventListener('keydown', (e: KeyboardEvent) => this.handlePopupKeydown(e));\n\n\t\tthis.closePopupHandler = (e: MouseEvent) => {\n\t\t\tconst target: EventTarget | null = e.target;\n\t\t\tif (target instanceof Node && !popup.contains(target) && target !== button) {\n\t\t\t\tthis.close();\n\t\t\t}\n\t\t};\n\t\tsetTimeout(() => {\n\t\t\tif (this.closePopupHandler) {\n\t\t\t\tdocument.addEventListener('mousedown', this.closePopupHandler);\n\t\t\t}\n\t\t}, 0);\n\t}\n\n\t/** Closes the active popup and cleans up event listeners. */\n\tclose(): void {\n\t\tif (this.activePopupButton) {\n\t\t\tthis.activePopupButton.classList.remove('notectl-toolbar-btn--popup-open');\n\t\t\tthis.activePopupButton.setAttribute('aria-expanded', 'false');\n\t\t\tthis.activePopupButton = null;\n\t\t}\n\t\tif (this.activePopup) {\n\t\t\tthis.activePopup.remove();\n\t\t\tthis.activePopup = null;\n\t\t}\n\t\tif (this.closePopupHandler) {\n\t\t\tdocument.removeEventListener('mousedown', this.closePopupHandler);\n\t\t\tthis.closePopupHandler = null;\n\t\t}\n\t}\n\n\t/** Closes popup and restores focus to the trigger button. */\n\tcloseAndRestoreFocus(): void {\n\t\tconst triggerBtn: HTMLButtonElement | null = this.activePopupButton;\n\t\tthis.close();\n\t\ttriggerBtn?.focus();\n\t}\n\n\tdestroy(): void {\n\t\tthis.close();\n\t}\n\n\t// --- Positioning ---\n\n\tprivate positionAndAppend(popup: HTMLElement, button: HTMLButtonElement): void {\n\t\tconst rect: DOMRect = button.getBoundingClientRect();\n\t\tpopup.style.position = 'fixed';\n\t\tpopup.style.top = `${rect.bottom + 2}px`;\n\t\tpopup.style.left = `${rect.left}px`;\n\t\tpopup.style.zIndex = '10000';\n\n\t\tconst root: Node = button.getRootNode();\n\t\tif (root instanceof ShadowRoot) {\n\t\t\troot.appendChild(popup);\n\t\t} else {\n\t\t\tdocument.body.appendChild(popup);\n\t\t}\n\t}\n\n\t// --- Focus ---\n\n\tprivate focusFirstItem(popup: HTMLElement): void {\n\t\trequestAnimationFrame(() => {\n\t\t\tconst firstItem: HTMLElement | null =\n\t\t\t\tpopup.querySelector('[role=\"menuitem\"]') ??\n\t\t\t\tpopup.querySelector('.notectl-grid-picker__cell') ??\n\t\t\t\tpopup.querySelector('button');\n\t\t\tfirstItem?.focus();\n\t\t});\n\t}\n\n\t// --- Keyboard Navigation ---\n\n\tprivate handlePopupKeydown(e: KeyboardEvent): void {\n\t\tif (!this.activePopup) return;\n\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.closeAndRestoreFocus();\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.key === 'Tab') {\n\t\t\te.preventDefault();\n\t\t\tthis.closeAndRestoreFocus();\n\t\t\treturn;\n\t\t}\n\n\t\tconst menuItems: NodeListOf<Element> = this.activePopup.querySelectorAll('[role=\"menuitem\"]');\n\t\tif (menuItems.length > 0) {\n\t\t\tthis.handleDropdownKeydown(e, menuItems);\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasGrid: boolean = this.activePopup.querySelector('.notectl-grid-picker__cell') !== null;\n\t\tif (hasGrid) {\n\t\t\tthis.handleGridKeydown(e);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.handleCustomPopupKeydown(e);\n\t}\n\n\tprivate handleDropdownKeydown(e: KeyboardEvent, items: NodeListOf<Element>): void {\n\t\tconst itemArr: HTMLElement[] = Array.from(items) as HTMLElement[];\n\t\tconst current: number = itemArr.indexOf(this.getActiveElement() as HTMLElement);\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextDropdownItem(itemArr, current, 1);\n\t\t\t\titemArr[next]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextDropdownItem(itemArr, current, -1);\n\t\t\t\titemArr[prev]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst focused: HTMLElement | undefined = itemArr[current];\n\t\t\t\tif (focused) focused.click();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleGridKeydown(e: KeyboardEvent): void {\n\t\tconst focused: HTMLElement = this.getActiveElement() as HTMLElement;\n\t\tconst row: number = Number(focused?.getAttribute('data-row') ?? 1);\n\t\tconst col: number = Number(focused?.getAttribute('data-col') ?? 1);\n\n\t\tconst grid: Element | null =\n\t\t\tthis.activePopup?.querySelector('.notectl-grid-picker__grid') ?? null;\n\t\tif (!grid) return;\n\n\t\tconst lastCell: Element | null = grid.querySelector('.notectl-grid-picker__cell:last-child');\n\t\tconst maxCols: number = Number(lastCell?.getAttribute('data-col') ?? 1);\n\t\tconst maxRows: number = Number(lastCell?.getAttribute('data-row') ?? 1);\n\n\t\tif (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {\n\t\t\te.preventDefault();\n\t\t\tconst [newRow, newCol]: [number, number] = navigateGrid(\n\t\t\t\trow,\n\t\t\t\tcol,\n\t\t\t\tmaxRows,\n\t\t\t\tmaxCols,\n\t\t\t\te.key as 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight',\n\t\t\t);\n\t\t\tconst target: HTMLElement | null = grid.querySelector(\n\t\t\t\t`.notectl-grid-picker__cell[data-row=\"${newRow}\"][data-col=\"${newCol}\"]`,\n\t\t\t);\n\t\t\ttarget?.focus();\n\n\t\t\thighlightCells(grid as HTMLElement, newRow, newCol);\n\t\t\tconst label: Element | null =\n\t\t\t\tthis.activePopup?.querySelector('.notectl-grid-picker__label') ?? null;\n\t\t\tif (label) label.textContent = `${newRow} x ${newCol}`;\n\t\t}\n\n\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\te.preventDefault();\n\t\t\tfocused?.click();\n\t\t}\n\t}\n\n\tprivate handleCustomPopupKeydown(e: KeyboardEvent): void {\n\t\tif (!this.activePopup) return;\n\t\tconst buttons: HTMLButtonElement[] = Array.from(this.activePopup.querySelectorAll('button'));\n\t\tif (buttons.length === 0) return;\n\t\tconst active: HTMLElement = this.getActiveElement() as HTMLElement;\n\t\tconst currentIdx: number = buttons.indexOf(active as HTMLButtonElement);\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowDown': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextDropdownItem(buttons, currentIdx, 1);\n\t\t\t\tbuttons[next]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowUp': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextDropdownItem(buttons, currentIdx, -1);\n\t\t\t\tbuttons[prev]?.focus();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (active) {\n\t\t\t\t\tactive.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * ToolbarTooltip: manages the tooltip lifecycle for toolbar buttons.\n * Shows a tooltip after a short delay when hovering or focusing a button,\n * hides it when the cursor leaves or focus moves away.\n */\n\nconst TOOLTIP_DELAY_MS = 500;\n\nexport class ToolbarTooltip {\n\tprivate readonly element: HTMLElement;\n\tprivate timer: ReturnType<typeof setTimeout> | null = null;\n\tprivate target: HTMLButtonElement | null = null;\n\tprivate readonly isPopupActive: () => boolean;\n\n\tstatic readonly TOOLTIP_ID = 'notectl-toolbar-tooltip';\n\n\tconstructor(isPopupActive: () => boolean) {\n\t\tthis.isPopupActive = isPopupActive;\n\t\tthis.element = document.createElement('div');\n\t\tthis.element.className = 'notectl-toolbar-tooltip';\n\t\tthis.element.id = ToolbarTooltip.TOOLTIP_ID;\n\t\tthis.element.setAttribute('role', 'tooltip');\n\t\tthis.element.style.display = 'none';\n\t}\n\n\tshow(button: HTMLButtonElement): void {\n\t\tthis.hide();\n\n\t\tif (this.isPopupActive() || button.disabled) return;\n\n\t\tconst text: string | null = button.getAttribute('data-tooltip');\n\t\tif (!text) return;\n\n\t\tthis.target = button;\n\n\t\tthis.timer = setTimeout(() => {\n\t\t\tif (this.isPopupActive()) return;\n\n\t\t\tthis.element.textContent = text;\n\t\t\tthis.element.style.display = '';\n\n\t\t\tconst root: Node = button.getRootNode();\n\t\t\tif (root instanceof ShadowRoot && !this.element.parentNode) {\n\t\t\t\troot.appendChild(this.element);\n\t\t\t} else if (!(root instanceof ShadowRoot) && !this.element.parentNode) {\n\t\t\t\tdocument.body.appendChild(this.element);\n\t\t\t}\n\n\t\t\tbutton.setAttribute('aria-describedby', ToolbarTooltip.TOOLTIP_ID);\n\n\t\t\tconst rect: DOMRect = button.getBoundingClientRect();\n\t\t\tthis.element.style.position = 'fixed';\n\t\t\tthis.element.style.top = `${rect.bottom + 6}px`;\n\t\t\tthis.element.style.left = `${rect.left + rect.width / 2}px`;\n\t\t\tthis.element.style.transform = 'translateX(-50%)';\n\t\t}, TOOLTIP_DELAY_MS);\n\t}\n\n\thide(): void {\n\t\tif (this.timer) {\n\t\t\tclearTimeout(this.timer);\n\t\t\tthis.timer = null;\n\t\t}\n\t\tif (this.target) {\n\t\t\tthis.target.removeAttribute('aria-describedby');\n\t\t\tthis.target = null;\n\t\t}\n\t\tthis.element.style.display = 'none';\n\t}\n\n\tdestroy(): void {\n\t\tthis.hide();\n\t\tthis.element.remove();\n\t}\n}\n","/**\n * Toolbar plugin: renders toolbar items registered by other plugins.\n * Acts as a pure rendering engine — has no knowledge of specific features.\n * Supports buttons, dropdowns, grid pickers, and custom popups.\n * Implements WAI-ARIA Toolbar pattern with roving tabindex.\n */\n\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport { ServiceKey } from '../Plugin.js';\nimport type { Plugin, PluginConfig, PluginContext } from '../Plugin.js';\nimport type { ToolbarItem } from './ToolbarItem.js';\nimport {\n\tapplyRovingTabindex,\n\tfindFirstEnabled,\n\tfindLastEnabled,\n\tfindNextEnabled,\n} from './ToolbarKeyboardNav.js';\nimport { ToolbarPopupController } from './ToolbarPopupController.js';\nimport { createSeparator } from './ToolbarRenderers.js';\nimport { ToolbarTooltip } from './ToolbarTooltip.js';\n\n// --- Layout Config ---\n\nexport interface ToolbarLayoutConfig {\n\treadonly groups: ReadonlyArray<ReadonlyArray<string>>;\n}\n\n// --- Typed Service API ---\n\nexport interface ToolbarServiceAPI {\n\t/** Re-reads isActive/isEnabled from state and updates all buttons. */\n\trefresh(): void;\n\t/** Closes the currently open popup, if any. */\n\tclosePopup(): void;\n}\n\nexport const ToolbarServiceKey = new ServiceKey<ToolbarServiceAPI>('toolbar');\n\n// --- Plugin ---\n\ninterface ToolbarButton {\n\telement: HTMLButtonElement;\n\titem: ToolbarItem;\n}\n\nexport class ToolbarPlugin implements Plugin {\n\treadonly id = 'toolbar';\n\treadonly name = 'Toolbar';\n\treadonly priority = 10;\n\n\tprivate context: PluginContext | null = null;\n\tprivate toolbarElement: HTMLElement | null = null;\n\tprivate buttons: ToolbarButton[] = [];\n\tprivate readonly hiddenItems = new Set<string>();\n\tprivate readonly layoutConfig: ToolbarLayoutConfig | null;\n\tprivate focusedIndex = 0;\n\tprivate tooltip: ToolbarTooltip | null = null;\n\tprivate popupController: ToolbarPopupController | null = null;\n\n\tconstructor(layoutConfig?: ToolbarLayoutConfig) {\n\t\tthis.layoutConfig = layoutConfig ?? null;\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.context = context;\n\n\t\tthis.popupController = new ToolbarPopupController(() => this.getActiveElement());\n\t\tthis.tooltip = new ToolbarTooltip(() => this.popupController?.isOpen() ?? false);\n\n\t\tcontext.registerService(ToolbarServiceKey, {\n\t\t\trefresh: () => this.updateButtonStates(context.getState()),\n\t\t\tclosePopup: () => this.popupController?.close(),\n\t\t});\n\n\t\tthis.createToolbarElement();\n\t}\n\n\tonReady(): void {\n\t\tthis.renderItems();\n\t}\n\n\tdestroy(): void {\n\t\tthis.popupController?.destroy();\n\t\tthis.popupController = null;\n\t\tthis.tooltip?.destroy();\n\t\tthis.tooltip = null;\n\t\tif (this.toolbarElement) {\n\t\t\tthis.toolbarElement.remove();\n\t\t\tthis.toolbarElement = null;\n\t\t}\n\t\tthis.buttons = [];\n\t\tthis.context = null;\n\t}\n\n\tonStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tthis.updateButtonStates(newState);\n\t}\n\n\tonConfigure(config: PluginConfig): void {\n\t\tfor (const [key, value] of Object.entries(config)) {\n\t\t\tif (value === false) {\n\t\t\t\tthis.hiddenItems.add(key);\n\t\t\t} else {\n\t\t\t\tthis.hiddenItems.delete(key);\n\t\t\t}\n\t\t}\n\t\tthis.renderItems();\n\t}\n\n\t// --- Toolbar ---\n\n\tprivate createToolbarElement(): void {\n\t\tif (!this.context) return;\n\n\t\tif (this.toolbarElement) {\n\t\t\tthis.toolbarElement.remove();\n\t\t}\n\t\tthis.buttons = [];\n\n\t\tconst container: HTMLElement = this.context.getPluginContainer('top');\n\t\tthis.toolbarElement = document.createElement('div');\n\t\tthis.toolbarElement.setAttribute('role', 'toolbar');\n\t\tthis.toolbarElement.setAttribute('aria-label', 'Formatting options');\n\t\tthis.toolbarElement.className = 'notectl-toolbar';\n\n\t\tthis.toolbarElement.addEventListener('keydown', (e) => this.handleToolbarKeydown(e));\n\n\t\tcontainer.appendChild(this.toolbarElement);\n\t}\n\n\tprivate renderItems(): void {\n\t\tif (!this.context || !this.toolbarElement) return;\n\n\t\tfor (const btn of this.buttons) {\n\t\t\tbtn.element.remove();\n\t\t}\n\t\tthis.buttons = [];\n\n\t\tfor (const sep of this.toolbarElement.querySelectorAll('.notectl-toolbar-separator')) {\n\t\t\tsep.remove();\n\t\t}\n\n\t\tif (this.layoutConfig) {\n\t\t\tthis.renderItemsByLayout();\n\t\t} else {\n\t\t\tthis.renderItemsByPriority();\n\t\t}\n\n\t\tif (this.buttons.length > 0 && !this.toolbarElement.parentElement) {\n\t\t\tconst container: HTMLElement = this.context.getPluginContainer('top');\n\t\t\tcontainer.appendChild(this.toolbarElement);\n\t\t}\n\n\t\tthis.initRovingTabindex();\n\t\tthis.updateButtonStates(this.context.getState());\n\t}\n\n\t// --- Roving Tabindex ---\n\n\tprivate initRovingTabindex(): void {\n\t\tconst elements: HTMLButtonElement[] = this.buttons.map((b) => b.element);\n\t\tconst first: number = findFirstEnabled(elements);\n\t\tthis.focusedIndex = first >= 0 ? first : 0;\n\t\tapplyRovingTabindex(elements, this.focusedIndex);\n\t}\n\n\tprivate setRovingFocus(index: number): void {\n\t\tif (index < 0 || index >= this.buttons.length) return;\n\t\tthis.focusedIndex = index;\n\t\tconst elements: HTMLButtonElement[] = this.buttons.map((b) => b.element);\n\t\tapplyRovingTabindex(elements, index);\n\t\telements[index]?.focus();\n\t}\n\n\t/** Returns the active element, respecting shadow DOM boundaries. */\n\tprivate getActiveElement(): Element | null {\n\t\tconst root: Node | undefined = this.toolbarElement?.getRootNode();\n\t\tif (root instanceof ShadowRoot) {\n\t\t\treturn root.activeElement;\n\t\t}\n\t\treturn document.activeElement;\n\t}\n\n\tprivate syncFocusedIndex(): void {\n\t\tconst active: Element | null = this.getActiveElement();\n\t\tconst idx: number = this.buttons.findIndex((b) => b.element === active);\n\t\tif (idx >= 0) {\n\t\t\tthis.focusedIndex = idx;\n\t\t}\n\t}\n\n\t// --- Toolbar Keyboard ---\n\n\tprivate handleToolbarKeydown(e: KeyboardEvent): void {\n\t\tconst elements: HTMLButtonElement[] = this.buttons.map((b) => b.element);\n\t\tif (elements.length === 0) return;\n\n\t\tthis.syncFocusedIndex();\n\n\t\tswitch (e.key) {\n\t\t\tcase 'ArrowRight': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst next: number = findNextEnabled(elements, this.focusedIndex, 1);\n\t\t\t\tthis.setRovingFocus(next);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'ArrowLeft': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst prev: number = findNextEnabled(elements, this.focusedIndex, -1);\n\t\t\t\tthis.setRovingFocus(prev);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Home': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst first: number = findFirstEnabled(elements);\n\t\t\t\tif (first >= 0) this.setRovingFocus(first);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'End': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst last: number = findLastEnabled(elements);\n\t\t\t\tif (last >= 0) this.setRovingFocus(last);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'Enter':\n\t\t\tcase ' ': {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst btn: ToolbarButton | undefined = this.buttons[this.focusedIndex];\n\t\t\t\tif (btn) this.activateButton(btn.element, btn.item);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Activates a toolbar button (shared between mouse click and keyboard). */\n\tprivate activateButton(btn: HTMLButtonElement, item: ToolbarItem): void {\n\t\tthis.tooltip?.hide();\n\t\tif (item.popupType && this.context) {\n\t\t\tthis.popupController?.toggle(btn, item, this.context);\n\t\t} else {\n\t\t\tthis.context?.executeCommand(item.command);\n\t\t}\n\t}\n\n\t// --- Layout Rendering ---\n\n\tprivate renderItemsByLayout(): void {\n\t\tif (!this.context || !this.toolbarElement || !this.layoutConfig) return;\n\n\t\tconst registry = this.context.getSchemaRegistry();\n\t\tlet firstGroup = true;\n\n\t\tfor (const groupPluginIds of this.layoutConfig.groups) {\n\t\t\tconst groupItems: ToolbarItem[] = [];\n\t\t\tfor (const pId of groupPluginIds) {\n\t\t\t\tconst items: ToolbarItem[] = registry\n\t\t\t\t\t.getToolbarItemsByPlugin(pId)\n\t\t\t\t\t.filter((item) => !this.hiddenItems.has(item.id));\n\t\t\t\titems.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));\n\t\t\t\tgroupItems.push(...items);\n\t\t\t}\n\n\t\t\tif (groupItems.length === 0) continue;\n\n\t\t\tif (!firstGroup) {\n\t\t\t\tthis.toolbarElement.appendChild(createSeparator());\n\t\t\t}\n\t\t\tfirstGroup = false;\n\n\t\t\tfor (const item of groupItems) {\n\t\t\t\tconst btn: ToolbarButton = this.createButton(item);\n\t\t\t\tthis.toolbarElement.appendChild(btn.element);\n\t\t\t\tthis.buttons.push(btn);\n\t\t\t}\n\t\t}\n\n\t\tif (this.buttons.length === 0) {\n\t\t\tthis.toolbarElement.remove();\n\t\t}\n\t}\n\n\tprivate renderItemsByPriority(): void {\n\t\tif (!this.context || !this.toolbarElement) return;\n\n\t\tconst registry = this.context.getSchemaRegistry();\n\t\tconst items: ToolbarItem[] = registry\n\t\t\t.getToolbarItems()\n\t\t\t.filter((item) => !this.hiddenItems.has(item.id));\n\t\tif (items.length === 0) {\n\t\t\tthis.toolbarElement.remove();\n\t\t\treturn;\n\t\t}\n\n\t\tconst sorted: ToolbarItem[] = [...items].sort(\n\t\t\t(a, b) => (a.priority ?? 100) - (b.priority ?? 100),\n\t\t);\n\n\t\tconst hasSeparatorAfter: boolean = sorted.some((item) => item.separatorAfter);\n\n\t\tif (hasSeparatorAfter) {\n\t\t\tfor (let i = 0; i < sorted.length; i++) {\n\t\t\t\tconst item: ToolbarItem | undefined = sorted[i];\n\t\t\t\tif (!item) continue;\n\t\t\t\tconst btn: ToolbarButton = this.createButton(item);\n\t\t\t\tthis.toolbarElement.appendChild(btn.element);\n\t\t\t\tthis.buttons.push(btn);\n\n\t\t\t\tif (item.separatorAfter && i < sorted.length - 1) {\n\t\t\t\t\tthis.toolbarElement.appendChild(createSeparator());\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst groups = new Map<string, ToolbarItem[]>();\n\t\t\tfor (const item of sorted) {\n\t\t\t\tconst list: ToolbarItem[] = groups.get(item.group) ?? [];\n\t\t\t\tlist.push(item);\n\t\t\t\tgroups.set(item.group, list);\n\t\t\t}\n\n\t\t\tlet firstGroup = true;\n\t\t\tfor (const [, groupItems] of groups) {\n\t\t\t\tif (!firstGroup) {\n\t\t\t\t\tthis.toolbarElement.appendChild(createSeparator());\n\t\t\t\t}\n\t\t\t\tfirstGroup = false;\n\n\t\t\t\tfor (const item of groupItems) {\n\t\t\t\t\tconst btn: ToolbarButton = this.createButton(item);\n\t\t\t\t\tthis.toolbarElement.appendChild(btn.element);\n\t\t\t\t\tthis.buttons.push(btn);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Button Creation ---\n\n\tprivate createButton(item: ToolbarItem): ToolbarButton {\n\t\tconst btn: HTMLButtonElement = document.createElement('button');\n\t\tbtn.type = 'button';\n\t\tbtn.className = `notectl-toolbar-btn notectl-toolbar-btn--${item.id}`;\n\t\tbtn.setAttribute('aria-pressed', 'false');\n\t\tbtn.setAttribute('aria-label', item.label);\n\t\tbtn.setAttribute('data-toolbar-item', item.id);\n\t\tbtn.setAttribute('data-tooltip', item.tooltip ?? item.label);\n\n\t\tif (item.popupType) {\n\t\t\tbtn.setAttribute('aria-haspopup', 'true');\n\t\t\tbtn.setAttribute('aria-expanded', 'false');\n\t\t}\n\n\t\tconst span: HTMLSpanElement = document.createElement('span');\n\t\tspan.className = 'notectl-toolbar-btn__icon';\n\t\tspan.innerHTML = item.icon;\n\t\tbtn.appendChild(span);\n\n\t\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\tthis.activateButton(btn, item);\n\t\t});\n\n\t\tbtn.addEventListener('mouseenter', () => this.tooltip?.show(btn));\n\t\tbtn.addEventListener('mouseleave', () => this.tooltip?.hide());\n\t\tbtn.addEventListener('focus', () => this.tooltip?.show(btn));\n\t\tbtn.addEventListener('blur', () => this.tooltip?.hide());\n\n\t\treturn { element: btn, item };\n\t}\n\n\t// --- Button State Updates ---\n\n\tprivate updateButtonStates(state: EditorState): void {\n\t\tfor (const btn of this.buttons) {\n\t\t\tconst active: boolean = btn.item.isActive?.(state) ?? false;\n\t\t\tconst enabled: boolean = btn.item.isEnabled?.(state) ?? true;\n\t\t\tbtn.element.setAttribute('aria-pressed', String(active));\n\t\t\tbtn.element.classList.toggle('notectl-toolbar-btn--active', active);\n\t\t\tbtn.element.disabled = !enabled;\n\t\t\tif (!enabled) {\n\t\t\t\tbtn.element.setAttribute('aria-disabled', 'true');\n\t\t\t} else {\n\t\t\t\tbtn.element.removeAttribute('aria-disabled');\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * ToolbarItem: describes a toolbar button registered by a plugin.\n */\n\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { PluginContext } from '../Plugin.js';\n\nexport interface GridPickerConfig {\n\treadonly maxRows: number;\n\treadonly maxCols: number;\n\tonSelect(rows: number, cols: number): void;\n}\n\nexport interface DropdownConfig {\n\treadonly items: readonly { label: string; command: string; icon?: string }[];\n}\n\nexport type ToolbarGroup = 'format' | 'block' | 'insert' | (string & {});\nexport type PopupType = 'gridPicker' | 'dropdown' | 'custom';\n\ninterface ToolbarItemBase {\n\treadonly id: string;\n\t/** Grouping key: 'format' | 'insert' | 'block' or custom. */\n\treadonly group: ToolbarGroup;\n\t/** Icon content: inline SVG markup or plain text. Rendered via innerHTML. */\n\treadonly icon: string;\n\treadonly label: string;\n\t/** Tooltip shown on hover, e.g. \"Bold (Ctrl+B)\". Falls back to label. */\n\treadonly tooltip?: string;\n\t/** Command name to execute on click. */\n\treadonly command: string;\n\t/**\n\t * Lower priority renders further left.\n\t * @deprecated Use the declarative `toolbar` config on `createEditor()` instead.\n\t */\n\treadonly priority?: number;\n\t/**\n\t * When true, a visual separator is rendered after this item.\n\t * @deprecated Use the declarative `toolbar` config on `createEditor()` instead.\n\t */\n\treadonly separatorAfter?: boolean;\n\tisActive?(state: EditorState): boolean;\n\tisEnabled?(state: EditorState): boolean;\n}\n\ninterface ToolbarItemNoPopup extends ToolbarItemBase {\n\treadonly popupType?: undefined;\n}\n\ninterface ToolbarItemGridPicker extends ToolbarItemBase {\n\treadonly popupType: 'gridPicker';\n\treadonly popupConfig: GridPickerConfig;\n}\n\ninterface ToolbarItemDropdown extends ToolbarItemBase {\n\treadonly popupType: 'dropdown';\n\treadonly popupConfig: DropdownConfig;\n}\n\ninterface ToolbarItemCustomPopup extends ToolbarItemBase {\n\treadonly popupType: 'custom';\n\trenderPopup(container: HTMLElement, context: PluginContext): void;\n}\n\nexport type ToolbarItem =\n\t| ToolbarItemNoPopup\n\t| ToolbarItemGridPicker\n\t| ToolbarItemDropdown\n\t| ToolbarItemCustomPopup;\n\n/**\n * Formats a keymap binding string into a human-readable shortcut,\n * using platform-appropriate modifier symbols (⌘ on Mac, Ctrl on others).\n *\n * @example formatShortcut('Mod-B') → \"Ctrl+B\" or \"⌘B\"\n * @example formatShortcut('Mod-Shift-X') → \"Ctrl+Shift+X\" or \"⌘⇧X\"\n */\nexport function formatShortcut(binding: string): string {\n\tconst isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.platform);\n\tif (isMac) {\n\t\treturn binding\n\t\t\t.replace(/Mod/g, '⌘')\n\t\t\t.replace(/Shift/g, '⇧')\n\t\t\t.replace(/Alt/g, '⌥')\n\t\t\t.replace(/-/g, '');\n\t}\n\treturn binding.replace(/Mod/g, 'Ctrl').replace(/-/g, '+');\n}\n","/**\n * TextFormattingPlugin: registers inline marks (bold, italic, underline)\n * with their MarkSpecs, toggle commands, keyboard shortcuts, and toolbar items.\n *\n * This plugin is data-driven — each mark type is defined declaratively and\n * all registrations (MarkSpec, command, keymap, toolbar item) are derived\n * from the same definition.\n *\n * Supports two separate config dimensions:\n * - Feature config (bold/italic/underline): controls whether the mark is\n * registered in the schema. When disabled, the keyboard shortcut does nothing.\n * - Toolbar config: controls whether the toolbar button is visible.\n * When a feature is disabled but toolbar is enabled, the button renders as disabled.\n */\n\nimport { isMarkActive, toggleMark } from '../../commands/Commands.js';\nimport type { ParseRule } from '../../model/ParseRule.js';\nimport type { SanitizeConfig } from '../../model/SanitizeConfig.js';\nimport { markType as mkType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\n\n// --- Configuration ---\n\n/** Controls toolbar button visibility per mark. */\nexport interface TextFormattingToolbarConfig {\n\treadonly bold?: boolean;\n\treadonly italic?: boolean;\n\treadonly underline?: boolean;\n}\n\n/** Controls which inline marks are enabled and which toolbar buttons are shown. */\nexport interface TextFormattingConfig {\n\treadonly bold: boolean;\n\treadonly italic: boolean;\n\treadonly underline: boolean;\n\treadonly toolbar?: TextFormattingToolbarConfig;\n\t/** When true, a separator is rendered after the last text-formatting toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: TextFormattingConfig = {\n\tbold: true,\n\titalic: true,\n\tunderline: true,\n};\n\n// --- Mark Definitions ---\n\ninterface MarkDefinition {\n\treadonly type: string;\n\treadonly configKey: keyof Omit<TextFormattingConfig, 'toolbar' | 'separatorAfter'>;\n\treadonly rank: number;\n\treadonly tag: string;\n\treadonly label: string;\n\treadonly icon: string;\n\treadonly keyBinding: string;\n\treadonly toHTMLString: (content: string) => string;\n\treadonly parseHTML: readonly ParseRule[];\n\treadonly sanitize: SanitizeConfig;\n}\n\nconst BOLD_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z\"/></svg>';\nconst ITALIC_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z\"/></svg>';\nconst UNDERLINE_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z\"/></svg>';\n\nconst MARK_DEFINITIONS: readonly MarkDefinition[] = [\n\t{\n\t\ttype: 'bold',\n\t\tconfigKey: 'bold',\n\t\trank: 0,\n\t\ttag: 'strong',\n\t\tlabel: 'Bold',\n\t\ticon: BOLD_ICON,\n\t\tkeyBinding: 'Mod-B',\n\t\ttoHTMLString: (content) => `<strong>${content}</strong>`,\n\t\tparseHTML: [{ tag: 'strong' }, { tag: 'b' }],\n\t\tsanitize: { tags: ['strong', 'b'] },\n\t},\n\t{\n\t\ttype: 'italic',\n\t\tconfigKey: 'italic',\n\t\trank: 1,\n\t\ttag: 'em',\n\t\tlabel: 'Italic',\n\t\ticon: ITALIC_ICON,\n\t\tkeyBinding: 'Mod-I',\n\t\ttoHTMLString: (content) => `<em>${content}</em>`,\n\t\tparseHTML: [{ tag: 'em' }, { tag: 'i' }],\n\t\tsanitize: { tags: ['em', 'i'] },\n\t},\n\t{\n\t\ttype: 'underline',\n\t\tconfigKey: 'underline',\n\t\trank: 2,\n\t\ttag: 'u',\n\t\tlabel: 'Underline',\n\t\ticon: UNDERLINE_ICON,\n\t\tkeyBinding: 'Mod-U',\n\t\ttoHTMLString: (content) => `<u>${content}</u>`,\n\t\tparseHTML: [{ tag: 'u' }],\n\t\tsanitize: { tags: ['u'] },\n\t},\n];\n\n// --- Plugin ---\n\nexport class TextFormattingPlugin implements Plugin {\n\treadonly id = 'text-formatting';\n\treadonly name = 'Text Formatting';\n\treadonly priority = 20;\n\n\tprivate readonly config: TextFormattingConfig;\n\n\tconstructor(config?: Partial<TextFormattingConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tconst enabledMarks = MARK_DEFINITIONS.filter((def) => this.config[def.configKey]);\n\n\t\t// Determine which marks will have visible toolbar items\n\t\tconst visibleToolbarMarks = enabledMarks.filter((def) => this.isToolbarVisible(def.configKey));\n\t\tconst lastVisibleMark = visibleToolbarMarks.at(-1);\n\n\t\tfor (const def of enabledMarks) {\n\t\t\tconst isSeparatorTarget = this.config.separatorAfter && def === lastVisibleMark;\n\t\t\tthis.registerMark(context, def, isSeparatorTarget);\n\t\t}\n\n\t\tthis.registerKeymaps(context, enabledMarks);\n\n\t\t// Register disabled placeholder buttons for marks that are disabled\n\t\t// as features but explicitly requested in the toolbar config\n\t\tthis.registerDisabledToolbarItems(context);\n\t}\n\n\tprivate registerMark(\n\t\tcontext: PluginContext,\n\t\tdef: MarkDefinition,\n\t\tseparatorAfter?: boolean,\n\t): void {\n\t\tconst commandName = toCommandName(def.type);\n\t\tconst toolbarVisible = this.isToolbarVisible(def.configKey);\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: def.type,\n\t\t\trank: def.rank,\n\t\t\ttoDOM() {\n\t\t\t\treturn document.createElement(def.tag);\n\t\t\t},\n\t\t\ttoHTMLString: (_mark, content) => def.toHTMLString(content),\n\t\t\tparseHTML: def.parseHTML,\n\t\t\tsanitize: def.sanitize,\n\t\t});\n\n\t\tcontext.registerCommand(commandName, () => {\n\t\t\tconst tr = toggleMark(context.getState(), mkType(def.type));\n\t\t\tif (tr) {\n\t\t\t\tcontext.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\tif (toolbarVisible) {\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: def.type,\n\t\t\t\tgroup: 'format',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel: def.label,\n\t\t\t\ttooltip: `${def.label} (${formatShortcut(def.keyBinding)})`,\n\t\t\t\tcommand: commandName,\n\t\t\t\tpriority: def.rank * 10 + 10,\n\t\t\t\tseparatorAfter,\n\t\t\t\tisActive: (state) => isMarkActive(state, mkType(def.type)),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext, marks: readonly MarkDefinition[]): void {\n\t\tconst keymap: Record<string, () => boolean> = {};\n\t\tfor (const def of marks) {\n\t\t\tconst commandName = toCommandName(def.type);\n\t\t\tkeymap[def.keyBinding] = () => context.executeCommand(commandName);\n\t\t}\n\t\tif (Object.keys(keymap).length > 0) {\n\t\t\tcontext.registerKeymap(keymap);\n\t\t}\n\t}\n\n\t/**\n\t * Registers disabled toolbar buttons for marks whose feature is disabled\n\t * but whose toolbar button is explicitly requested.\n\t */\n\tprivate registerDisabledToolbarItems(context: PluginContext): void {\n\t\tif (!this.config.toolbar) return;\n\n\t\tfor (const def of MARK_DEFINITIONS) {\n\t\t\tconst featureEnabled = this.config[def.configKey];\n\t\t\tconst toolbarVisible = this.config.toolbar[def.configKey] ?? true;\n\n\t\t\tif (!featureEnabled && toolbarVisible) {\n\t\t\t\tcontext.registerToolbarItem({\n\t\t\t\t\tid: def.type,\n\t\t\t\t\tgroup: 'format',\n\t\t\t\t\ticon: def.icon,\n\t\t\t\t\tlabel: def.label,\n\t\t\t\t\tcommand: toCommandName(def.type),\n\t\t\t\t\tpriority: def.rank * 10 + 10,\n\t\t\t\t\tisEnabled: () => false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Checks if a toolbar button should be visible for a given mark. */\n\tprivate isToolbarVisible(\n\t\tconfigKey: keyof Omit<TextFormattingConfig, 'toolbar' | 'separatorAfter'>,\n\t): boolean {\n\t\tif (!this.config.toolbar) return true;\n\t\treturn this.config.toolbar[configKey] ?? true;\n\t}\n}\n\n/** Converts a mark type to its toggle command name (e.g. 'bold' → 'toggleBold'). */\nfunction toCommandName(markType: string): string {\n\treturn `toggle${markType.charAt(0).toUpperCase()}${markType.slice(1)}`;\n}\n","/**\n * HeadingPlugin: registers Title, Subtitle, and H1–H6 heading block types\n * with NodeSpec, toggle commands, keyboard shortcuts, input rules, and a\n * combobox-style toolbar dropdown that reflects the current block type.\n */\n\nimport type { BlockNode, Mark } from '../../model/Document.js';\nimport {\n\tgenerateBlockId,\n\tgetBlockLength,\n\tgetBlockText,\n\tgetInlineChildren,\n\tisTextNode,\n} from '../../model/Document.js';\nimport { createBlockElement } from '../../model/NodeSpec.js';\nimport { createCollapsedSelection, isCollapsed, isNodeSelection } from '../../model/Selection.js';\nimport { type NodeTypeName, nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction, TransactionBuilder } from '../../state/Transaction.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport type { BlockAlignment } from '../alignment/AlignmentPlugin.js';\nimport { ToolbarServiceKey } from '../toolbar/ToolbarPlugin.js';\nimport type { PickerEntryStyle } from './BlockTypePickerEntry.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\theading: { level: HeadingLevel; align?: BlockAlignment };\n\t\ttitle: { align?: BlockAlignment };\n\t\tsubtitle: { align?: BlockAlignment };\n\t}\n}\n\n// --- Configuration ---\n\nexport type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\n\nexport interface HeadingConfig {\n\t/** Which heading levels to enable. Defaults to [1, 2, 3, 4, 5, 6]. */\n\treadonly levels: readonly HeadingLevel[];\n\t/** When true, a separator is rendered after the heading toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: HeadingConfig = {\n\tlevels: [1, 2, 3, 4, 5, 6],\n};\n\n// --- Heading Tag Mapping ---\n\nconst HEADING_TAGS: Record<HeadingLevel, string> = {\n\t1: 'h1',\n\t2: 'h2',\n\t3: 'h3',\n\t4: 'h4',\n\t5: 'h5',\n\t6: 'h6',\n};\n\n// --- Display Labels ---\n\nconst HEADING_LABELS: Record<HeadingLevel, string> = {\n\t1: 'Heading 1',\n\t2: 'Heading 2',\n\t3: 'Heading 3',\n\t4: 'Heading 4',\n\t5: 'Heading 5',\n\t6: 'Heading 6',\n};\n\nconst TITLE_LABEL = 'Title';\nconst SUBTITLE_LABEL = 'Subtitle';\nconst PARAGRAPH_LABEL = 'Paragraph';\n\n// --- Plugin ---\n\nexport class HeadingPlugin implements Plugin {\n\treadonly id = 'heading';\n\treadonly name = 'Heading';\n\treadonly priority = 30;\n\n\tprivate readonly config: HeadingConfig;\n\tprivate context: PluginContext | null = null;\n\tprivate comboLabel: HTMLSpanElement | null = null;\n\n\tconstructor(config?: Partial<HeadingConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.context = context;\n\t\tthis.registerNodeSpecs(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerInputRules(context);\n\t\tthis.registerPickerEntries(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tdestroy(): void {\n\t\tthis.context = null;\n\t\tthis.comboLabel = null;\n\t}\n\n\tonStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tthis.updateComboLabel(newState);\n\t}\n\n\tprivate registerNodeSpecs(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'title',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\texcludeMarks: ['fontSize'],\n\t\t\ttoDOM(node) {\n\t\t\t\tconst el = createBlockElement('h1', node.id);\n\t\t\t\tel.classList.add('notectl-title');\n\t\t\t\treturn el;\n\t\t\t},\n\t\t\ttoHTML(_node, content) {\n\t\t\t\treturn `<h1>${content || '<br>'}</h1>`;\n\t\t\t},\n\t\t\tsanitize: { tags: ['h1'] },\n\t\t});\n\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'subtitle',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\texcludeMarks: ['fontSize'],\n\t\t\ttoDOM(node) {\n\t\t\t\tconst el = createBlockElement('h2', node.id);\n\t\t\t\tel.classList.add('notectl-subtitle');\n\t\t\t\treturn el;\n\t\t\t},\n\t\t\ttoHTML(_node, content) {\n\t\t\t\treturn `<h2>${content || '<br>'}</h2>`;\n\t\t\t},\n\t\t\tsanitize: { tags: ['h2'] },\n\t\t});\n\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'heading',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\texcludeMarks: ['fontSize'],\n\t\t\tattrs: {\n\t\t\t\tlevel: { default: 1 },\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst level = node.attrs?.level ?? 1;\n\t\t\t\tconst tag = HEADING_TAGS[level] ?? 'h1';\n\t\t\t\treturn createBlockElement(tag, node.id);\n\t\t\t},\n\t\t\ttoHTML(node, content) {\n\t\t\t\tconst level = (node.attrs?.level ?? 1) as HeadingLevel;\n\t\t\t\tconst tag: string = HEADING_TAGS[level] ?? 'h1';\n\t\t\t\treturn `<${tag}>${content || '<br>'}</${tag}>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{ tag: 'h1', getAttrs: () => ({ level: 1 }) },\n\t\t\t\t{ tag: 'h2', getAttrs: () => ({ level: 2 }) },\n\t\t\t\t{ tag: 'h3', getAttrs: () => ({ level: 3 }) },\n\t\t\t\t{ tag: 'h4', getAttrs: () => ({ level: 4 }) },\n\t\t\t\t{ tag: 'h5', getAttrs: () => ({ level: 5 }) },\n\t\t\t\t{ tag: 'h6', getAttrs: () => ({ level: 6 }) },\n\t\t\t],\n\t\t\tsanitize: { tags: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\t// Title / Subtitle\n\t\tcontext.registerCommand('setTitle', () => {\n\t\t\treturn this.toggleSpecialBlock(context, 'title');\n\t\t});\n\n\t\tcontext.registerCommand('setSubtitle', () => {\n\t\t\treturn this.toggleSpecialBlock(context, 'subtitle');\n\t\t});\n\n\t\t// Heading levels\n\t\tfor (const level of this.config.levels) {\n\t\t\tcontext.registerCommand(`setHeading${level}`, () => {\n\t\t\t\treturn this.toggleHeading(context, level);\n\t\t\t});\n\t\t}\n\n\t\t// Generic command that toggles back to paragraph\n\t\tcontext.registerCommand('toggleHeading', () => {\n\t\t\treturn this.toggleHeading(context, 1);\n\t\t});\n\n\t\t// Set paragraph (reset heading)\n\t\tcontext.registerCommand('setParagraph', () => {\n\t\t\treturn this.setBlockType(context, nodeType('paragraph'));\n\t\t});\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tconst keymap: Record<string, () => boolean> = {\n\t\t\tEnter: () => this.handleEnter(context),\n\t\t};\n\n\t\tfor (const level of this.config.levels) {\n\t\t\tif (level <= 6) {\n\t\t\t\tkeymap[`Mod-Shift-${level}`] = () => context.executeCommand(`setHeading${level}`);\n\t\t\t}\n\t\t}\n\n\t\tcontext.registerKeymap(keymap);\n\t}\n\n\tprivate registerInputRules(context: PluginContext): void {\n\t\tfor (const level of this.config.levels) {\n\t\t\tconst hashes = '#'.repeat(level);\n\t\t\tconst pattern = new RegExp(`^${hashes} $`);\n\n\t\t\tcontext.registerInputRule({\n\t\t\t\tpattern,\n\t\t\t\thandler(state, _match, start, _end) {\n\t\t\t\t\tconst sel = state.selection;\n\t\t\t\t\tif (isNodeSelection(sel)) return null;\n\t\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\t\treturn state\n\t\t\t\t\t\t.transaction('input')\n\t\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + level + 1)\n\t\t\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('heading'), { level })\n\t\t\t\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, 0))\n\t\t\t\t\t\t.build();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerPickerEntries(context: PluginContext): void {\n\t\tcontext.registerBlockTypePickerEntry({\n\t\t\tid: 'paragraph',\n\t\t\tlabel: PARAGRAPH_LABEL,\n\t\t\tcommand: 'setParagraph',\n\t\t\tpriority: 10,\n\t\t\tisActive: (state) => {\n\t\t\t\tif (isNodeSelection(state.selection)) return false;\n\t\t\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\t\t\treturn block?.type === 'paragraph';\n\t\t\t},\n\t\t});\n\n\t\tcontext.registerBlockTypePickerEntry({\n\t\t\tid: 'title',\n\t\t\tlabel: TITLE_LABEL,\n\t\t\tcommand: 'setTitle',\n\t\t\tpriority: 20,\n\t\t\tstyle: { fontSize: '1.6em', fontWeight: '700' },\n\t\t\tisActive: (state) => {\n\t\t\t\tif (isNodeSelection(state.selection)) return false;\n\t\t\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\t\t\treturn block?.type === 'title';\n\t\t\t},\n\t\t});\n\n\t\tcontext.registerBlockTypePickerEntry({\n\t\t\tid: 'subtitle',\n\t\t\tlabel: SUBTITLE_LABEL,\n\t\t\tcommand: 'setSubtitle',\n\t\t\tpriority: 30,\n\t\t\tstyle: { fontSize: '1.3em', fontWeight: '500' },\n\t\t\tisActive: (state) => {\n\t\t\t\tif (isNodeSelection(state.selection)) return false;\n\t\t\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\t\t\treturn block?.type === 'subtitle';\n\t\t\t},\n\t\t});\n\n\t\tfor (const level of this.config.levels) {\n\t\t\tcontext.registerBlockTypePickerEntry({\n\t\t\t\tid: `heading-${level}`,\n\t\t\t\tlabel: HEADING_LABELS[level],\n\t\t\t\tcommand: `setHeading${level}`,\n\t\t\t\tpriority: 100 + level,\n\t\t\t\tstyle: { fontSize: `${1.4 - level * 0.1}em`, fontWeight: '600' },\n\t\t\t\tisActive: (state) => {\n\t\t\t\t\tif (isNodeSelection(state.selection)) return false;\n\t\t\t\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\t\t\t\treturn block?.type === 'heading' && block.attrs?.level === level;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon: string = `<span class=\"notectl-heading-select__label\" data-heading-label>${PARAGRAPH_LABEL}</span><span class=\"notectl-heading-select__arrow\">\\u25BE</span>`;\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'heading',\n\t\t\tgroup: 'block',\n\t\t\ticon,\n\t\t\tlabel: 'Block Type',\n\t\t\ttooltip: 'Block Type',\n\t\t\tcommand: 'setParagraph',\n\t\t\tpriority: 50,\n\t\t\tpopupType: 'custom',\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\trenderPopup: (container, ctx) => {\n\t\t\t\tthis.renderHeadingPopup(container, ctx);\n\t\t\t},\n\t\t\tisActive: (state) => {\n\t\t\t\tconst entries = context.getSchemaRegistry().getBlockTypePickerEntries();\n\t\t\t\treturn entries.some((entry) => entry.id !== 'paragraph' && entry.isActive(state));\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- Combo Label ---\n\n\tprivate updateComboLabel(state: EditorState): void {\n\t\tif (!this.comboLabel) {\n\t\t\tconst container: HTMLElement | undefined = this.context?.getPluginContainer('top');\n\t\t\tif (!container) return;\n\t\t\tthis.comboLabel = container.querySelector<HTMLSpanElement>('[data-heading-label]') ?? null;\n\t\t\tif (!this.comboLabel) return;\n\t\t}\n\n\t\tthis.comboLabel.textContent = this.getActiveLabel(state);\n\t}\n\n\tprivate getActiveLabel(state: EditorState): string {\n\t\tif (isNodeSelection(state.selection)) return PARAGRAPH_LABEL;\n\t\tconst entries = this.context?.getSchemaRegistry().getBlockTypePickerEntries() ?? [];\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.isActive(state)) return entry.label;\n\t\t}\n\t\treturn PARAGRAPH_LABEL;\n\t}\n\n\t// --- Custom Popup ---\n\n\tprivate dismissPopup(): void {\n\t\tconst toolbar = this.context?.getService(ToolbarServiceKey);\n\t\ttoolbar?.closePopup();\n\t}\n\n\tprivate renderHeadingPopup(container: HTMLElement, context: PluginContext): void {\n\t\tcontainer.classList.add('notectl-heading-picker');\n\n\t\tconst state: EditorState = context.getState();\n\t\tif (isNodeSelection(state.selection)) return;\n\n\t\tconst list: HTMLDivElement = document.createElement('div');\n\t\tlist.className = 'notectl-heading-picker__list';\n\t\tlist.setAttribute('role', 'listbox');\n\t\tlist.setAttribute('aria-label', 'Block types');\n\n\t\tconst entries = context.getSchemaRegistry().getBlockTypePickerEntries();\n\t\tfor (const entry of entries) {\n\t\t\tconst active: boolean = entry.isActive(state);\n\t\t\tlist.appendChild(\n\t\t\t\tthis.createPickerItem(\n\t\t\t\t\tentry.label,\n\t\t\t\t\tactive,\n\t\t\t\t\t(e: MouseEvent) => {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\tcontext.executeCommand(entry.command);\n\t\t\t\t\t\tthis.dismissPopup();\n\t\t\t\t\t},\n\t\t\t\t\tentry.style,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tcontainer.appendChild(list);\n\t}\n\n\tprivate createPickerItem(\n\t\tlabel: string,\n\t\tisActive: boolean,\n\t\thandler: (e: MouseEvent) => void,\n\t\tstyle?: PickerEntryStyle,\n\t): HTMLButtonElement {\n\t\tconst item: HTMLButtonElement = document.createElement('button');\n\t\titem.type = 'button';\n\t\titem.className = 'notectl-heading-picker__item';\n\t\titem.setAttribute('role', 'option');\n\t\titem.setAttribute('aria-selected', String(isActive));\n\n\t\tif (isActive) {\n\t\t\titem.classList.add('notectl-heading-picker__item--active');\n\t\t}\n\n\t\tconst check: HTMLSpanElement = document.createElement('span');\n\t\tcheck.className = 'notectl-heading-picker__check';\n\t\tcheck.textContent = isActive ? '\\u2713' : '';\n\t\titem.appendChild(check);\n\n\t\tconst labelSpan: HTMLSpanElement = document.createElement('span');\n\t\tlabelSpan.className = 'notectl-heading-picker__label';\n\t\tlabelSpan.textContent = label;\n\t\tif (style) {\n\t\t\tlabelSpan.style.fontSize = style.fontSize;\n\t\t\tlabelSpan.style.fontWeight = style.fontWeight;\n\t\t}\n\t\titem.appendChild(labelSpan);\n\n\t\titem.addEventListener('mousedown', handler);\n\t\treturn item;\n\t}\n\n\t// --- Enter Handling ---\n\n\tprivate static readonly HEADING_TYPES: ReadonlySet<string> = new Set([\n\t\t'heading',\n\t\t'title',\n\t\t'subtitle',\n\t]);\n\n\t/**\n\t * Handles Enter inside a heading block.\n\t * Empty heading → convert to paragraph.\n\t * Cursor at end → split and convert new block to paragraph.\n\t * Cursor in middle → normal split (both stay heading).\n\t */\n\tprivate handleEnter(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || !HeadingPlugin.HEADING_TYPES.has(block.type)) return false;\n\n\t\tconst text: string = getBlockText(block);\n\n\t\tif (text === '') {\n\t\t\t// Empty heading → convert to paragraph\n\t\t\tconst tr = state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\tconst blockLength: number = getBlockLength(block);\n\n\t\tif (sel.anchor.offset >= blockLength) {\n\t\t\t// Cursor at end → split and convert new block to paragraph\n\t\t\tconst newBlockId = generateBlockId();\n\t\t\tconst tr = state\n\t\t\t\t.transaction('input')\n\t\t\t\t.splitBlock(sel.anchor.blockId, sel.anchor.offset, newBlockId)\n\t\t\t\t.setBlockType(newBlockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(createCollapsedSelection(newBlockId, 0))\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Cursor in middle → default split (both parts stay heading)\n\t\treturn false;\n\t}\n\n\t/**\n\t * Toggles between a special block type (title/subtitle) and paragraph.\n\t * If the block is already that type, resets to paragraph.\n\t */\n\tprivate toggleSpecialBlock(context: PluginContext, type: string): boolean {\n\t\tconst state = context.getState();\n\t\tif (isNodeSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tif (block.type === type) {\n\t\t\treturn this.setBlockType(context, nodeType('paragraph'));\n\t\t}\n\n\t\treturn this.setBlockType(context, nodeType(type) as NodeTypeName);\n\t}\n\n\t/**\n\t * Toggles between heading (at given level) and paragraph.\n\t * If the block is already a heading at the same level, resets to paragraph.\n\t */\n\tprivate toggleHeading(context: PluginContext, level: HeadingLevel): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tif (block.type === 'heading' && block.attrs?.level === level) {\n\t\t\treturn this.setBlockType(context, nodeType('paragraph'));\n\t\t}\n\n\t\treturn this.setBlockType(context, nodeType('heading'), { level });\n\t}\n\n\tprivate setBlockType(\n\t\tcontext: PluginContext,\n\t\ttype: NodeTypeName,\n\t\tattrs?: Record<string, string | number | boolean>,\n\t): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tconst builder = state.transaction('command');\n\n\t\tconst spec = context.getSchemaRegistry().getNodeSpec(type);\n\t\tif (spec?.excludeMarks && spec.excludeMarks.length > 0) {\n\t\t\tthis.stripExcludedMarks(builder, block, spec.excludeMarks);\n\t\t\tthis.clearExcludedStoredMarks(builder, state, spec.excludeMarks);\n\t\t}\n\n\t\tconst tr = builder.setBlockType(sel.anchor.blockId, type, attrs).setSelection(sel).build();\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Adds removeMark steps for each excluded mark type found\n\t * on the block's inline text content.\n\t */\n\tprivate stripExcludedMarks(\n\t\tbuilder: TransactionBuilder,\n\t\tblock: BlockNode,\n\t\texcludeMarks: readonly string[],\n\t): void {\n\t\tconst blockLength: number = getBlockLength(block);\n\t\tif (blockLength === 0) return;\n\n\t\tconst excludeSet: Set<string> = new Set(excludeMarks);\n\t\tconst inlineChildren = getInlineChildren(block);\n\t\tlet offset = 0;\n\n\t\tfor (const child of inlineChildren) {\n\t\t\tif (isTextNode(child)) {\n\t\t\t\tif (child.text.length > 0) {\n\t\t\t\t\tfor (const mark of child.marks) {\n\t\t\t\t\t\tif (excludeSet.has(mark.type)) {\n\t\t\t\t\t\t\tbuilder.removeMark(block.id, offset, offset + child.text.length, mark);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\toffset += child.text.length;\n\t\t\t} else {\n\t\t\t\toffset += 1;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Clears excluded mark types from stored marks so that\n\t * subsequent typing does not reintroduce them.\n\t */\n\tprivate clearExcludedStoredMarks(\n\t\tbuilder: TransactionBuilder,\n\t\tstate: EditorState,\n\t\texcludeMarks: readonly string[],\n\t): void {\n\t\tif (!state.storedMarks) return;\n\n\t\tconst excludeSet: Set<string> = new Set(excludeMarks);\n\t\tconst filtered: readonly Mark[] = state.storedMarks.filter(\n\t\t\t(m: Mark) => !excludeSet.has(m.type),\n\t\t);\n\n\t\tif (filtered.length !== state.storedMarks.length) {\n\t\t\tbuilder.setStoredMarks(filtered.length > 0 ? filtered : null, state.storedMarks);\n\t\t}\n\t}\n}\n","/**\n * LinkPlugin: registers a link mark type with href attribute,\n * toggle command, keyboard shortcut (Mod-K), and toolbar button\n * with a URL input popup.\n */\n\nimport { getBlockMarksAtOffset, hasMark } from '../../model/Document.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { isCollapsed, isNodeSelection, selectionRange } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tlink: { href: string };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface LinkConfig {\n\t/** Whether to add rel=\"noopener noreferrer\" and target=\"_blank\" by default. */\n\treadonly openInNewTab: boolean;\n\t/** When true, a separator is rendered after the link toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: LinkConfig = {\n\topenInNewTab: true,\n};\n\n// --- Plugin ---\n\nexport class LinkPlugin implements Plugin {\n\treadonly id = 'link';\n\treadonly name = 'Link';\n\treadonly priority = 25;\n\n\tprivate readonly config: LinkConfig;\n\n\tconstructor(config?: Partial<LinkConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tconst openInNewTab = this.config.openInNewTab;\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'link',\n\t\t\trank: 10,\n\t\t\tattrs: {\n\t\t\t\thref: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst a = document.createElement('a');\n\t\t\t\tconst href = mark.attrs?.href ?? '';\n\t\t\t\ta.setAttribute('href', href);\n\t\t\t\tif (openInNewTab) {\n\t\t\t\t\ta.setAttribute('target', '_blank');\n\t\t\t\t\ta.setAttribute('rel', 'noopener noreferrer');\n\t\t\t\t}\n\t\t\t\treturn a;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst href: string = escapeHTML(String(mark.attrs?.href ?? ''));\n\t\t\t\treturn `<a href=\"${href}\">${content}</a>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'a',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst href: string = el.getAttribute('href') ?? '';\n\t\t\t\t\t\treturn { href };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['a'], attrs: ['href', 'target', 'rel'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleLink', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.toggleLink(context, state);\n\t\t});\n\n\t\tcontext.registerCommand('setLink', () => {\n\t\t\t// setLink is called by the popup after URL input\n\t\t\t// The actual URL is set via the popup's custom render\n\t\t\treturn false;\n\t\t});\n\n\t\tcontext.registerCommand('removeLink', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.removeLink(context, state);\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-K': () => context.executeCommand('toggleLink'),\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'link',\n\t\t\tgroup: 'insert',\n\t\t\ticon,\n\t\t\tlabel: 'Link',\n\t\t\ttooltip: `Insert Link (${formatShortcut('Mod-K')})`,\n\t\t\tcommand: 'toggleLink',\n\t\t\tpriority: 60,\n\t\t\tpopupType: 'custom',\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\trenderPopup: (container, ctx) => {\n\t\t\t\tthis.renderLinkPopup(container, ctx);\n\t\t\t},\n\t\t\tisActive: (state) => this.isLinkActive(state),\n\t\t\tisEnabled: (state) => !isCollapsed(state.selection),\n\t\t});\n\t}\n\n\tprivate isLinkActive(state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (isCollapsed(sel)) {\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return false;\n\t\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\t\treturn hasMark(marks, markType('link'));\n\t\t}\n\n\t\t// Check if link is active anywhere in selection\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\treturn hasMark(marks, markType('link'));\n\t}\n\n\tprivate toggleLink(context: PluginContext, state: EditorState): boolean {\n\t\tif (this.isLinkActive(state)) {\n\t\t\treturn this.removeLink(context, state);\n\t\t}\n\t\t// Adding links requires the toolbar popup for URL input\n\t\treturn false;\n\t}\n\n\tprivate addLink(context: PluginContext, state: EditorState, href: string): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (isCollapsed(sel)) return false;\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t\tconst mark = { type: markType('link'), attrs: { href } };\n\n\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\tbuilder.addMark(blockId, from, to, mark);\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\tprivate removeLink(context: PluginContext, state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = isCollapsed(sel)\n\t\t\t? { from: sel.anchor, to: sel.anchor }\n\t\t\t: selectionRange(sel, blockOrder);\n\n\t\tconst builder = state.transaction('command');\n\n\t\tif (isCollapsed(sel)) {\n\t\t\t// Remove link from entire link span around cursor\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return false;\n\n\t\t\t// Find the extent of the link mark around the cursor.\n\t\t\t// Build a list of text children with their positions first,\n\t\t\t// then scan backward and forward from the cursor node.\n\t\t\tconst textChildren: { pos: number; end: number; hasLink: boolean }[] = [];\n\t\t\tlet pos = 0;\n\t\t\tfor (const child of block.children) {\n\t\t\t\tif (!('text' in child)) continue;\n\t\t\t\tconst end = pos + child.text.length;\n\t\t\t\ttextChildren.push({ pos, end, hasLink: hasMark(child.marks, markType('link')) });\n\t\t\t\tpos = end;\n\t\t\t}\n\n\t\t\t// Find the text child containing the cursor\n\t\t\tconst cursorIdx = textChildren.findIndex(\n\t\t\t\t(c) => sel.anchor.offset >= c.pos && sel.anchor.offset <= c.end,\n\t\t\t);\n\t\t\tconst cursorEntry = cursorIdx >= 0 ? textChildren[cursorIdx] : undefined;\n\t\t\tif (cursorIdx === -1 || !cursorEntry?.hasLink) return false;\n\n\t\t\t// Scan backward from cursor node to find link start\n\t\t\tlet startIdx = cursorIdx;\n\t\t\twhile (startIdx > 0 && textChildren[startIdx - 1]?.hasLink) {\n\t\t\t\tstartIdx--;\n\t\t\t}\n\n\t\t\t// Scan forward from cursor node to find link end\n\t\t\tlet endIdx = cursorIdx;\n\t\t\twhile (endIdx < textChildren.length - 1 && textChildren[endIdx + 1]?.hasLink) {\n\t\t\t\tendIdx++;\n\t\t\t}\n\n\t\t\tconst startEntry = textChildren[startIdx];\n\t\t\tconst endEntry = textChildren[endIdx];\n\t\t\tif (!startEntry || !endEntry) return false;\n\n\t\t\tconst linkStart = startEntry.pos;\n\t\t\tconst linkEnd = endEntry.end;\n\n\t\t\tbuilder.removeMark(sel.anchor.blockId, linkStart, linkEnd, { type: markType('link') });\n\t\t} else {\n\t\t\t// Remove link from selection range\n\t\t\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\t\t\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\t\tconst blockId = blockOrder[i];\n\t\t\t\tif (!blockId) continue;\n\t\t\t\tconst block = state.getBlock(blockId);\n\t\t\t\tif (!block) continue;\n\t\t\t\tconst blockLen = block.children.reduce(\n\t\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t\t0,\n\t\t\t\t);\n\n\t\t\t\tconst from = i === fromIdx ? range.from.offset : 0;\n\t\t\t\tconst to = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\t\tif (from !== to) {\n\t\t\t\t\tbuilder.removeMark(blockId, from, to, { type: markType('link') });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\tprivate renderLinkPopup(container: HTMLElement, context: PluginContext): void {\n\t\tcontainer.style.padding = '8px';\n\t\tcontainer.style.minWidth = '200px';\n\n\t\tconst state = context.getState();\n\t\tconst isActive = this.isLinkActive(state);\n\n\t\tif (isActive) {\n\t\t\t// Show remove link button\n\t\t\tconst removeBtn = document.createElement('button');\n\t\t\tremoveBtn.type = 'button';\n\t\t\tremoveBtn.textContent = 'Remove Link';\n\t\t\tremoveBtn.setAttribute('aria-label', 'Remove link');\n\t\t\tremoveBtn.style.cssText = 'width:100%;padding:6px 12px;cursor:pointer;';\n\t\t\tremoveBtn.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tcontext.executeCommand('removeLink');\n\t\t\t});\n\t\t\tcontainer.appendChild(removeBtn);\n\t\t} else {\n\t\t\t// Show URL input\n\t\t\tconst input = document.createElement('input');\n\t\t\tinput.type = 'url';\n\t\t\tinput.placeholder = 'https://...';\n\t\t\tinput.setAttribute('aria-label', 'URL');\n\t\t\tinput.style.cssText = 'width:100%;padding:4px;box-sizing:border-box;';\n\n\t\t\tconst applyBtn = document.createElement('button');\n\t\t\tapplyBtn.type = 'button';\n\t\t\tapplyBtn.textContent = 'Apply';\n\t\t\tapplyBtn.setAttribute('aria-label', 'Apply link');\n\t\t\tapplyBtn.style.cssText = 'width:100%;padding:6px 12px;margin-top:4px;cursor:pointer;';\n\n\t\t\tapplyBtn.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tconst href = input.value.trim();\n\t\t\t\tif (href) {\n\t\t\t\t\tthis.addLink(context, context.getState(), href);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tinput.addEventListener('keydown', (e) => {\n\t\t\t\tif (e.key === 'Enter') {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tconst href = input.value.trim();\n\t\t\t\t\tif (href) {\n\t\t\t\t\t\tthis.addLink(context, context.getState(), href);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tcontainer.appendChild(input);\n\t\t\tcontainer.appendChild(applyBtn);\n\n\t\t\t// Auto-focus input\n\t\t\trequestAnimationFrame(() => input.focus());\n\t\t}\n\t}\n}\n","/**\n * ListPlugin: registers ordered, unordered, and checklist block types\n * with NodeSpecs, toggle commands, indent/outdent (Tab/Shift-Tab),\n * input rules, and toolbar buttons.\n *\n * List items are modeled as flat blocks with a `listType` and `indent` attribute,\n * allowing simple nesting representation without deep tree structures.\n */\n\nimport { isNodeOfType } from '../../model/AttrRegistry.js';\nimport { generateBlockId, getBlockText } from '../../model/Document.js';\nimport { createBlockElement } from '../../model/NodeSpec.js';\nimport { createCollapsedSelection, isCollapsed, isNodeSelection } from '../../model/Selection.js';\nimport { nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\n\n// --- Attribute Registry Augmentation ---\n\nexport type ListType = 'bullet' | 'ordered' | 'checklist';\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tlist_item: { listType: ListType; indent: number; checked: boolean };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface ListConfig {\n\t/** Which list types to enable. Defaults to all. */\n\treadonly types: readonly ListType[];\n\t/** Maximum indent depth. Defaults to 4. */\n\treadonly maxIndent: number;\n\t/** When true, a separator is rendered after the last list toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: ListConfig = {\n\ttypes: ['bullet', 'ordered', 'checklist'],\n\tmaxIndent: 4,\n};\n\n// --- List Type Metadata ---\n\ninterface ListTypeDefinition {\n\treadonly type: ListType;\n\treadonly label: string;\n\treadonly icon: string;\n\treadonly inputPattern: RegExp;\n\treadonly inputPrefix: string;\n}\n\nconst BULLET_LIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z\"/></svg>';\nconst NUMBERED_LIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z\"/></svg>';\nconst CHECKLIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M22 7h-9v2h9V7zm0 8h-9v2h9v-2zM5.54 11L2 7.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 11zm0 8L2 15.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 19z\"/></svg>';\n\nconst LIST_TYPE_DEFINITIONS: readonly ListTypeDefinition[] = [\n\t{\n\t\ttype: 'bullet',\n\t\tlabel: 'Bullet List',\n\t\ticon: BULLET_LIST_ICON,\n\t\tinputPattern: /^[-*] $/,\n\t\tinputPrefix: '- ',\n\t},\n\t{\n\t\ttype: 'ordered',\n\t\tlabel: 'Numbered List',\n\t\ticon: NUMBERED_LIST_ICON,\n\t\tinputPattern: /^\\d+\\. $/,\n\t\tinputPrefix: '1. ',\n\t},\n\t{\n\t\ttype: 'checklist',\n\t\tlabel: 'Checklist',\n\t\ticon: CHECKLIST_ICON,\n\t\tinputPattern: /^\\[[ x]] $/,\n\t\tinputPrefix: '[ ] ',\n\t},\n];\n\n// --- Plugin ---\n\nexport class ListPlugin implements Plugin {\n\treadonly id = 'list';\n\treadonly name = 'List';\n\treadonly priority = 35;\n\n\tprivate readonly config: ListConfig;\n\n\tconstructor(config?: Partial<ListConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerInputRules(context);\n\t\tthis.registerToolbarItems(context);\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'list_item',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\tattrs: {\n\t\t\t\tlistType: { default: 'bullet' },\n\t\t\t\tindent: { default: 0 },\n\t\t\t\tchecked: { default: false },\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst listType = node.attrs?.listType ?? 'bullet';\n\t\t\t\tconst indent = node.attrs?.indent ?? 0;\n\t\t\t\tconst checked = node.attrs?.checked ?? false;\n\n\t\t\t\tconst li = createBlockElement('li', node.id);\n\t\t\t\tli.setAttribute('role', 'listitem');\n\t\t\t\tli.setAttribute('data-list-type', listType);\n\t\t\t\tli.setAttribute('data-indent', String(indent));\n\t\t\t\tli.className = `notectl-list-item notectl-list-item--${listType}`;\n\n\t\t\t\tif (indent > 0) {\n\t\t\t\t\tli.style.marginLeft = `${indent * 24}px`;\n\t\t\t\t}\n\n\t\t\t\tif (listType === 'checklist') {\n\t\t\t\t\tli.setAttribute('data-checked', String(checked));\n\t\t\t\t\tli.setAttribute('aria-checked', String(checked));\n\t\t\t\t}\n\t\t\t\tli.setAttribute('aria-level', String(indent + 1));\n\n\t\t\t\treturn li;\n\t\t\t},\n\t\t\twrapper(node) {\n\t\t\t\tconst listType = node.attrs?.listType ?? 'bullet';\n\t\t\t\tconst tag = listType === 'ordered' ? 'ol' : 'ul';\n\t\t\t\treturn {\n\t\t\t\t\ttag,\n\t\t\t\t\tkey: `list-${listType}`,\n\t\t\t\t\tclassName: `notectl-list notectl-list--${listType}`,\n\t\t\t\t\tattrs: { role: 'list' },\n\t\t\t\t};\n\t\t\t},\n\t\t\ttoHTML(_node, content) {\n\t\t\t\treturn `<li>${content || '<br>'}</li>`;\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'li' }],\n\t\t\tsanitize: { tags: ['ul', 'ol', 'li'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerCommand(`toggleList:${def.type}`, () => {\n\t\t\t\treturn this.toggleList(context, def.type);\n\t\t\t});\n\t\t}\n\n\t\tcontext.registerCommand('indentListItem', () => {\n\t\t\treturn this.indent(context);\n\t\t});\n\n\t\tcontext.registerCommand('outdentListItem', () => {\n\t\t\treturn this.outdent(context);\n\t\t});\n\n\t\tif (this.config.types.includes('checklist')) {\n\t\t\tcontext.registerCommand('toggleChecklistItem', () => {\n\t\t\t\treturn this.toggleChecked(context);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\tEnter: () => this.handleEnter(context),\n\t\t\tBackspace: () => this.handleBackspace(context),\n\t\t\tTab: () => this.indent(context),\n\t\t\t'Shift-Tab': () => this.outdent(context),\n\t\t});\n\t}\n\n\tprivate registerInputRules(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerInputRule({\n\t\t\t\tpattern: def.inputPattern,\n\t\t\t\thandler: (state, match, start, _end) => {\n\t\t\t\t\tconst sel = state.selection;\n\t\t\t\t\tif (isNodeSelection(sel)) return null;\n\t\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\t\tconst matchStr = match[0] ?? '';\n\t\t\t\t\tconst matchLen = matchStr.length;\n\t\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t\tlistType: def.type,\n\t\t\t\t\t\tindent: 0,\n\t\t\t\t\t};\n\t\t\t\t\tif (def.type === 'checklist') {\n\t\t\t\t\t\tattrs.checked = matchStr.includes('[x]');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn state\n\t\t\t\t\t\t.transaction('input')\n\t\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + matchLen)\n\t\t\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, 0))\n\t\t\t\t\t\t.build();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerToolbarItems(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\t\tconst lastType = enabledTypes.at(-1);\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: `list-${def.type}`,\n\t\t\t\tgroup: 'block',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel: def.label,\n\t\t\t\tcommand: `toggleList:${def.type}`,\n\t\t\t\tpriority: def.type === 'bullet' ? 70 : def.type === 'ordered' ? 71 : 72,\n\t\t\t\tseparatorAfter: this.config.separatorAfter && def === lastType,\n\t\t\t\tisActive: (state) => this.isListActive(state, def.type),\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Command Implementations ---\n\n\tprivate toggleList(context: PluginContext, listType: ListType): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\t// If already this list type, convert back to paragraph\n\t\tif (block.type === 'list_item' && block.attrs?.listType === listType) {\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Convert to list item\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlistType,\n\t\t\tindent: isNodeOfType(block, 'list_item') ? block.attrs.indent : 0,\n\t\t};\n\t\tif (listType === 'checklist') {\n\t\t\tattrs.checked = false;\n\t\t}\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate indent(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (isNodeSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || !isNodeOfType(block, 'list_item')) return false;\n\n\t\tif (block.attrs.indent >= this.config.maxIndent) return false;\n\n\t\treturn this.setIndent(context, state, block.attrs.indent + 1);\n\t}\n\n\tprivate outdent(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (isNodeSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || !isNodeOfType(block, 'list_item')) return false;\n\n\t\tif (block.attrs.indent <= 0) return false;\n\n\t\treturn this.setIndent(context, state, block.attrs.indent - 1);\n\t}\n\n\tprivate setIndent(context: PluginContext, state: EditorState, indent: number): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tconst attrs = { ...block.attrs, indent } as Record<string, string | number | boolean>;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate toggleChecked(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (isNodeSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item' || block.attrs?.listType !== 'checklist') {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst checked = !block.attrs?.checked;\n\t\tconst attrs = { ...block.attrs, checked } as Record<string, string | number | boolean>;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(state.selection.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(state.selection)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles Backspace at the start of a list item.\n\t * Converts the list item back to a paragraph, preserving text.\n\t */\n\tprivate handleBackspace(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item') return false;\n\t\tif (sel.anchor.offset !== 0) return false;\n\n\t\tconst tr = state\n\t\t\t.transaction('input')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles Enter inside a list item.\n\t * Empty item → exit list (convert to paragraph).\n\t * Non-empty item → split and create a new list item with the same type.\n\t */\n\tprivate handleEnter(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item') return false;\n\n\t\tconst text = getBlockText(block);\n\n\t\tif (text === '') {\n\t\t\t// Empty list item → convert to paragraph (exit list)\n\t\t\tconst tr = state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Non-empty → split block and set new block to same list type\n\t\tconst newBlockId = generateBlockId();\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlistType: isNodeOfType(block, 'list_item') ? block.attrs.listType : 'bullet',\n\t\t\tindent: isNodeOfType(block, 'list_item') ? block.attrs.indent : 0,\n\t\t};\n\t\tif (attrs.listType === 'checklist') {\n\t\t\tattrs.checked = false;\n\t\t}\n\n\t\tconst tr = state\n\t\t\t.transaction('input')\n\t\t\t.splitBlock(sel.anchor.blockId, sel.anchor.offset, newBlockId)\n\t\t\t.setBlockType(newBlockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(createCollapsedSelection(newBlockId, 0))\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t// --- Helpers ---\n\n\tprivate isListActive(state: EditorState, listType: ListType): boolean {\n\t\tif (isNodeSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\treturn block?.type === 'list_item' && block.attrs?.listType === listType;\n\t}\n\n\tprivate getEnabledTypes(): readonly ListTypeDefinition[] {\n\t\treturn LIST_TYPE_DEFINITIONS.filter((def) => this.config.types.includes(def.type));\n\t}\n}\n","/**\n * BlockquotePlugin: registers a blockquote block type with NodeSpec,\n * toggle command, keyboard shortcut, input rule, and a toolbar button.\n */\n\nimport { createBlockElement } from '../../model/NodeSpec.js';\nimport { isCollapsed, isNodeSelection } from '../../model/Selection.js';\nimport { type NodeTypeName, nodeType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tblockquote: Record<string, never>;\n\t}\n}\n\n// --- Configuration ---\n\nexport interface BlockquoteConfig {\n\t/** When true, a separator is rendered after the blockquote toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: BlockquoteConfig = {};\n\n// --- Plugin ---\n\nexport class BlockquotePlugin implements Plugin {\n\treadonly id = 'blockquote';\n\treadonly name = 'Blockquote';\n\treadonly priority = 35;\n\n\tprivate readonly config: BlockquoteConfig;\n\n\tconstructor(config?: Partial<BlockquoteConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerInputRule(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'blockquote',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\ttoDOM(node) {\n\t\t\t\treturn createBlockElement('blockquote', node.id);\n\t\t\t},\n\t\t\ttoHTML(_node, content) {\n\t\t\t\treturn `<blockquote>${content || '<br>'}</blockquote>`;\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'blockquote' }],\n\t\t\tsanitize: { tags: ['blockquote'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleBlockquote', () => {\n\t\t\treturn this.toggleBlockquote(context);\n\t\t});\n\n\t\tcontext.registerCommand('setBlockquote', () => {\n\t\t\treturn this.setBlockType(context, nodeType('blockquote'));\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift->': () => context.executeCommand('toggleBlockquote'),\n\t\t});\n\t}\n\n\tprivate registerInputRule(context: PluginContext): void {\n\t\tcontext.registerInputRule({\n\t\t\tpattern: /^> $/,\n\t\t\thandler(state, _match, start, _end) {\n\t\t\t\tconst sel = state.selection;\n\t\t\t\tif (isNodeSelection(sel)) return null;\n\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + 2)\n\t\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('blockquote'))\n\t\t\t\t\t.setSelection(sel)\n\t\t\t\t\t.build();\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'blockquote',\n\t\t\tgroup: 'block',\n\t\t\ticon,\n\t\t\tlabel: 'Blockquote',\n\t\t\ttooltip: `Blockquote (${formatShortcut('Mod-Shift->')})`,\n\t\t\tcommand: 'toggleBlockquote',\n\t\t\tpriority: 55,\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\tisActive: (state) => {\n\t\t\t\tif (isNodeSelection(state.selection)) return false;\n\t\t\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\t\t\treturn block?.type === 'blockquote';\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Toggles between blockquote and paragraph.\n\t * If the block is already a blockquote, resets to paragraph.\n\t */\n\tprivate toggleBlockquote(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (isNodeSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tif (block.type === 'blockquote') {\n\t\t\treturn this.setBlockType(context, nodeType('paragraph'));\n\t\t}\n\n\t\treturn this.setBlockType(context, nodeType('blockquote'));\n\t}\n\n\tprivate setBlockType(\n\t\tcontext: PluginContext,\n\t\ttype: NodeTypeName,\n\t\tattrs?: Record<string, string | number | boolean>,\n\t): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, type, attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n}\n","/**\n * StrikethroughPlugin: registers a strikethrough inline mark with MarkSpec,\n * toggle command, keyboard shortcut (Mod-Shift-X), and a toolbar button.\n */\n\nimport { isMarkActive, toggleMark } from '../../commands/Commands.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tstrikethrough: Record<string, never>;\n\t}\n}\n\n// --- Configuration ---\n\nexport interface StrikethroughConfig {\n\t/** When true, a separator is rendered after the strikethrough toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: StrikethroughConfig = {};\n\n// --- Plugin ---\n\nexport class StrikethroughPlugin implements Plugin {\n\treadonly id = 'strikethrough';\n\treadonly name = 'Strikethrough';\n\treadonly priority = 22;\n\n\tprivate readonly config: StrikethroughConfig;\n\n\tconstructor(config?: Partial<StrikethroughConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommand(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'strikethrough',\n\t\t\trank: 3,\n\t\t\ttoDOM() {\n\t\t\t\treturn document.createElement('s');\n\t\t\t},\n\t\t\ttoHTMLString: (_mark, content) => `<s>${content}</s>`,\n\t\t\tparseHTML: [{ tag: 's' }, { tag: 'strike' }, { tag: 'del' }],\n\t\t\tsanitize: { tags: ['s'] },\n\t\t});\n\t}\n\n\tprivate registerCommand(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleStrikethrough', () => {\n\t\t\tconst tr = toggleMark(context.getState(), markType('strikethrough'));\n\t\t\tif (tr) {\n\t\t\t\tcontext.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift-X': () => context.executeCommand('toggleStrikethrough'),\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'strikethrough',\n\t\t\tgroup: 'format',\n\t\t\ticon,\n\t\t\tlabel: 'Strikethrough',\n\t\t\ttooltip: `Strikethrough (${formatShortcut('Mod-Shift-X')})`,\n\t\t\tcommand: 'toggleStrikethrough',\n\t\t\tpriority: 40,\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\tisActive: (state) => isMarkActive(state, markType('strikethrough')),\n\t\t});\n\t}\n}\n","/**\n * TextColorPlugin: registers a text color mark with attrs,\n * toolbar button with a color picker popup, and removeTextColor command.\n */\n\nimport { isMarkOfType } from '../../model/AttrRegistry.js';\nimport { getBlockMarksAtOffset, hasMark } from '../../model/Document.js';\nimport { isCollapsed, isNodeSelection, selectionRange } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\ttextColor: { color: string };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface TextColorConfig {\n\t/**\n\t * Restricts the color picker to a specific set of hex colors.\n\t * Each value must be a valid hex color code (`#RGB` or `#RRGGBB`).\n\t * Duplicates are removed automatically (case-insensitive).\n\t * When omitted, the full default palette is shown.\n\t */\n\treadonly colors?: readonly string[];\n\t/** When true, a separator is rendered after the textColor toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: TextColorConfig = {};\n\n// --- Color Validation ---\n\nconst HEX_COLOR_PATTERN: RegExp = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;\n\nfunction isValidHexColor(value: string): boolean {\n\treturn HEX_COLOR_PATTERN.test(value);\n}\n\n/**\n * Validates, deduplicates, and normalizes the user-supplied color list.\n * Returns the default palette when no custom colors are provided.\n *\n * @throws {Error} if any value is not a valid hex color code.\n */\nfunction resolveColors(colors: readonly string[] | undefined): readonly string[] {\n\tif (!colors || colors.length === 0) return COLOR_PALETTE;\n\n\tconst invalid: string[] = colors.filter((c) => !isValidHexColor(c));\n\tif (invalid.length > 0) {\n\t\tthrow new Error(\n\t\t\t`TextColorPlugin: invalid hex color(s): ${invalid.join(', ')}. Expected format: #RGB or #RRGGBB.`,\n\t\t);\n\t}\n\n\tconst seen: Set<string> = new Set();\n\tconst unique: string[] = [];\n\tfor (const color of colors) {\n\t\tconst normalized: string = color.toLowerCase();\n\t\tif (!seen.has(normalized)) {\n\t\t\tseen.add(normalized);\n\t\t\tunique.push(normalized);\n\t\t}\n\t}\n\treturn unique;\n}\n\n// --- Color Palette (Google Docs style: 10 columns x 7 rows) ---\n\nconst COLOR_PALETTE: readonly string[] = [\n\t// Row 1 — dark\n\t'#000000',\n\t'#434343',\n\t'#666666',\n\t'#999999',\n\t'#b7b7b7',\n\t'#cccccc',\n\t'#d9d9d9',\n\t'#efefef',\n\t'#f3f3f3',\n\t'#ffffff',\n\t// Row 2 — vivid\n\t'#980000',\n\t'#ff0000',\n\t'#ff9900',\n\t'#ffff00',\n\t'#00ff00',\n\t'#00ffff',\n\t'#4a86e8',\n\t'#0000ff',\n\t'#9900ff',\n\t'#ff00ff',\n\t// Row 3 — light 3\n\t'#e6b8af',\n\t'#f4cccc',\n\t'#fce5cd',\n\t'#fff2cc',\n\t'#d9ead3',\n\t'#d0e0e3',\n\t'#c9daf8',\n\t'#cfe2f3',\n\t'#d9d2e9',\n\t'#ead1dc',\n\t// Row 4 — light 2\n\t'#dd7e6b',\n\t'#ea9999',\n\t'#f9cb9c',\n\t'#ffe599',\n\t'#b6d7a8',\n\t'#a2c4c9',\n\t'#a4c2f4',\n\t'#9fc5e8',\n\t'#b4a7d6',\n\t'#d5a6bd',\n\t// Row 5 — light 1\n\t'#cc4125',\n\t'#e06666',\n\t'#f6b26b',\n\t'#ffd966',\n\t'#93c47d',\n\t'#76a5af',\n\t'#6d9eeb',\n\t'#6fa8dc',\n\t'#8e7cc3',\n\t'#c27ba0',\n\t// Row 6 — dark 1\n\t'#a61c00',\n\t'#cc0000',\n\t'#e69138',\n\t'#f1c232',\n\t'#6aa84f',\n\t'#45818e',\n\t'#3c78d8',\n\t'#3d85c6',\n\t'#674ea7',\n\t'#a64d79',\n\t// Row 7 — dark 2\n\t'#85200c',\n\t'#990000',\n\t'#b45f06',\n\t'#bf9000',\n\t'#38761d',\n\t'#134f5c',\n\t'#1155cc',\n\t'#0b5394',\n\t'#351c75',\n\t'#741b47',\n];\n\n// --- Plugin ---\n\nexport class TextColorPlugin implements Plugin {\n\treadonly id = 'textColor';\n\treadonly name = 'Text Color';\n\treadonly priority = 23;\n\n\tprivate readonly config: TextColorConfig;\n\tprivate readonly colors: readonly string[];\n\n\tconstructor(config?: Partial<TextColorConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t\tthis.colors = resolveColors(config?.colors);\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'textColor',\n\t\t\trank: 5,\n\t\t\tattrs: {\n\t\t\t\tcolor: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst span = document.createElement('span');\n\t\t\t\tconst color = mark.attrs?.color ?? '';\n\t\t\t\tspan.style.color = color;\n\t\t\t\treturn span;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst color: string = String(mark.attrs?.color ?? '');\n\t\t\t\treturn `<span style=\"color: ${color}\">${content}</span>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst color: string = el.style.color;\n\t\t\t\t\t\tif (!color) return false;\n\t\t\t\t\t\treturn { color };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['span'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('removeTextColor', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.removeColor(context, state);\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst pathD =\n\t\t\t'M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2z' + 'm-1.38 9L12 5.67 14.38 12H9.62z';\n\t\tconst icon: string = [\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\"',\n\t\t\t' viewBox=\"0 0 24 24\">',\n\t\t\t`<path d=\"${pathD}\"/>`,\n\t\t\t'<rect x=\"3\" y=\"19.5\" width=\"18\" height=\"3\"',\n\t\t\t' rx=\"0.5\" fill=\"#e53935\"/>',\n\t\t\t'</svg>',\n\t\t].join('');\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'textColor',\n\t\t\tgroup: 'format',\n\t\t\ticon,\n\t\t\tlabel: 'Text Color',\n\t\t\ttooltip: 'Text Color',\n\t\t\tcommand: 'removeTextColor',\n\t\t\tpriority: 45,\n\t\t\tpopupType: 'custom',\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\trenderPopup: (container, ctx) => {\n\t\t\t\tthis.renderColorPopup(container, ctx);\n\t\t\t},\n\t\t\tisActive: (state) => this.isTextColorActive(state),\n\t\t});\n\t}\n\n\t// --- State Queries ---\n\n\tprivate isTextColorActive(state: EditorState): boolean {\n\t\treturn this.getActiveColor(state) !== null;\n\t}\n\n\tprivate getActiveColor(state: EditorState): string | null {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return null;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tif (state.storedMarks) {\n\t\t\t\tconst mark = state.storedMarks.find((m) => m.type === 'textColor');\n\t\t\t\treturn mark && isMarkOfType(mark, 'textColor') ? (mark.attrs.color ?? null) : null;\n\t\t\t}\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return null;\n\t\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\t\tconst mark = marks.find((m) => m.type === 'textColor');\n\t\t\treturn mark && isMarkOfType(mark, 'textColor') ? (mark.attrs.color ?? null) : null;\n\t\t}\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return null;\n\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\tconst mark = marks.find((m) => m.type === 'textColor');\n\t\treturn mark && isMarkOfType(mark, 'textColor') ? (mark.attrs.color ?? null) : null;\n\t}\n\n\t// --- Color Application ---\n\n\tprivate applyColor(context: PluginContext, state: EditorState, color: string): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\t// Set stored marks with the new color\n\t\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!anchorBlock) return false;\n\t\t\tconst currentMarks =\n\t\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\t\tconst withoutColor = currentMarks.filter((m) => m.type !== 'textColor');\n\t\t\tconst newMarks = [...withoutColor, { type: markType('textColor'), attrs: { color } }];\n\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Range selection: remove existing textColor, then add new one\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t\tconst mark = { type: markType('textColor'), attrs: { color } };\n\n\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\t// Remove existing textColor first, then add new one\n\t\t\t\tbuilder.removeMark(blockId, from, to, { type: markType('textColor') });\n\t\t\t\tbuilder.addMark(blockId, from, to, mark);\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\tprivate removeColor(context: PluginContext, state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\t// Remove textColor from stored marks\n\t\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!anchorBlock) return false;\n\t\t\tconst currentMarks =\n\t\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\t\tif (!hasMark(currentMarks, markType('textColor'))) return false;\n\n\t\t\tconst newMarks = currentMarks.filter((m) => m.type !== 'textColor');\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Range selection: remove textColor from range\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\tbuilder.removeMark(blockId, from, to, { type: markType('textColor') });\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\t// --- Popup Rendering ---\n\n\tprivate renderColorPopup(container: HTMLElement, context: PluginContext): void {\n\t\tcontainer.classList.add('notectl-color-picker');\n\n\t\tconst state = context.getState();\n\t\tconst activeColor = this.getActiveColor(state);\n\n\t\t// \"Default\" button to remove color\n\t\tconst defaultBtn = document.createElement('button');\n\t\tdefaultBtn.type = 'button';\n\t\tdefaultBtn.className = 'notectl-color-picker__default';\n\t\tdefaultBtn.textContent = 'Default';\n\t\tdefaultBtn.addEventListener('mousedown', (e) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tcontext.executeCommand('removeTextColor');\n\t\t});\n\t\tcontainer.appendChild(defaultBtn);\n\n\t\t// Color grid\n\t\tconst grid = document.createElement('div');\n\t\tgrid.className = 'notectl-color-picker__grid';\n\n\t\tfor (const color of this.colors) {\n\t\t\tconst swatch = document.createElement('button');\n\t\t\tswatch.type = 'button';\n\t\t\tswatch.className = 'notectl-color-picker__swatch';\n\t\t\tif (activeColor && activeColor.toLowerCase() === color.toLowerCase()) {\n\t\t\t\tswatch.classList.add('notectl-color-picker__swatch--active');\n\t\t\t}\n\t\t\tswatch.style.backgroundColor = color;\n\t\t\tif (color === '#ffffff') {\n\t\t\t\tswatch.style.border = '1px solid #d0d0d0';\n\t\t\t}\n\t\t\tswatch.title = color;\n\t\t\tswatch.setAttribute('aria-label', `Text color ${color}`);\n\n\t\t\tswatch.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.applyColor(context, context.getState(), color);\n\t\t\t});\n\n\t\t\tgrid.appendChild(swatch);\n\t\t}\n\n\t\tcontainer.appendChild(grid);\n\t}\n}\n","/**\n * HorizontalRulePlugin: registers a horizontal rule (divider) void block type\n * with NodeSpec, insert command, input rule, and toolbar button.\n */\n\nimport { createBlockNode } from '../../model/Document.js';\nimport { createBlockElement } from '../../model/NodeSpec.js';\nimport { createCollapsedSelection, isCollapsed, isNodeSelection } from '../../model/Selection.js';\nimport { nodeType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\thorizontal_rule: Record<string, never>;\n\t}\n}\n\n// --- Configuration ---\n\nexport interface HorizontalRuleConfig {\n\t/** When true, a separator is rendered after the toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: HorizontalRuleConfig = {};\n\n// --- Plugin ---\n\nexport class HorizontalRulePlugin implements Plugin {\n\treadonly id = 'horizontal-rule';\n\treadonly name = 'Horizontal Rule';\n\treadonly priority = 40;\n\n\tprivate readonly config: HorizontalRuleConfig;\n\n\tconstructor(config?: Partial<HorizontalRuleConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerInputRule(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'horizontal_rule',\n\t\t\tgroup: 'block',\n\t\t\tisVoid: true,\n\t\t\ttoDOM(node) {\n\t\t\t\treturn createBlockElement('hr', node.id);\n\t\t\t},\n\t\t\ttoHTML() {\n\t\t\t\treturn '<hr>';\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'hr' }],\n\t\t\tsanitize: { tags: ['hr'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('insertHorizontalRule', () => {\n\t\t\treturn this.insertHorizontalRule(context);\n\t\t});\n\t}\n\n\tprivate registerInputRule(context: PluginContext): void {\n\t\tcontext.registerInputRule({\n\t\t\tpattern: /^-{3,} $/,\n\t\t\thandler(state, _match, _start, end) {\n\t\t\t\tconst sel = state.selection;\n\t\t\t\tif (isNodeSelection(sel)) return null;\n\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\tconst blockIndex = state.doc.children.findIndex((b) => b.id === sel.anchor.blockId);\n\t\t\t\tif (blockIndex === -1) return null;\n\n\t\t\t\tconst newParagraph = createBlockNode(nodeType('paragraph'));\n\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, 0, end)\n\t\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('horizontal_rule'))\n\t\t\t\t\t.insertNode([], blockIndex + 1, newParagraph)\n\t\t\t\t\t.setSelection(createCollapsedSelection(newParagraph.id, 0))\n\t\t\t\t\t.build();\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M4 11h16v2H4z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'horizontal-rule',\n\t\t\tgroup: 'block',\n\t\t\ticon,\n\t\t\tlabel: 'Horizontal Rule',\n\t\t\ttooltip: 'Horizontal Rule (--- + Space)',\n\t\t\tcommand: 'insertHorizontalRule',\n\t\t\tpriority: 60,\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t});\n\t}\n\n\t/**\n\t * Inserts a horizontal rule after the current block,\n\t * followed by a new paragraph for continued editing.\n\t */\n\tprivate insertHorizontalRule(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tconst blockIndex = state.doc.children.findIndex((b) => b.id === sel.anchor.blockId);\n\t\tif (blockIndex === -1) return false;\n\n\t\tconst hrBlock = createBlockNode(nodeType('horizontal_rule'));\n\t\tconst newParagraph = createBlockNode(nodeType('paragraph'));\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.insertNode([], blockIndex + 1, hrBlock)\n\t\t\t.insertNode([], blockIndex + 2, newParagraph)\n\t\t\t.setSelection(createCollapsedSelection(newParagraph.id, 0))\n\t\t\t.build();\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n}\n","/**\n * AlignmentPlugin: adds left/center/right/justify alignment as a block\n * attribute on paragraphs, headings, images, and other alignable types.\n * Patches their NodeSpecs to render the `align` attribute via inline\n * `text-align` style and provides toggle commands, keyboard shortcuts,\n * and a toolbar dropdown. Handles both TextSelection and NodeSelection.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { findNodePath } from '../../model/NodeResolver.js';\nimport { isNodeSelection, isTextSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\n\n// --- Public Types ---\n\nexport type BlockAlignment = 'left' | 'center' | 'right' | 'justify';\n\nexport interface AlignmentConfig {\n\t/** Which alignments to expose. Defaults to all four. */\n\treadonly alignments: readonly BlockAlignment[];\n\t/** Block types that support alignment. Defaults to paragraph + heading + title + subtitle + table_cell + image. */\n\treadonly alignableTypes: readonly string[];\n\t/** Per-type default alignment (e.g. `{ image: 'center' }`). Falls back to `'left'`. */\n\treadonly defaults: Readonly<Record<string, BlockAlignment>>;\n\t/** When true, a separator is rendered after the toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\n// --- Constants ---\n\nconst DEFAULT_CONFIG: AlignmentConfig = {\n\talignments: ['left', 'center', 'right', 'justify'],\n\talignableTypes: ['paragraph', 'heading', 'title', 'subtitle', 'table_cell', 'image'],\n\tdefaults: { image: 'center' },\n};\n\nconst ALIGNMENT_LABELS: Readonly<Record<BlockAlignment, string>> = {\n\tleft: 'Align Left',\n\tcenter: 'Align Center',\n\tright: 'Align Right',\n\tjustify: 'Justify',\n};\n\nexport const ALIGNMENT_ICONS: Readonly<Record<BlockAlignment, string>> = {\n\tleft: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z\"/></svg>',\n\tcenter:\n\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z\"/></svg>',\n\tright:\n\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z\"/></svg>',\n\tjustify:\n\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M3 21h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18V7H3v2zM3 3v2h18V3H3z\"/></svg>',\n};\n\n// --- Plugin ---\n\nexport class AlignmentPlugin implements Plugin {\n\treadonly id = 'alignment';\n\treadonly name = 'Alignment';\n\treadonly priority = 90;\n\n\tprivate readonly config: AlignmentConfig;\n\tprivate alignableTypes!: ReadonlySet<string>;\n\n\tconstructor(config?: Partial<AlignmentConfig>) {\n\t\tthis.config = {\n\t\t\t...DEFAULT_CONFIG,\n\t\t\t...config,\n\t\t\tdefaults: { ...DEFAULT_CONFIG.defaults, ...config?.defaults },\n\t\t};\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.alignableTypes = new Set(this.config.alignableTypes);\n\t\tthis.patchNodeSpecs(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerToolbarItem(context);\n\t\tthis.registerMiddleware(context);\n\t}\n\n\t// --- NodeSpec Patching ---\n\n\t/**\n\t * Patches existing NodeSpecs for alignable block types to support the\n\t * `align` attribute and render it as an inline style. Skips types\n\t * that already define an `align` attribute in their spec.\n\t */\n\tprivate patchNodeSpecs(context: PluginContext): void {\n\t\tconst registry = context.getSchemaRegistry();\n\n\t\tfor (const type of this.config.alignableTypes) {\n\t\t\tconst spec = registry.getNodeSpec(type);\n\t\t\tif (!spec) continue;\n\n\t\t\t// Skip types that already declare an `align` attr (e.g. image)\n\t\t\tif (spec.attrs?.align) continue;\n\n\t\t\tconst originalToDOM = spec.toDOM;\n\t\t\tconst defaultAlign: BlockAlignment = this.config.defaults[type] ?? 'left';\n\n\t\t\tregistry.removeNodeSpec(type);\n\t\t\tregistry.registerNodeSpec({\n\t\t\t\t...spec,\n\t\t\t\tattrs: {\n\t\t\t\t\t...spec.attrs,\n\t\t\t\t\talign: { default: defaultAlign },\n\t\t\t\t},\n\t\t\t\ttoDOM(node) {\n\t\t\t\t\tconst el = originalToDOM.call(spec, node);\n\t\t\t\t\tapplyAlignment(el, node);\n\t\t\t\t\treturn el;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Commands ---\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tfor (const alignment of this.config.alignments) {\n\t\t\tcontext.registerCommand(`align${capitalize(alignment)}`, () => {\n\t\t\t\treturn this.setAlignment(context, alignment);\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Keymaps ---\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tconst bindings: Record<string, () => boolean> = {};\n\n\t\tif (this.config.alignments.includes('left')) {\n\t\t\tbindings['Mod-Shift-L'] = () => context.executeCommand('alignLeft');\n\t\t}\n\t\tif (this.config.alignments.includes('center')) {\n\t\t\tbindings['Mod-Shift-E'] = () => context.executeCommand('alignCenter');\n\t\t}\n\t\tif (this.config.alignments.includes('right')) {\n\t\t\tbindings['Mod-Shift-R'] = () => context.executeCommand('alignRight');\n\t\t}\n\t\tif (this.config.alignments.includes('justify')) {\n\t\t\tbindings['Mod-Shift-J'] = () => context.executeCommand('alignJustify');\n\t\t}\n\n\t\tif (Object.keys(bindings).length > 0) {\n\t\t\tcontext.registerKeymap(bindings);\n\t\t}\n\t}\n\n\t// --- Toolbar ---\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst dropdownItems = this.config.alignments.map((alignment) => ({\n\t\t\tlabel: ALIGNMENT_LABELS[alignment],\n\t\t\tcommand: `align${capitalize(alignment)}`,\n\t\t\ticon: ALIGNMENT_ICONS[alignment],\n\t\t}));\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'alignment',\n\t\t\tgroup: 'block',\n\t\t\ticon: ALIGNMENT_ICONS.left,\n\t\t\tlabel: 'Alignment',\n\t\t\ttooltip: 'Alignment',\n\t\t\tcommand: 'alignLeft',\n\t\t\tpriority: 60,\n\t\t\tpopupType: 'dropdown',\n\t\t\tpopupConfig: { items: dropdownItems },\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\tisActive: (state) => this.isNonDefaultAlignment(state),\n\t\t\tisEnabled: (state) => this.isAlignable(state),\n\t\t});\n\t}\n\n\t// --- Middleware ---\n\n\t/**\n\t * Preserves the `align` attribute when other plugins change the block\n\t * type (e.g. paragraph → heading) via `setBlockType`, which replaces attrs.\n\t */\n\tprivate registerMiddleware(context: PluginContext): void {\n\t\tcontext.registerMiddleware((tr, _state, next) => {\n\t\t\tlet patched = false;\n\n\t\t\tconst patchedSteps = tr.steps.map((step) => {\n\t\t\t\tif (step.type !== 'setBlockType') return step;\n\t\t\t\tif (!this.alignableTypes.has(step.nodeType)) return step;\n\n\t\t\t\tconst prevAlign = step.previousAttrs?.align;\n\t\t\t\tif (!prevAlign || prevAlign === 'left') return step;\n\n\t\t\t\t// Carry forward align into new attrs\n\t\t\t\tpatched = true;\n\t\t\t\treturn {\n\t\t\t\t\t...step,\n\t\t\t\t\tattrs: { ...step.attrs, align: prevAlign },\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tnext(patched ? { ...tr, steps: patchedSteps } : tr);\n\t\t});\n\t}\n\n\t// --- Alignment Logic ---\n\n\t/**\n\t * Gets the selected block, handling both TextSelection and NodeSelection.\n\t */\n\tprivate getSelectedBlock(state: EditorState): BlockNode | undefined {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) {\n\t\t\treturn state.getBlock(sel.nodeId);\n\t\t}\n\t\tif (isTextSelection(sel)) {\n\t\t\treturn state.getBlock(sel.anchor.blockId);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Gets the block ID of the selected block, handling both selection types.\n\t */\n\tprivate getSelectedBlockId(state: EditorState): BlockId | undefined {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return sel.nodeId;\n\t\tif (isTextSelection(sel)) return sel.anchor.blockId;\n\t\treturn undefined;\n\t}\n\n\tprivate setAlignment(context: PluginContext, alignment: BlockAlignment): boolean {\n\t\tconst state = context.getState();\n\t\tconst block = this.getSelectedBlock(state);\n\t\tif (!block || !this.alignableTypes.has(block.type)) return false;\n\n\t\tconst blockId = this.getSelectedBlockId(state);\n\t\tif (!blockId) return false;\n\n\t\tconst path = findNodePath(state.doc, blockId);\n\t\tif (!path) return false;\n\n\t\tconst newAttrs = { ...block.attrs, align: alignment };\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setNodeAttr(path as BlockId[], newAttrs)\n\t\t\t.setSelection(state.selection)\n\t\t\t.build();\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate isNonDefaultAlignment(state: EditorState): boolean {\n\t\tconst block = this.getSelectedBlock(state);\n\t\tif (!block || !this.alignableTypes.has(block.type)) return false;\n\t\tconst align = block.attrs?.align;\n\t\tconst defaultAlign: BlockAlignment = this.config.defaults[block.type] ?? 'left';\n\t\treturn align != null && align !== defaultAlign;\n\t}\n\n\tprivate isAlignable(state: EditorState): boolean {\n\t\tconst block = this.getSelectedBlock(state);\n\t\treturn block != null && this.alignableTypes.has(block.type);\n\t}\n}\n\n// --- Helpers ---\n\nfunction applyAlignment(el: HTMLElement, node: BlockNode): void {\n\tconst align = node.attrs?.align;\n\tif (typeof align === 'string' && align !== 'left') {\n\t\tel.style.textAlign = align;\n\t}\n}\n\nfunction capitalize(s: string): string {\n\treturn s.charAt(0).toUpperCase() + s.slice(1);\n}\n","/**\n * FontPlugin: registers a font-family mark, a combobox-style toolbar selector\n * for font selection, and a developer-friendly API for registering custom fonts\n * (WOFF2, TTF, OTF).\n */\n\nimport { isMarkOfType } from '../../model/AttrRegistry.js';\nimport { getBlockMarksAtOffset, getTextChildren, hasMark } from '../../model/Document.js';\nimport type { BlockNode, Mark } from '../../model/Document.js';\nimport { isCollapsed, isNodeSelection, selectionRange } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { ToolbarServiceKey } from '../toolbar/ToolbarPlugin.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tfont: { family: string };\n\t}\n}\n\n// --- Public Types ---\n\n/** Describes a single @font-face source. */\nexport interface FontFaceDescriptor {\n\t/** CSS `src` value, e.g. `\"url('/fonts/My.woff2') format('woff2')\"`. */\n\treadonly src: string;\n\t/** Font weight, e.g. `'400'` or `'300 700'` for variable fonts. */\n\treadonly weight?: string;\n\t/** Font style, e.g. `'normal'` or `'italic'`. */\n\treadonly style?: string;\n\t/** Font display strategy. Defaults to `'swap'`. */\n\treadonly display?: string;\n}\n\n/** Defines a font available in the editor. */\nexport interface FontDefinition {\n\t/** Display name shown in the toolbar dropdown. */\n\treadonly name: string;\n\t/** CSS `font-family` value, e.g. `\"'Fira Code', monospace\"`. */\n\treadonly family: string;\n\t/** Font category for grouping in the UI. */\n\treadonly category?: 'serif' | 'sans-serif' | 'monospace' | 'display' | 'handwriting';\n\t/**\n\t * Optional `@font-face` descriptors. When provided, the plugin\n\t * auto-injects the corresponding CSS rules into the document.\n\t */\n\treadonly fontFaces?: readonly FontFaceDescriptor[];\n}\n\n// --- Configuration ---\n\nexport interface FontConfig {\n\t/**\n\t * Fonts available in the editor. System fonts require no `fontFaces`.\n\t * Custom fonts with `fontFaces` get their `@font-face` rules auto-injected.\n\t *\n\t * Use `STARTER_FONTS` for a pre-configured set of fonts:\n\t * ```ts\n\t * new FontPlugin({ fonts: [...STARTER_FONTS] })\n\t * ```\n\t */\n\treadonly fonts: readonly FontDefinition[];\n\t/**\n\t * Name of the font that acts as the editor's default.\n\t * Selecting this font removes the mark (since the editor already uses it).\n\t * Defaults to the first font in the list.\n\t */\n\treadonly defaultFont?: string;\n\t/** When true, a separator is rendered after the font toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\n// --- Plugin ---\n\nexport class FontPlugin implements Plugin {\n\treadonly id = 'font';\n\treadonly name = 'Font';\n\treadonly priority = 22;\n\n\tprivate readonly config: FontConfig;\n\tprivate injectedStyleElement: HTMLStyleElement | null = null;\n\tprivate context: PluginContext | null = null;\n\tprivate comboLabel: HTMLSpanElement | null = null;\n\n\tconstructor(config: FontConfig) {\n\t\tthis.config = config;\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.context = context;\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerToolbarItem(context);\n\t\tthis.injectFontFaces();\n\t}\n\n\tdestroy(): void {\n\t\tthis.injectedStyleElement?.remove();\n\t\tthis.injectedStyleElement = null;\n\t\tthis.context = null;\n\t\tthis.comboLabel = null;\n\t}\n\n\tonStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tthis.updateComboLabel(newState);\n\t}\n\n\t// --- Schema ---\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'font',\n\t\t\trank: 6,\n\t\t\tattrs: {\n\t\t\t\tfamily: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst span: HTMLElement = document.createElement('span');\n\t\t\t\tconst family: string = mark.attrs?.family ?? '';\n\t\t\t\tif (family) {\n\t\t\t\t\tspan.style.fontFamily = family;\n\t\t\t\t}\n\t\t\t\treturn span;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst family: string = String(mark.attrs?.family ?? '');\n\t\t\t\tif (!family) return content;\n\t\t\t\treturn `<span style=\"font-family: ${family}\">${content}</span>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst family: string = el.style.fontFamily;\n\t\t\t\t\t\tif (!family) return false;\n\t\t\t\t\t\treturn { family };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['span'] },\n\t\t});\n\t}\n\n\t// --- Commands ---\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('removeFont', () => {\n\t\t\tconst state: EditorState = context.getState();\n\t\t\treturn this.removeFont(context, state);\n\t\t});\n\n\t\tcontext.registerCommand('setFont', () => {\n\t\t\treturn false;\n\t\t});\n\t}\n\n\t// --- Toolbar ---\n\n\tprivate get defaultFont(): FontDefinition {\n\t\tif (this.config.defaultFont) {\n\t\t\tconst found: FontDefinition | undefined = this.config.fonts.find(\n\t\t\t\t(f) => f.name === this.config.defaultFont,\n\t\t\t);\n\t\t\tif (found) return found;\n\t\t}\n\t\tconst first: FontDefinition | undefined = this.config.fonts[0];\n\t\tif (!first) throw new Error('FontPlugin: fonts list is empty');\n\t\treturn first;\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\t// The icon content renders as a combobox label + dropdown arrow.\n\t\t// The actual label text is updated via onStateChange → updateComboLabel.\n\t\tconst defaultName: string = this.defaultFont.name;\n\t\tconst label: string = `<span class=\"notectl-font-select__label\" data-font-label>${defaultName}</span>`;\n\t\tconst arrow = '<span class=\"notectl-font-select__arrow\">\\u25BE</span>';\n\t\tconst icon = `${label}${arrow}`;\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'font',\n\t\t\tgroup: 'format',\n\t\t\ticon,\n\t\t\tlabel: 'Font',\n\t\t\ttooltip: 'Font Family',\n\t\t\tcommand: 'removeFont',\n\t\t\tpriority: 5,\n\t\t\tpopupType: 'custom',\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\trenderPopup: (container, ctx) => {\n\t\t\t\tthis.renderFontPopup(container, ctx);\n\t\t\t},\n\t\t\tisActive: (state) => this.isFontActive(state),\n\t\t});\n\t}\n\n\tprivate updateComboLabel(state: EditorState): void {\n\t\t// Lazily find the label element in the DOM\n\t\tif (!this.comboLabel) {\n\t\t\tconst container: HTMLElement | undefined = this.context?.getPluginContainer('top');\n\t\t\tif (!container) return;\n\t\t\tthis.comboLabel = container.querySelector<HTMLSpanElement>('[data-font-label]') ?? null;\n\t\t\tif (!this.comboLabel) return;\n\t\t}\n\n\t\tconst activeFamily: string | null = this.getActiveFont(state);\n\t\tconst displayName: string = this.resolveFontName(activeFamily);\n\t\tthis.comboLabel.textContent = displayName;\n\t}\n\n\tprivate resolveFontName(family: string | null): string {\n\t\tif (!family) return this.defaultFont.name;\n\t\tconst match: FontDefinition | undefined = this.config.fonts.find((f) => f.family === family);\n\t\treturn match?.name ?? (family.split(',')[0] ?? '').trim().replace(/'/g, '');\n\t}\n\n\t// --- State Queries ---\n\n\tprivate isFontActive(state: EditorState): boolean {\n\t\treturn this.getActiveFont(state) !== null;\n\t}\n\n\tgetActiveFont(state: EditorState): string | null {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return null;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tif (state.storedMarks) {\n\t\t\t\tconst mark = state.storedMarks.find((m) => m.type === 'font');\n\t\t\t\treturn mark && isMarkOfType(mark, 'font') ? (mark.attrs.family ?? null) : null;\n\t\t\t}\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return null;\n\t\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\t\tconst mark = marks.find((m) => m.type === 'font');\n\t\t\treturn mark && isMarkOfType(mark, 'font') ? (mark.attrs.family ?? null) : null;\n\t\t}\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return null;\n\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\tconst mark = marks.find((m) => m.type === 'font');\n\t\treturn mark && isMarkOfType(mark, 'font') ? (mark.attrs.family ?? null) : null;\n\t}\n\n\t// --- Font Application ---\n\n\tapplyFont(context: PluginContext, state: EditorState, family: string): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!anchorBlock) return false;\n\t\t\tconst currentMarks =\n\t\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\t\tconst withoutFont = currentMarks.filter((m) => m.type !== 'font');\n\t\t\tconst newMarks = [...withoutFont, { type: markType('font'), attrs: { family } }];\n\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx: number = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx: number = blockOrder.indexOf(range.to.blockId);\n\n\t\tconst mark = { type: markType('font'), attrs: { family } };\n\n\t\tfor (let i: number = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen: number = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from: number = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to: number = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\tconst existing: Mark | undefined = this.findFontMarkInRange(block, from, to);\n\t\t\t\tif (existing) {\n\t\t\t\t\tbuilder.removeMark(blockId, from, to, existing);\n\t\t\t\t}\n\t\t\t\tbuilder.addMark(blockId, from, to, mark);\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\tprivate removeFont(context: PluginContext, state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!anchorBlock) return false;\n\t\t\tconst currentMarks =\n\t\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\t\tif (!hasMark(currentMarks, markType('font'))) return false;\n\n\t\t\tconst newMarks = currentMarks.filter((m) => m.type !== 'font');\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx: number = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx: number = blockOrder.indexOf(range.to.blockId);\n\n\t\tfor (let i: number = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen: number = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from: number = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to: number = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\tconst existing: Mark | undefined = this.findFontMarkInRange(block, from, to);\n\t\t\t\tif (existing) {\n\t\t\t\t\tbuilder.removeMark(blockId, from, to, existing);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\t/** Finds the first font mark in a block's text range (for proper step inversion). */\n\tprivate findFontMarkInRange(block: BlockNode, from: number, to: number): Mark | undefined {\n\t\tconst textChildren = getTextChildren(block);\n\t\tlet pos = 0;\n\t\tfor (const node of textChildren) {\n\t\t\tconst nodeEnd: number = pos + node.text.length;\n\t\t\tif (nodeEnd > from && pos < to) {\n\t\t\t\tconst fontMark: Mark | undefined = node.marks.find((m) => m.type === 'font');\n\t\t\t\tif (fontMark) return fontMark;\n\t\t\t}\n\t\t\tpos = nodeEnd;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t// --- @font-face Injection ---\n\n\tprivate injectFontFaces(): void {\n\t\tconst rules: string[] = [];\n\n\t\tfor (const font of this.config.fonts) {\n\t\t\tif (!font.fontFaces?.length) continue;\n\n\t\t\tfor (const face of font.fontFaces) {\n\t\t\t\tconst familyName: string = (font.family.split(',')[0] ?? '').trim().replace(/'/g, '');\n\t\t\t\tconst declarations: string[] = [`font-family: '${familyName}'`, `src: ${face.src}`];\n\t\t\t\tif (face.weight) {\n\t\t\t\t\tdeclarations.push(`font-weight: ${face.weight}`);\n\t\t\t\t}\n\t\t\t\tif (face.style) {\n\t\t\t\t\tdeclarations.push(`font-style: ${face.style}`);\n\t\t\t\t}\n\t\t\t\tdeclarations.push(`font-display: ${face.display ?? 'swap'}`);\n\n\t\t\t\trules.push(`@font-face {\\n\\t${declarations.join(';\\n\\t')};\\n}`);\n\t\t\t}\n\t\t}\n\n\t\tif (rules.length === 0) return;\n\n\t\tconst style: HTMLStyleElement = document.createElement('style');\n\t\tstyle.setAttribute('data-notectl-fonts', '');\n\t\tstyle.textContent = rules.join('\\n\\n');\n\t\tdocument.head.appendChild(style);\n\t\tthis.injectedStyleElement = style;\n\t}\n\n\t// --- Popup Rendering ---\n\n\tprivate dismissPopup(): void {\n\t\tconst toolbar = this.context?.getService(ToolbarServiceKey);\n\t\ttoolbar?.closePopup();\n\t}\n\n\tprivate renderFontPopup(container: HTMLElement, context: PluginContext): void {\n\t\tcontainer.classList.add('notectl-font-picker');\n\n\t\tconst state: EditorState = context.getState();\n\t\tconst activeFont: string | null = this.getActiveFont(state);\n\t\tconst defaultFamily: string = this.defaultFont.family;\n\n\t\tconst list: HTMLDivElement = document.createElement('div');\n\t\tlist.className = 'notectl-font-picker__list';\n\n\t\tfor (const font of this.config.fonts) {\n\t\t\tconst isDefault: boolean = font.family === defaultFamily;\n\t\t\tconst isActive: boolean = isDefault\n\t\t\t\t? !activeFont || activeFont === font.family\n\t\t\t\t: activeFont === font.family;\n\n\t\t\tconst item: HTMLButtonElement = this.createFontItem(\n\t\t\t\tfont.name,\n\t\t\t\tfont.family,\n\t\t\t\tisActive,\n\t\t\t\t(e: MouseEvent) => {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t\tif (isDefault) {\n\t\t\t\t\t\tcontext.executeCommand('removeFont');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.applyFont(context, context.getState(), font.family);\n\t\t\t\t\t}\n\t\t\t\t\tthis.dismissPopup();\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (font.category) {\n\t\t\t\titem.setAttribute('data-category', font.category);\n\t\t\t}\n\n\t\t\tlist.appendChild(item);\n\t\t}\n\n\t\tcontainer.appendChild(list);\n\t}\n\n\tprivate createFontItem(\n\t\tname: string,\n\t\tfamily: string,\n\t\tisActive: boolean,\n\t\thandler: (e: MouseEvent) => void,\n\t): HTMLButtonElement {\n\t\tconst item: HTMLButtonElement = document.createElement('button');\n\t\titem.type = 'button';\n\t\titem.className = 'notectl-font-picker__item';\n\n\t\tif (isActive) {\n\t\t\titem.classList.add('notectl-font-picker__item--active');\n\t\t}\n\n\t\t// Checkmark indicator\n\t\tconst check: HTMLSpanElement = document.createElement('span');\n\t\tcheck.className = 'notectl-font-picker__check';\n\t\tcheck.textContent = isActive ? '\\u2713' : '';\n\t\titem.appendChild(check);\n\n\t\t// Font name label (rendered in the font itself for preview)\n\t\tconst label: HTMLSpanElement = document.createElement('span');\n\t\tlabel.className = 'notectl-font-picker__label';\n\t\tlabel.textContent = name;\n\t\tif (family) {\n\t\t\tlabel.style.fontFamily = family;\n\t\t}\n\t\titem.appendChild(label);\n\n\t\titem.addEventListener('mousedown', handler);\n\t\treturn item;\n\t}\n}\n","/**\n * FontSizePlugin: registers a fontSize mark with attrs, a combobox-style\n * toolbar selector with WCAG-accessible popup, and commands for\n * increasing / decreasing font size.\n */\n\nimport { isMarkOfType } from '../../model/AttrRegistry.js';\nimport { getBlockMarksAtOffset, hasMark } from '../../model/Document.js';\nimport { isCollapsed, isNodeSelection, selectionRange } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { ToolbarServiceKey } from '../toolbar/ToolbarPlugin.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tfontSize: { size: string };\n\t}\n}\n\n// --- Constants ---\n\n/** Default preset sizes shown in the font size dropdown. */\nexport const DEFAULT_FONT_SIZES: readonly number[] = [\n\t8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 32, 36, 48, 64, 72, 96,\n];\n\nconst DEFAULT_FONT_SIZE = 16;\nconst MIN_CUSTOM_SIZE = 1;\nconst MAX_CUSTOM_SIZE = 400;\n\n// --- Configuration ---\n\nexport interface FontSizeConfig {\n\t/**\n\t * Preset sizes shown in the font size dropdown.\n\t * Must contain positive integers. Values are sorted and deduplicated automatically.\n\t * Defaults to {@link DEFAULT_FONT_SIZES} when omitted or empty.\n\t */\n\treadonly sizes?: readonly number[];\n\t/**\n\t * The base font size that text has when no fontSize mark is applied.\n\t * Shown as the initial value in the toolbar combo and used as the\n\t * \"neutral\" size — selecting it removes the mark instead of applying one.\n\t * Defaults to 16.\n\t */\n\treadonly defaultSize?: number;\n\t/** When true, a separator is rendered after the fontSize toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: FontSizeConfig = {};\n\n// --- Plugin ---\n\nexport class FontSizePlugin implements Plugin {\n\treadonly id = 'fontSize';\n\treadonly name = 'Font Size';\n\treadonly priority = 21;\n\n\tprivate readonly config: FontSizeConfig;\n\tprivate readonly sizes: readonly number[];\n\tprivate readonly defaultSize: number;\n\tprivate context: PluginContext | null = null;\n\tprivate comboLabel: HTMLSpanElement | null = null;\n\n\tconstructor(config?: Partial<FontSizeConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t\tthis.sizes = resolveSizes(config?.sizes);\n\t\tthis.defaultSize = resolveDefaultSize(config?.defaultSize);\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.context = context;\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerToolbarItem(context);\n\t\tthis.applyDefaultSizeToContainer(context);\n\t}\n\n\tdestroy(): void {\n\t\tthis.context = null;\n\t\tthis.comboLabel = null;\n\t}\n\n\tonStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tthis.updateComboLabel(newState);\n\t}\n\n\t// --- Schema ---\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'fontSize',\n\t\t\trank: 4,\n\t\t\tattrs: {\n\t\t\t\tsize: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst span: HTMLElement = document.createElement('span');\n\t\t\t\tconst size: string = mark.attrs?.size ?? '';\n\t\t\t\tif (size) {\n\t\t\t\t\tspan.style.fontSize = size;\n\t\t\t\t}\n\t\t\t\treturn span;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst size: string = String(mark.attrs?.size ?? '');\n\t\t\t\tif (!size) return content;\n\t\t\t\treturn `<span style=\"font-size: ${size}\">${content}</span>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst size: string = el.style.fontSize;\n\t\t\t\t\t\tif (!size) return false;\n\t\t\t\t\t\treturn { size };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['span'] },\n\t\t});\n\t}\n\n\t// --- Commands ---\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('removeFontSize', () => {\n\t\t\tconst state: EditorState = context.getState();\n\t\t\treturn this.removeFontSize(context, state);\n\t\t});\n\n\t\tcontext.registerCommand('setFontSize', () => {\n\t\t\treturn false;\n\t\t});\n\n\t\tcontext.registerCommand('increaseFontSize', () => {\n\t\t\tconst state: EditorState = context.getState();\n\t\t\treturn this.stepFontSize(context, state, 'up');\n\t\t});\n\n\t\tcontext.registerCommand('decreaseFontSize', () => {\n\t\t\tconst state: EditorState = context.getState();\n\t\t\treturn this.stepFontSize(context, state, 'down');\n\t\t});\n\t}\n\n\t// --- Keymaps ---\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift-+': () => {\n\t\t\t\tconst state: EditorState = context.getState();\n\t\t\t\treturn this.stepFontSize(context, state, 'up');\n\t\t\t},\n\t\t\t'Mod-Shift-_': () => {\n\t\t\t\tconst state: EditorState = context.getState();\n\t\t\t\treturn this.stepFontSize(context, state, 'down');\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- Toolbar ---\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon: string = `<span class=\"notectl-font-size-select__label\" data-font-size-label>${this.defaultSize}</span><span class=\"notectl-font-size-select__arrow\">\\u25BE</span>`;\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'fontSize',\n\t\t\tgroup: 'format',\n\t\t\ticon,\n\t\t\tlabel: 'Font Size',\n\t\t\ttooltip: 'Font Size',\n\t\t\tcommand: 'removeFontSize',\n\t\t\tpriority: 6,\n\t\t\tpopupType: 'custom',\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\trenderPopup: (container, ctx) => {\n\t\t\t\tthis.renderFontSizePopup(container, ctx);\n\t\t\t},\n\t\t\tisActive: (state) => this.isFontSizeActive(state),\n\t\t});\n\t}\n\n\t/**\n\t * Sets the configured default font size on the editor content container\n\t * so that unformatted text renders at the correct size instead of the\n\t * browser default (16px).\n\t */\n\tprivate applyDefaultSizeToContainer(context: PluginContext): void {\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tcontainer.style.fontSize = `${this.defaultSize}px`;\n\t}\n\n\tprivate updateComboLabel(state: EditorState): void {\n\t\tif (!this.comboLabel) {\n\t\t\tconst container: HTMLElement | undefined = this.context?.getPluginContainer('top');\n\t\t\tif (!container) return;\n\t\t\tthis.comboLabel = container.querySelector<HTMLSpanElement>('[data-font-size-label]') ?? null;\n\t\t\tif (!this.comboLabel) return;\n\t\t}\n\n\t\tconst activeSize: number = this.getActiveSizeNumeric(state);\n\t\tthis.comboLabel.textContent = String(activeSize);\n\t}\n\n\t// --- State Queries ---\n\n\tprivate isFontSizeActive(state: EditorState): boolean {\n\t\treturn this.getActiveSize(state) !== null;\n\t}\n\n\tprivate getActiveSize(state: EditorState): string | null {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return null;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tif (state.storedMarks) {\n\t\t\t\tconst mark = state.storedMarks.find((m) => m.type === 'fontSize');\n\t\t\t\treturn mark && isMarkOfType(mark, 'fontSize') ? (mark.attrs.size ?? null) : null;\n\t\t\t}\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return null;\n\t\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\t\tconst mark = marks.find((m) => m.type === 'fontSize');\n\t\t\treturn mark && isMarkOfType(mark, 'fontSize') ? (mark.attrs.size ?? null) : null;\n\t\t}\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return null;\n\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\tconst mark = marks.find((m) => m.type === 'fontSize');\n\t\treturn mark && isMarkOfType(mark, 'fontSize') ? (mark.attrs.size ?? null) : null;\n\t}\n\n\tprivate getActiveSizeNumeric(state: EditorState): number {\n\t\tconst raw: string | null = this.getActiveSize(state);\n\t\tif (!raw) return this.defaultSize;\n\t\tconst parsed: number = Number.parseInt(raw, 10);\n\t\treturn Number.isNaN(parsed) ? this.defaultSize : parsed;\n\t}\n\n\t// --- Font Size Application ---\n\n\tprivate applyFontSize(context: PluginContext, state: EditorState, size: string): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!anchorBlock) return false;\n\t\t\tconst currentMarks =\n\t\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\t\tconst withoutSize = currentMarks.filter((m) => m.type !== 'fontSize');\n\t\t\tconst newMarks = [...withoutSize, { type: markType('fontSize'), attrs: { size } }];\n\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx: number = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx: number = blockOrder.indexOf(range.to.blockId);\n\n\t\tconst mark = { type: markType('fontSize'), attrs: { size } };\n\n\t\tfor (let i: number = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen: number = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from: number = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to: number = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\tbuilder.removeMark(blockId, from, to, {\n\t\t\t\t\ttype: markType('fontSize'),\n\t\t\t\t});\n\t\t\t\tbuilder.addMark(blockId, from, to, mark);\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\tprivate removeFontSize(context: PluginContext, state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!anchorBlock) return false;\n\t\t\tconst currentMarks =\n\t\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\t\tif (!hasMark(currentMarks, markType('fontSize'))) return false;\n\n\t\t\tconst newMarks = currentMarks.filter((m) => m.type !== 'fontSize');\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx: number = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx: number = blockOrder.indexOf(range.to.blockId);\n\n\t\tfor (let i: number = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen: number = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from: number = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to: number = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\tbuilder.removeMark(blockId, from, to, {\n\t\t\t\t\ttype: markType('fontSize'),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\t// --- Increase / Decrease ---\n\n\tprivate stepFontSize(\n\t\tcontext: PluginContext,\n\t\tstate: EditorState,\n\t\tdirection: 'up' | 'down',\n\t): boolean {\n\t\tconst current: number = this.getActiveSizeNumeric(state);\n\t\tconst next: number | null = this.getNextPresetSize(current, direction);\n\t\tif (next === null) return false;\n\n\t\tif (next === this.defaultSize) {\n\t\t\treturn this.removeFontSize(context, state);\n\t\t}\n\t\treturn this.applyFontSize(context, state, `${next}px`);\n\t}\n\n\tprivate getNextPresetSize(current: number, direction: 'up' | 'down'): number | null {\n\t\tif (direction === 'up') {\n\t\t\tfor (const size of this.sizes) {\n\t\t\t\tif (size > current) return size;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\tfor (let i: number = this.sizes.length - 1; i >= 0; i--) {\n\t\t\tconst size: number | undefined = this.sizes[i];\n\t\t\tif (size !== undefined && size < current) return size;\n\t\t}\n\t\treturn null;\n\t}\n\n\t// --- Popup Rendering ---\n\n\tprivate dismissPopup(): void {\n\t\tconst toolbar = this.context?.getService(ToolbarServiceKey);\n\t\ttoolbar?.closePopup();\n\t}\n\n\tprivate renderFontSizePopup(container: HTMLElement, context: PluginContext): void {\n\t\tcontainer.classList.add('notectl-font-size-picker');\n\n\t\tconst state: EditorState = context.getState();\n\t\tconst currentSize: number = this.getActiveSizeNumeric(state);\n\t\tlet focusedIndex = -1;\n\n\t\t// --- Custom Input ---\n\t\tconst inputWrapper: HTMLDivElement = document.createElement('div');\n\t\tinputWrapper.className = 'notectl-font-size-picker__input-wrapper';\n\n\t\tconst input: HTMLInputElement = document.createElement('input');\n\t\tinput.type = 'number';\n\t\tinput.className = 'notectl-font-size-picker__input';\n\t\tinput.min = String(MIN_CUSTOM_SIZE);\n\t\tinput.max = String(MAX_CUSTOM_SIZE);\n\t\tinput.value = String(currentSize);\n\t\tinput.setAttribute('aria-label', 'Custom font size');\n\n\t\tinputWrapper.appendChild(input);\n\t\tcontainer.appendChild(inputWrapper);\n\n\t\t// --- List ---\n\t\tconst list: HTMLDivElement = document.createElement('div');\n\t\tlist.className = 'notectl-font-size-picker__list';\n\t\tlist.setAttribute('role', 'listbox');\n\t\tlist.setAttribute('aria-label', 'Font sizes');\n\n\t\tconst items: HTMLButtonElement[] = [];\n\n\t\tfor (let idx = 0; idx < this.sizes.length; idx++) {\n\t\t\tconst size: number | undefined = this.sizes[idx];\n\t\t\tif (size === undefined) continue;\n\t\t\tconst isActive: boolean = size === currentSize;\n\t\t\tconst itemId: string = `notectl-font-size-option-${size}`;\n\n\t\t\tconst item: HTMLButtonElement = document.createElement('button');\n\t\t\titem.type = 'button';\n\t\t\titem.id = itemId;\n\t\t\titem.className = 'notectl-font-size-picker__item';\n\t\t\titem.setAttribute('role', 'option');\n\t\t\titem.setAttribute('aria-selected', String(isActive));\n\n\t\t\tif (isActive) {\n\t\t\t\titem.classList.add('notectl-font-size-picker__item--active');\n\t\t\t}\n\n\t\t\tconst check: HTMLSpanElement = document.createElement('span');\n\t\t\tcheck.className = 'notectl-font-size-picker__check';\n\t\t\tcheck.textContent = isActive ? '\\u2713' : '';\n\t\t\titem.appendChild(check);\n\n\t\t\tconst label: HTMLSpanElement = document.createElement('span');\n\t\t\tlabel.className = 'notectl-font-size-picker__label';\n\t\t\tlabel.textContent = String(size);\n\t\t\titem.appendChild(label);\n\n\t\t\titem.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.selectSize(context, size);\n\t\t\t\tthis.dismissPopup();\n\t\t\t});\n\n\t\t\titems.push(item);\n\t\t\tlist.appendChild(item);\n\t\t}\n\n\t\tcontainer.appendChild(list);\n\n\t\t// --- Scroll active item into view ---\n\t\tconst activeIdx: number = this.sizes.indexOf(currentSize);\n\t\tif (activeIdx >= 0) {\n\t\t\tconst activeItem: HTMLButtonElement | undefined = items[activeIdx];\n\t\t\tif (activeItem) {\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tactiveItem.scrollIntoView({ block: 'nearest' });\n\t\t\t\t});\n\t\t\t\tlist.setAttribute('aria-activedescendant', activeItem.id);\n\t\t\t}\n\t\t}\n\n\t\t// --- Keyboard helpers ---\n\t\tconst setFocusedIndex = (idx: number): void => {\n\t\t\tif (focusedIndex >= 0 && focusedIndex < items.length) {\n\t\t\t\titems[focusedIndex]?.classList.remove('notectl-font-size-picker__item--focused');\n\t\t\t}\n\t\t\tfocusedIndex = idx;\n\t\t\tconst focused: HTMLButtonElement | undefined = items[focusedIndex];\n\t\t\tif (focusedIndex >= 0 && focusedIndex < items.length && focused) {\n\t\t\t\tfocused.classList.add('notectl-font-size-picker__item--focused');\n\t\t\t\tfocused.scrollIntoView({ block: 'nearest' });\n\t\t\t\tlist.setAttribute('aria-activedescendant', focused.id);\n\t\t\t}\n\t\t};\n\n\t\t// --- Input Events ---\n\t\tinput.addEventListener('keydown', (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'Enter') {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst val: number = Number.parseInt(input.value, 10);\n\t\t\t\tif (!Number.isNaN(val) && val >= MIN_CUSTOM_SIZE && val <= MAX_CUSTOM_SIZE) {\n\t\t\t\t\tthis.selectSize(context, val);\n\t\t\t\t\tthis.dismissPopup();\n\t\t\t\t}\n\t\t\t} else if (e.key === 'ArrowDown') {\n\t\t\t\te.preventDefault();\n\t\t\t\tsetFocusedIndex(0);\n\t\t\t\titems[0]?.focus();\n\t\t\t} else if (e.key === 'Escape') {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.dismissPopup();\n\t\t\t}\n\t\t});\n\n\t\t// --- List Keyboard Navigation ---\n\t\tlist.addEventListener('keydown', (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'ArrowDown') {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (focusedIndex < items.length - 1) {\n\t\t\t\t\tsetFocusedIndex(focusedIndex + 1);\n\t\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\t}\n\t\t\t} else if (e.key === 'ArrowUp') {\n\t\t\t\te.preventDefault();\n\t\t\t\tif (focusedIndex > 0) {\n\t\t\t\t\tsetFocusedIndex(focusedIndex - 1);\n\t\t\t\t\titems[focusedIndex]?.focus();\n\t\t\t\t} else {\n\t\t\t\t\tsetFocusedIndex(-1);\n\t\t\t\t\tinput.focus();\n\t\t\t\t}\n\t\t\t} else if (e.key === 'Enter') {\n\t\t\t\te.preventDefault();\n\t\t\t\tconst selectedSize: number | undefined = this.sizes[focusedIndex];\n\t\t\t\tif (focusedIndex >= 0 && focusedIndex < this.sizes.length && selectedSize !== undefined) {\n\t\t\t\t\tthis.selectSize(context, selectedSize);\n\t\t\t\t\tthis.dismissPopup();\n\t\t\t\t}\n\t\t\t} else if (e.key === 'Escape') {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.dismissPopup();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate selectSize(context: PluginContext, size: number): void {\n\t\tif (size === this.defaultSize) {\n\t\t\tcontext.executeCommand('removeFontSize');\n\t\t} else {\n\t\t\tthis.applyFontSize(context, context.getState(), `${size}px`);\n\t\t}\n\t}\n}\n\n// --- Helpers ---\n\nfunction resolveSizes(sizes: readonly number[] | undefined): readonly number[] {\n\tif (!sizes || sizes.length === 0) return DEFAULT_FONT_SIZES;\n\tconst unique: number[] = [...new Set(sizes)].filter((n) => Number.isInteger(n) && n > 0);\n\tunique.sort((a, b) => a - b);\n\treturn unique.length > 0 ? unique : DEFAULT_FONT_SIZES;\n}\n\nfunction resolveDefaultSize(size: number | undefined): number {\n\tif (size === undefined) return DEFAULT_FONT_SIZE;\n\treturn Number.isInteger(size) && size > 0 ? size : DEFAULT_FONT_SIZE;\n}\n","/**\n * Embedded starter font data for the FontPlugin.\n * Contains FiraCode (monospace) and FiraSans (sans-serif) as WOFF2 data URIs.\n * Tree-shakeable: only imported when used.\n */\n\nimport type { FontDefinition } from './FontPlugin.js';\n\nexport const FIRA_CODE_WOFF2_DATA: string =\n\t'data:font/woff2;base64,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';\n\nexport const FIRA_SANS_WOFF2_DATA: string =\n\t'data:font/woff2;base64,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';\n\n/** Fira Code — a monospace font with programming ligatures. */\nexport const FIRA_CODE: FontDefinition = {\n\tname: 'Fira Code',\n\tfamily: \"'Fira Code', monospace\",\n\tcategory: 'monospace',\n\tfontFaces: [\n\t\t{\n\t\t\tsrc: `url(${FIRA_CODE_WOFF2_DATA}) format('woff2')`,\n\t\t\tweight: '400',\n\t\t\tstyle: 'normal',\n\t\t},\n\t],\n};\n\n/** Fira Sans — a humanist sans-serif typeface. */\nexport const FIRA_SANS: FontDefinition = {\n\tname: 'Fira Sans',\n\tfamily: \"'Fira Sans', sans-serif\",\n\tcategory: 'sans-serif',\n\tfontFaces: [\n\t\t{\n\t\t\tsrc: `url(${FIRA_SANS_WOFF2_DATA}) format('woff2')`,\n\t\t\tweight: '400',\n\t\t\tstyle: 'normal',\n\t\t},\n\t],\n};\n\n/** All starter fonts bundled with notectl. */\nexport const STARTER_FONTS: readonly FontDefinition[] = [FIRA_SANS, FIRA_CODE];\n","/**\n * Utility functions for table operations: creating table structures,\n * finding table context, and navigating cells.\n */\n\nimport {\n\ttype BlockNode,\n\ttype ChildNode,\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgenerateBlockId,\n\tgetBlockChildren,\n} from '../../model/Document.js';\nimport type { BlockId, NodeTypeName } from '../../model/TypeBrands.js';\nimport { nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\n\n/** Context information about a cell within a table. */\nexport interface TableContext {\n\treadonly tableId: BlockId;\n\treadonly tableIndex: number;\n\treadonly rowId: BlockId;\n\treadonly rowIndex: number;\n\treadonly cellId: BlockId;\n\treadonly colIndex: number;\n\treadonly totalRows: number;\n\treadonly totalCols: number;\n}\n\n/** Creates a table BlockNode structure with the given dimensions. */\nexport function createTable(rows: number, cols: number): BlockNode {\n\tconst tableId: BlockId = generateBlockId();\n\tconst rowNodes: ChildNode[] = [];\n\n\tfor (let r = 0; r < rows; r++) {\n\t\tconst cellNodes: ChildNode[] = [];\n\t\tfor (let c = 0; c < cols; c++) {\n\t\t\tcellNodes.push(createTableCell());\n\t\t}\n\t\trowNodes.push(\n\t\t\tcreateBlockNode(nodeType('table_row') as NodeTypeName, cellNodes, generateBlockId()),\n\t\t);\n\t}\n\n\treturn createBlockNode(nodeType('table') as NodeTypeName, rowNodes, tableId);\n}\n\n/** Creates a single table row with the given number of cells. */\nexport function createTableRow(cols: number): BlockNode {\n\tconst cellNodes: ChildNode[] = [];\n\tfor (let c = 0; c < cols; c++) {\n\t\tcellNodes.push(createTableCell());\n\t}\n\treturn createBlockNode(nodeType('table_row') as NodeTypeName, cellNodes, generateBlockId());\n}\n\n/** Creates a single empty table cell containing a paragraph. */\nexport function createTableCell(): BlockNode {\n\tconst paragraph: BlockNode = createBlockNode(\n\t\tnodeType('paragraph') as NodeTypeName,\n\t\t[createTextNode('')],\n\t\tgenerateBlockId(),\n\t);\n\treturn createBlockNode(nodeType('table_cell') as NodeTypeName, [paragraph], generateBlockId());\n}\n\n/**\n * Finds table context for a given block ID.\n * Returns null if the block is not inside a table.\n */\nexport function findTableContext(state: EditorState, blockId: BlockId): TableContext | null {\n\tconst path = state.getNodePath(blockId);\n\tif (!path) return null;\n\n\t// Find table node in the path\n\tlet tableId: BlockId | null = null;\n\tlet tableNode: BlockNode | null = null;\n\n\tfor (const id of path) {\n\t\tconst node = state.getBlock(id as BlockId);\n\t\tif (node?.type === 'table') {\n\t\t\ttableId = id as BlockId;\n\t\t\ttableNode = node;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!tableId || !tableNode) return null;\n\n\t// Find table index in document\n\tconst tableIndex: number = state.doc.children.findIndex((b) => b.id === tableId);\n\n\t// Find the cell — could be the block itself or an ancestor\n\tlet cellId: BlockId | null = null;\n\tlet rowId: BlockId | null = null;\n\n\t// Walk path to identify row and cell\n\tfor (const id of path) {\n\t\tconst node = state.getBlock(id as BlockId);\n\t\tif (node?.type === 'table_row') {\n\t\t\trowId = id as BlockId;\n\t\t}\n\t\tif (node?.type === 'table_cell') {\n\t\t\tcellId = id as BlockId;\n\t\t}\n\t}\n\n\t// If the block itself is a cell\n\tconst block = state.getBlock(blockId);\n\tif (block?.type === 'table_cell') {\n\t\tcellId = blockId;\n\t}\n\n\tif (!cellId || !rowId) return null;\n\n\tconst rows: readonly BlockNode[] = getBlockChildren(tableNode);\n\tconst rowIndex: number = rows.findIndex((r) => r.id === rowId);\n\tif (rowIndex === -1) return null;\n\n\tconst rowNode: BlockNode | undefined = rows[rowIndex];\n\tif (!rowNode) return null;\n\tconst cells: readonly BlockNode[] = getBlockChildren(rowNode);\n\tconst colIndex: number = cells.findIndex((c) => c.id === cellId);\n\tif (colIndex === -1) return null;\n\n\tconst totalCols: number = cells.length;\n\tconst totalRows: number = rows.length;\n\n\treturn {\n\t\ttableId,\n\t\ttableIndex,\n\t\trowId,\n\t\trowIndex,\n\t\tcellId,\n\t\tcolIndex,\n\t\ttotalRows,\n\t\ttotalCols,\n\t};\n}\n\n/**\n * Gets the cell BlockId at the given row and column indices.\n * Returns null if out of bounds.\n */\nexport function getCellAt(\n\tstate: EditorState,\n\ttableId: BlockId,\n\trowIndex: number,\n\tcolIndex: number,\n): BlockId | null {\n\tconst table = state.getBlock(tableId);\n\tif (!table) return null;\n\n\tconst rows: readonly BlockNode[] = getBlockChildren(table);\n\tconst row: BlockNode | undefined = rows[rowIndex];\n\tif (!row) return null;\n\n\tconst cells: readonly BlockNode[] = getBlockChildren(row);\n\tconst cell: BlockNode | undefined = cells[colIndex];\n\treturn cell?.id ?? null;\n}\n\n/** Returns all cell IDs in a table in row-major order. */\nexport function getAllCellIds(state: EditorState, tableId: BlockId): readonly BlockId[] {\n\tconst table = state.getBlock(tableId);\n\tif (!table) return [];\n\n\tconst result: BlockId[] = [];\n\tconst rows: readonly BlockNode[] = getBlockChildren(table);\n\tfor (const row of rows) {\n\t\tconst cells: readonly BlockNode[] = getBlockChildren(row);\n\t\tfor (const cell of cells) {\n\t\t\tresult.push(cell.id);\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Returns the first leaf-block ID inside a table cell (e.g. the paragraph). */\nexport function getFirstLeafInCell(state: EditorState, cellId: BlockId): BlockId {\n\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\tif (!cell) return cellId;\n\tconst blockChildren: readonly BlockNode[] = getBlockChildren(cell);\n\tconst first: BlockNode | undefined = blockChildren[0];\n\tif (!first) return cellId;\n\tlet current: BlockNode = first;\n\twhile (true) {\n\t\tconst children: readonly BlockNode[] = getBlockChildren(current);\n\t\tconst next: BlockNode | undefined = children[0];\n\t\tif (!next) return current.id;\n\t\tcurrent = next;\n\t}\n}\n\n/** Returns the last leaf-block ID inside a table cell. */\nexport function getLastLeafInCell(state: EditorState, cellId: BlockId): BlockId {\n\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\tif (!cell) return cellId;\n\tconst blockChildren: readonly BlockNode[] = getBlockChildren(cell);\n\tconst last: BlockNode | undefined = blockChildren[blockChildren.length - 1];\n\tif (!last) return cellId;\n\tlet current: BlockNode = last;\n\twhile (true) {\n\t\tconst children: readonly BlockNode[] = getBlockChildren(current);\n\t\tconst next: BlockNode | undefined = children[children.length - 1];\n\t\tif (!next) return current.id;\n\t\tcurrent = next;\n\t}\n}\n\n/** Checks whether a block is inside a table. */\nexport function isInsideTable(state: EditorState, blockId: BlockId): boolean {\n\tconst path = state.getNodePath(blockId);\n\tif (!path) return false;\n\n\tfor (const id of path) {\n\t\tconst node = state.getBlock(id as BlockId);\n\t\tif (node?.type === 'table') return true;\n\t}\n\treturn false;\n}\n","/**\n * Table commands: insert table, add/remove rows and columns, delete table.\n * All commands are registered via PluginContext and operate through transactions.\n */\n\nimport { createBlockNode, getBlockChildren } from '../../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\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 } from '../../state/Transaction.js';\nimport type { PluginContext } from '../Plugin.js';\nimport {\n\ttype TableContext,\n\tcreateTable,\n\tcreateTableCell,\n\tcreateTableRow,\n\tfindTableContext,\n\tgetCellAt,\n\tgetFirstLeafInCell,\n} from './TableHelpers.js';\n\ninterface TableDeletionTarget {\n\treadonly tableId: BlockId;\n}\n\n/**\n * Inserts a table with the given dimensions at the current cursor position.\n * Adds a paragraph after the table for cursor escape.\n * Moves cursor into the first cell.\n */\nexport function insertTable(context: PluginContext, rows: number, cols: number): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return false;\n\n\tconst currentBlockId: BlockId = sel.anchor.blockId;\n\n\t// Find which root-level block contains the current selection\n\tlet rootIndex = -1;\n\tfor (let i = 0; i < state.doc.children.length; i++) {\n\t\tconst rootBlock = state.doc.children[i];\n\t\tif (!rootBlock) continue;\n\t\tif (rootBlock.id === currentBlockId) {\n\t\t\trootIndex = i;\n\t\t\tbreak;\n\t\t}\n\t\t// Check if current block is nested inside this root block\n\t\tconst path = state.getNodePath(currentBlockId);\n\t\tif (path && path[0] === rootBlock.id) {\n\t\t\trootIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (rootIndex === -1) rootIndex = state.doc.children.length - 1;\n\n\tconst tableNode = createTable(rows, cols);\n\tconst paragraphAfter = createBlockNode(nodeType('paragraph') as NodeTypeName);\n\n\t// Insert table after current block, then paragraph after table\n\tconst insertIndex: number = rootIndex + 1;\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.insertNode([], insertIndex, tableNode)\n\t\t.insertNode([], insertIndex + 1, paragraphAfter);\n\n\t// Set cursor in first paragraph inside first cell\n\tconst firstRow = getBlockChildren(tableNode)[0];\n\tconst firstCell = firstRow ? getBlockChildren(firstRow)[0] : undefined;\n\tconst firstParagraph = firstCell ? getBlockChildren(firstCell)[0] : undefined;\n\n\tif (firstParagraph) {\n\t\ttr.setSelection(createCollapsedSelection(firstParagraph.id, 0));\n\t} else if (firstCell) {\n\t\ttr.setSelection(createCollapsedSelection(firstCell.id, 0));\n\t}\n\n\tcontext.dispatch(tr.build());\n\treturn true;\n}\n\n/** Adds a row above the current row. */\nexport function addRowAbove(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\tconst table = state.getBlock(tableCtx.tableId);\n\tif (!table) return false;\n\n\tconst newRow = createTableRow(tableCtx.totalCols);\n\tconst tr = state.transaction('command').insertNode([tableCtx.tableId], tableCtx.rowIndex, newRow);\n\n\t// Move cursor to first paragraph inside first cell of new row\n\tconst firstCell = getBlockChildren(newRow)[0];\n\tconst firstLeaf = firstCell ? getBlockChildren(firstCell)[0] : undefined;\n\tif (firstLeaf) {\n\t\ttr.setSelection(createCollapsedSelection(firstLeaf.id, 0));\n\t} else if (firstCell) {\n\t\ttr.setSelection(createCollapsedSelection(firstCell.id, 0));\n\t}\n\n\tcontext.dispatch(tr.build());\n\treturn true;\n}\n\n/** Adds a row below the current row. */\nexport function addRowBelow(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\tconst newRow = createTableRow(tableCtx.totalCols);\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.insertNode([tableCtx.tableId], tableCtx.rowIndex + 1, newRow);\n\n\t// Move cursor to first paragraph inside first cell of new row\n\tconst firstCell = getBlockChildren(newRow)[0];\n\tconst firstLeaf = firstCell ? getBlockChildren(firstCell)[0] : undefined;\n\tif (firstLeaf) {\n\t\ttr.setSelection(createCollapsedSelection(firstLeaf.id, 0));\n\t} else if (firstCell) {\n\t\ttr.setSelection(createCollapsedSelection(firstCell.id, 0));\n\t}\n\n\tcontext.dispatch(tr.build());\n\treturn true;\n}\n\n/** Adds a column to the left of the current column. */\nexport function addColumnLeft(context: PluginContext): boolean {\n\treturn addColumn(context, 'left');\n}\n\n/** Adds a column to the right of the current column. */\nexport function addColumnRight(context: PluginContext): boolean {\n\treturn addColumn(context, 'right');\n}\n\nfunction addColumn(context: PluginContext, side: 'left' | 'right'): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\tconst table = state.getBlock(tableCtx.tableId);\n\tif (!table) return false;\n\n\tconst rows = getBlockChildren(table);\n\tconst insertColIndex: number = side === 'left' ? tableCtx.colIndex : tableCtx.colIndex + 1;\n\n\tconst tr = state.transaction('command');\n\n\t// Insert a new cell in each row at the column index\n\tfor (const row of rows) {\n\t\tconst newCell = createTableCell();\n\t\ttr.insertNode([tableCtx.tableId, row.id], insertColIndex, newCell);\n\t}\n\n\ttr.setSelection(state.selection);\n\tcontext.dispatch(tr.build());\n\treturn true;\n}\n\n/**\n * Deletes the current row. If it's the last row, deletes the entire table.\n */\nexport function deleteRow(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\tif (tableCtx.totalRows <= 1) {\n\t\treturn deleteTable(context);\n\t}\n\n\tconst tr = state.transaction('command').removeNode([tableCtx.tableId], tableCtx.rowIndex);\n\n\t// Move cursor to cell in adjacent row\n\tconst targetRowIndex: number = tableCtx.rowIndex > 0 ? tableCtx.rowIndex - 1 : 0;\n\tconst targetCellId: BlockId | null = getCellAt(\n\t\tstate,\n\t\ttableCtx.tableId,\n\t\ttargetRowIndex === tableCtx.rowIndex ? targetRowIndex + 1 : targetRowIndex,\n\t\tMath.min(tableCtx.colIndex, tableCtx.totalCols - 1),\n\t);\n\n\tif (targetCellId) {\n\t\tconst leafId: BlockId = getFirstLeafInCell(state, targetCellId);\n\t\ttr.setSelection(createCollapsedSelection(leafId, 0));\n\t}\n\n\tcontext.dispatch(tr.build());\n\treturn true;\n}\n\n/**\n * Deletes the current column. If it's the last column, deletes the entire table.\n */\nexport function deleteColumn(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\tif (tableCtx.totalCols <= 1) {\n\t\treturn deleteTable(context);\n\t}\n\n\tconst table = state.getBlock(tableCtx.tableId);\n\tif (!table) return false;\n\n\tconst rows = getBlockChildren(table);\n\tconst tr = state.transaction('command');\n\n\t// Remove the cell at colIndex from each row (reverse order for index stability)\n\tfor (let r = rows.length - 1; r >= 0; r--) {\n\t\tconst row = rows[r];\n\t\tif (!row) continue;\n\t\ttr.removeNode([tableCtx.tableId, row.id], tableCtx.colIndex);\n\t}\n\n\t// Move cursor to adjacent cell\n\tconst targetColIndex: number = tableCtx.colIndex > 0 ? tableCtx.colIndex - 1 : 0;\n\tconst targetCellId: BlockId | null = getCellAt(\n\t\tstate,\n\t\ttableCtx.tableId,\n\t\ttableCtx.rowIndex,\n\t\ttargetColIndex === tableCtx.colIndex ? targetColIndex + 1 : targetColIndex,\n\t);\n\n\tif (targetCellId) {\n\t\tconst leafId: BlockId = getFirstLeafInCell(state, targetCellId);\n\t\ttr.setSelection(createCollapsedSelection(leafId, 0));\n\t}\n\n\tcontext.dispatch(tr.build());\n\treturn true;\n}\n\n/** Deletes the entire table and moves cursor to surrounding block. */\nexport function deleteTable(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst target = resolveTableDeletionTarget(state);\n\tif (!target) return false;\n\n\tconst tr = createDeleteTableTransaction(state, target.tableId);\n\tif (!tr) return false;\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Selects the surrounding table as a node object. */\nexport function selectTable(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) {\n\t\tconst selectedNode = state.getBlock(sel.nodeId);\n\t\treturn selectedNode?.type === 'table';\n\t}\n\n\tconst tableCtx: TableContext | null = findTableContext(state, sel.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\tconst path = state.getNodePath(tableCtx.tableId);\n\tif (!path) return false;\n\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.setSelection(createNodeSelection(tableCtx.tableId, path))\n\t\t.build();\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Registers all table commands on the given plugin context. */\nexport function registerTableCommands(context: PluginContext): void {\n\tcontext.registerCommand('insertTable', () => insertTable(context, 3, 3));\n\tcontext.registerCommand('addRowAbove', () => addRowAbove(context));\n\tcontext.registerCommand('addRowBelow', () => addRowBelow(context));\n\tcontext.registerCommand('addColumnLeft', () => addColumnLeft(context));\n\tcontext.registerCommand('addColumnRight', () => addColumnRight(context));\n\tcontext.registerCommand('deleteRow', () => deleteRow(context));\n\tcontext.registerCommand('deleteColumn', () => deleteColumn(context));\n\tcontext.registerCommand('selectTable', () => selectTable(context));\n\tcontext.registerCommand('deleteTable', () => deleteTable(context));\n}\n\n/**\n * Creates a transaction that removes the given root-level table node.\n * Cursor placement prefers the next root block, then previous.\n */\nexport function createDeleteTableTransaction(\n\tstate: EditorState,\n\ttableId: BlockId,\n): Transaction | null {\n\tconst tableIndex: number = state.doc.children.findIndex((block) => block.id === tableId);\n\tif (tableIndex === -1) return null;\n\n\tconst tr = state.transaction('command').removeNode([], tableIndex);\n\n\tconst nextRoot = state.doc.children[tableIndex + 1];\n\tif (nextRoot) {\n\t\ttr.setSelection(createCollapsedSelection(nextRoot.id, 0));\n\t\treturn tr.build();\n\t}\n\n\tconst prevRoot = state.doc.children[tableIndex - 1];\n\tif (prevRoot) {\n\t\ttr.setSelection(createCollapsedSelection(prevRoot.id, 0));\n\t}\n\n\treturn tr.build();\n}\n\nfunction resolveTableDeletionTarget(\n\tstate: ReturnType<PluginContext['getState']>,\n): TableDeletionTarget | null {\n\tif (isNodeSelection(state.selection)) {\n\t\tconst selectedNode = state.getBlock(state.selection.nodeId);\n\t\tif (selectedNode?.type !== 'table') return null;\n\t\treturn { tableId: selectedNode.id };\n\t}\n\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return null;\n\n\treturn { tableId: tableCtx.tableId };\n}\n","/**\n * Keyboard navigation handlers for table cells.\n * Handles Tab, Shift-Tab, arrow keys, Enter, Backspace, Delete, and Escape.\n */\n\nimport type { Keymap } from '../../input/Keymap.js';\nimport { getBlockLength } from '../../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tisCollapsed,\n\tisNodeSelection,\n} from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { addRowBelow } from './TableCommands.js';\nimport {\n\ttype TableContext,\n\tfindTableContext,\n\tgetCellAt,\n\tgetFirstLeafInCell,\n\tgetLastLeafInCell,\n} from './TableHelpers.js';\n\n/** Registers all table navigation keymaps. */\nexport function registerTableKeymaps(context: PluginContext): void {\n\tconst keymap: Keymap = {\n\t\tTab: () => handleTab(context),\n\t\t'Shift-Tab': () => handleShiftTab(context),\n\t\tEnter: () => handleEnter(context),\n\t\tBackspace: () => handleBackspace(context),\n\t\tDelete: () => handleDelete(context),\n\t\tArrowDown: () => handleArrowDown(context),\n\t\tArrowUp: () => handleArrowUp(context),\n\t\tArrowRight: () => handleArrowRight(context),\n\t\tArrowLeft: () => handleArrowLeft(context),\n\t\tEscape: () => handleEscape(context),\n\t};\n\n\tcontext.registerKeymap(keymap);\n}\n\n/** Tab: move to next cell. At end of table, add a new row. */\nfunction handleTab(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\t// Try next cell in same row\n\tif (tableCtx.colIndex < tableCtx.totalCols - 1) {\n\t\treturn moveToCellAndSelect(context, tableCtx.tableId, tableCtx.rowIndex, tableCtx.colIndex + 1);\n\t}\n\n\t// Try first cell in next row\n\tif (tableCtx.rowIndex < tableCtx.totalRows - 1) {\n\t\treturn moveToCellAndSelect(context, tableCtx.tableId, tableCtx.rowIndex + 1, 0);\n\t}\n\n\t// At end of table — add a new row and move there\n\taddRowBelow(context);\n\treturn true;\n}\n\n/** Shift-Tab: move to previous cell. At start of table, return false. */\nfunction handleShiftTab(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\t// Try previous cell in same row\n\tif (tableCtx.colIndex > 0) {\n\t\treturn moveToCellAndSelect(context, tableCtx.tableId, tableCtx.rowIndex, tableCtx.colIndex - 1);\n\t}\n\n\t// Try last cell in previous row\n\tif (tableCtx.rowIndex > 0) {\n\t\treturn moveToCellAndSelect(\n\t\t\tcontext,\n\t\t\ttableCtx.tableId,\n\t\t\ttableCtx.rowIndex - 1,\n\t\t\ttableCtx.totalCols - 1,\n\t\t);\n\t}\n\n\t// At start of table — stay put\n\treturn true;\n}\n\n/** Enter: move to same column in next row (spreadsheet behavior). */\nfunction handleEnter(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\n\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t// Only intercept Enter for paragraphs inside table cells.\n\t// Other block types (list_item, heading, etc.) are handled by their plugins.\n\tif (block && block.type !== 'paragraph') return false;\n\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\t// Move to same column in next row\n\tif (tableCtx.rowIndex < tableCtx.totalRows - 1) {\n\t\treturn moveToCellAndSelect(context, tableCtx.tableId, tableCtx.rowIndex + 1, tableCtx.colIndex);\n\t}\n\n\t// On last row — block to prevent splitBlock\n\treturn true;\n}\n\n/** Backspace at deletion-boundary: select table node (first step of 2-step delete). */\nfunction handleBackspace(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return false;\n\tif (!isCollapsed(sel)) return false;\n\tif (sel.anchor.offset !== 0) return false;\n\n\tconst tableCtx: TableContext | null = findTableContext(state, sel.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\tconst isAtDeletionBoundary = tableCtx.rowIndex === 0 && tableCtx.colIndex === 0;\n\tif (!isAtDeletionBoundary) return false;\n\n\t// Cursor must be on the first block inside the cell\n\tconst firstLeaf: BlockId = getFirstLeafInCell(state, tableCtx.cellId);\n\tif (sel.anchor.blockId !== firstLeaf) return false;\n\n\treturn selectTableNode(context, tableCtx.tableId);\n}\n\n/** Delete at deletion-boundary: select table node (first step of 2-step delete). */\nfunction handleDelete(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return false;\n\tif (!isCollapsed(sel)) return false;\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return false;\n\n\tconst blockLen: number = getBlockLength(block);\n\tif (sel.anchor.offset !== blockLen) return false;\n\n\tconst tableCtx: TableContext | null = findTableContext(state, sel.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\tconst isAtDeletionBoundary =\n\t\ttableCtx.rowIndex === tableCtx.totalRows - 1 && tableCtx.colIndex === tableCtx.totalCols - 1;\n\tif (!isAtDeletionBoundary) return false;\n\n\t// Cursor must be on the last block inside the cell\n\tconst lastLeaf: BlockId = getLastLeafInCell(state, tableCtx.cellId);\n\tif (sel.anchor.blockId !== lastLeaf) return false;\n\n\treturn selectTableNode(context, tableCtx.tableId);\n}\n\n/** ArrowDown: move to same column in next row. */\nfunction handleArrowDown(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\t// Only intercept when cursor is on the last block in the cell\n\tconst lastLeaf: BlockId = getLastLeafInCell(state, tableCtx.cellId);\n\tif (state.selection.anchor.blockId !== lastLeaf) return false;\n\n\tif (tableCtx.rowIndex >= tableCtx.totalRows - 1) {\n\t\t// At last row — move cursor to paragraph after table\n\t\treturn handleEscape(context);\n\t}\n\n\treturn moveToCellAndSelect(context, tableCtx.tableId, tableCtx.rowIndex + 1, tableCtx.colIndex);\n}\n\n/** ArrowUp: move to same column in previous row. */\nfunction handleArrowUp(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\t// Only intercept when cursor is on the first block in the cell\n\tconst firstLeaf: BlockId = getFirstLeafInCell(state, tableCtx.cellId);\n\tif (state.selection.anchor.blockId !== firstLeaf) return false;\n\n\tif (tableCtx.rowIndex <= 0) {\n\t\t// At first row — let default behavior handle it\n\t\treturn false;\n\t}\n\n\treturn moveToCellAndSelect(context, tableCtx.tableId, tableCtx.rowIndex - 1, tableCtx.colIndex);\n}\n\n/** ArrowRight at cell end: move to next cell. */\nfunction handleArrowRight(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return false;\n\tif (!isCollapsed(sel)) return false;\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return false;\n\n\tconst blockLen: number = getBlockLength(block);\n\tif (sel.anchor.offset !== blockLen) return false;\n\n\tconst tableCtx: TableContext | null = findTableContext(state, sel.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\t// Only jump to next cell when cursor is on the last block in the cell\n\tconst lastLeaf: BlockId = getLastLeafInCell(state, tableCtx.cellId);\n\tif (sel.anchor.blockId !== lastLeaf) return false;\n\n\t// Try next cell in same row\n\tif (tableCtx.colIndex < tableCtx.totalCols - 1) {\n\t\treturn moveToCellAndSelect(context, tableCtx.tableId, tableCtx.rowIndex, tableCtx.colIndex + 1);\n\t}\n\n\t// Try first cell in next row\n\tif (tableCtx.rowIndex < tableCtx.totalRows - 1) {\n\t\treturn moveToCellAndSelect(context, tableCtx.tableId, tableCtx.rowIndex + 1, 0);\n\t}\n\n\treturn true;\n}\n\n/** ArrowLeft at cell start: move to previous cell. */\nfunction handleArrowLeft(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return false;\n\tif (!isCollapsed(sel)) return false;\n\tif (sel.anchor.offset !== 0) return false;\n\n\tconst tableCtx: TableContext | null = findTableContext(state, sel.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\t// Only jump to previous cell when cursor is on the first block in the cell\n\tconst firstLeaf: BlockId = getFirstLeafInCell(state, tableCtx.cellId);\n\tif (sel.anchor.blockId !== firstLeaf) return false;\n\n\t// Try previous cell in same row\n\tif (tableCtx.colIndex > 0) {\n\t\treturn moveToCellAtEnd(context, tableCtx.tableId, tableCtx.rowIndex, tableCtx.colIndex - 1);\n\t}\n\n\t// Try last cell in previous row\n\tif (tableCtx.rowIndex > 0) {\n\t\treturn moveToCellAtEnd(\n\t\t\tcontext,\n\t\t\ttableCtx.tableId,\n\t\t\ttableCtx.rowIndex - 1,\n\t\t\ttableCtx.totalCols - 1,\n\t\t);\n\t}\n\n\treturn true;\n}\n\n/** Escape: move cursor to the paragraph after the table. */\nfunction handleEscape(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tif (isNodeSelection(state.selection)) return false;\n\tconst tableCtx: TableContext | null = findTableContext(state, state.selection.anchor.blockId);\n\tif (!tableCtx) return false;\n\n\t// Find the block after the table\n\tconst nextIndex: number = tableCtx.tableIndex + 1;\n\tif (nextIndex < state.doc.children.length) {\n\t\tconst nextBlock = state.doc.children[nextIndex];\n\t\tif (!nextBlock) return false;\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setSelection(createCollapsedSelection(nextBlock.id, 0))\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/** Moves cursor to the start of a cell (first leaf block inside). */\nfunction moveToCellAndSelect(\n\tcontext: PluginContext,\n\ttableId: BlockId,\n\trowIndex: number,\n\tcolIndex: number,\n): boolean {\n\tconst state = context.getState();\n\tconst cellId: BlockId | null = getCellAt(state, tableId, rowIndex, colIndex);\n\tif (!cellId) return false;\n\n\tconst leafId: BlockId = getFirstLeafInCell(state, cellId);\n\tconst tr = state.transaction('command').setSelection(createCollapsedSelection(leafId, 0)).build();\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Moves cursor to the end of a cell (last leaf block inside, for ArrowLeft). */\nfunction moveToCellAtEnd(\n\tcontext: PluginContext,\n\ttableId: BlockId,\n\trowIndex: number,\n\tcolIndex: number,\n): boolean {\n\tconst state = context.getState();\n\tconst cellId: BlockId | null = getCellAt(state, tableId, rowIndex, colIndex);\n\tif (!cellId) return false;\n\n\tconst leafId: BlockId = getLastLeafInCell(state, cellId);\n\tconst leaf = state.getBlock(leafId);\n\tif (!leaf) return false;\n\n\tconst leafLen: number = getBlockLength(leaf);\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.setSelection(createCollapsedSelection(leafId, leafLen))\n\t\t.build();\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Switches current selection to a table NodeSelection. */\nfunction selectTableNode(context: PluginContext, tableId: BlockId): boolean {\n\tconst state = context.getState();\n\tconst path = state.getNodePath(tableId);\n\tif (!path) return false;\n\n\tconst tr = state.transaction('input').setSelection(createNodeSelection(tableId, path)).build();\n\tcontext.dispatch(tr);\n\treturn true;\n}\n","/**\n * Interactive table controls: floating insert lines between borders,\n * add row/column buttons at edges, and column/row handles with delete.\n * All controls appear on hover with smooth CSS animations.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { getBlockChildren } from '../../model/Document.js';\nimport { createCollapsedSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport { createDeleteTableTransaction } from './TableCommands.js';\nimport { createTableCell, createTableRow, getCellAt } from './TableHelpers.js';\n\n// --- SVG Icons ---\n\nconst PLUS_SVG: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" ' +\n\t'viewBox=\"0 0 12 12\" fill=\"none\">' +\n\t'<path d=\"M6 1v10M1 6h10\" stroke=\"currentColor\" ' +\n\t'stroke-width=\"1.8\" stroke-linecap=\"round\"/></svg>';\n\nconst DELETE_SVG: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" ' +\n\t'viewBox=\"0 0 10 10\" fill=\"none\">' +\n\t'<path d=\"M2 2l6 6M8 2l-6 6\" stroke=\"currentColor\" ' +\n\t'stroke-width=\"1.5\" stroke-linecap=\"round\"/></svg>';\n\nconst TABLE_DELETE_SVG: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" ' +\n\t'viewBox=\"0 0 24 24\" fill=\"none\">' +\n\t'<path d=\"M9 3h6m-9 4h12M10 11v6m4-6v6m-9 3h14l-1-13H6L5 20z\" ' +\n\t'stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" ' +\n\t'stroke-linejoin=\"round\"/></svg>';\n\n// --- Constants ---\n\nconst BORDER_THRESHOLD: number = 10;\n\n// --- Types ---\n\nexport interface TableControlsHandle {\n\tupdate(node: BlockNode): void;\n\tdestroy(): void;\n}\n\ninterface BorderInfo {\n\treadonly position: number;\n\treadonly index: number;\n}\n\n// --- Transaction Helpers ---\n\nfunction insertRowAtIndex(\n\tgetState: () => EditorState,\n\tdispatch: (tr: Transaction) => void,\n\ttableId: BlockId,\n\trowIndex: number,\n): void {\n\tconst state: EditorState = getState();\n\tconst table: BlockNode | undefined = state.getBlock(tableId);\n\tif (!table) return;\n\n\tconst rows: readonly BlockNode[] = getBlockChildren(table);\n\tconst numCols: number = rows[0] ? getBlockChildren(rows[0]).length : 0;\n\tif (numCols === 0) return;\n\n\tconst newRow: BlockNode = createTableRow(numCols);\n\tconst firstCell: BlockNode | undefined = getBlockChildren(newRow)[0];\n\n\tconst tr = state.transaction('command').insertNode([tableId], rowIndex, newRow);\n\n\tif (firstCell) {\n\t\ttr.setSelection(createCollapsedSelection(firstCell.id, 0));\n\t}\n\n\tdispatch(tr.build());\n}\n\nfunction insertColumnAtIndex(\n\tgetState: () => EditorState,\n\tdispatch: (tr: Transaction) => void,\n\ttableId: BlockId,\n\tcolIndex: number,\n): void {\n\tconst state: EditorState = getState();\n\tconst table: BlockNode | undefined = state.getBlock(tableId);\n\tif (!table) return;\n\n\tconst rows: readonly BlockNode[] = getBlockChildren(table);\n\tconst tr = state.transaction('command');\n\n\tfor (const row of rows) {\n\t\tconst newCell: BlockNode = createTableCell();\n\t\ttr.insertNode([tableId, row.id], colIndex, newCell);\n\t}\n\n\ttr.setSelection(state.selection);\n\tdispatch(tr.build());\n}\n\nfunction deleteRowAtIndex(\n\tgetState: () => EditorState,\n\tdispatch: (tr: Transaction) => void,\n\ttableId: BlockId,\n\trowIndex: number,\n): void {\n\tconst state: EditorState = getState();\n\tconst table: BlockNode | undefined = state.getBlock(tableId);\n\tif (!table) return;\n\n\tconst rows: readonly BlockNode[] = getBlockChildren(table);\n\tif (rows.length <= 1) {\n\t\tdeleteTableAtRoot(getState, dispatch, tableId);\n\t\treturn;\n\t}\n\n\tconst tr = state.transaction('command').removeNode([tableId], rowIndex);\n\n\tconst targetRow: number = rowIndex > 0 ? rowIndex - 1 : 1;\n\tconst cellId: BlockId | null = getCellAt(state, tableId, targetRow, 0);\n\tif (cellId) {\n\t\ttr.setSelection(createCollapsedSelection(cellId, 0));\n\t}\n\n\tdispatch(tr.build());\n}\n\nfunction deleteColumnAtIndex(\n\tgetState: () => EditorState,\n\tdispatch: (tr: Transaction) => void,\n\ttableId: BlockId,\n\tcolIndex: number,\n): void {\n\tconst state: EditorState = getState();\n\tconst table: BlockNode | undefined = state.getBlock(tableId);\n\tif (!table) return;\n\n\tconst rows: readonly BlockNode[] = getBlockChildren(table);\n\tconst numCols: number = rows[0] ? getBlockChildren(rows[0]).length : 0;\n\n\tif (numCols <= 1) {\n\t\tdeleteTableAtRoot(getState, dispatch, tableId);\n\t\treturn;\n\t}\n\n\tconst tr = state.transaction('command');\n\n\tfor (let r: number = rows.length - 1; r >= 0; r--) {\n\t\tconst row: BlockNode | undefined = rows[r];\n\t\tif (!row) continue;\n\t\ttr.removeNode([tableId, row.id], colIndex);\n\t}\n\n\tconst targetCol: number = colIndex > 0 ? colIndex - 1 : 1;\n\tconst cellId: BlockId | null = getCellAt(state, tableId, 0, targetCol);\n\tif (cellId) {\n\t\ttr.setSelection(createCollapsedSelection(cellId, 0));\n\t}\n\n\tdispatch(tr.build());\n}\n\nfunction deleteTableAtRoot(\n\tgetState: () => EditorState,\n\tdispatch: (tr: Transaction) => void,\n\ttableId: BlockId,\n): void {\n\tconst tr = createDeleteTableTransaction(getState(), tableId);\n\tif (!tr) return;\n\tdispatch(tr);\n}\n\n// --- DOM Builders ---\n\nfunction createButton(className: string, innerHTML: string, title: string): HTMLButtonElement {\n\tconst btn: HTMLButtonElement = document.createElement('button');\n\tbtn.className = className;\n\tbtn.innerHTML = innerHTML;\n\tbtn.title = title;\n\tbtn.type = 'button';\n\tbtn.setAttribute('aria-label', title);\n\tbtn.setAttribute('contenteditable', 'false');\n\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t});\n\treturn btn;\n}\n\nfunction buildInsertLine(orientation: 'horizontal' | 'vertical'): HTMLDivElement {\n\tconst line: HTMLDivElement = document.createElement('div');\n\tline.className = `ntbl-insert-line ntbl-insert-line--${orientation}`;\n\tline.setAttribute('contenteditable', 'false');\n\n\tconst title: string = orientation === 'horizontal' ? 'Insert row' : 'Insert column';\n\tconst btn: HTMLButtonElement = createButton('ntbl-insert-btn', PLUS_SVG, title);\n\tline.appendChild(btn);\n\n\treturn line;\n}\n\nfunction buildAddButton(className: string, title: string): HTMLButtonElement {\n\tconst btn: HTMLButtonElement = document.createElement('button');\n\tbtn.className = `ntbl-add-zone ${className}`;\n\tbtn.type = 'button';\n\tbtn.setAttribute('contenteditable', 'false');\n\tbtn.setAttribute('aria-label', title);\n\tbtn.title = title;\n\n\tconst icon: HTMLSpanElement = document.createElement('span');\n\ticon.className = 'ntbl-add-icon';\n\ticon.innerHTML = PLUS_SVG;\n\tbtn.appendChild(icon);\n\n\tbtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t});\n\n\treturn btn;\n}\n\nfunction buildHandleBar(className: string): HTMLDivElement {\n\tconst bar: HTMLDivElement = document.createElement('div');\n\tbar.className = className;\n\tbar.setAttribute('contenteditable', 'false');\n\treturn bar;\n}\n\nfunction buildHandle(\n\tclassName: string,\n\tindex: number,\n\tonDelete: (idx: number) => void,\n): HTMLDivElement {\n\tconst handle: HTMLDivElement = document.createElement('div');\n\thandle.className = `ntbl-handle ${className}`;\n\thandle.dataset.index = String(index);\n\n\tconst deleteBtn: HTMLButtonElement = createButton(\n\t\t'ntbl-handle-delete',\n\t\tDELETE_SVG,\n\t\tclassName.includes('col') ? 'Delete column' : 'Delete row',\n\t);\n\tdeleteBtn.addEventListener('click', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tonDelete(index);\n\t});\n\thandle.appendChild(deleteBtn);\n\n\treturn handle;\n}\n\n// --- Main Factory ---\n\nexport function createTableControls(\n\tcontainer: HTMLElement,\n\ttableEl: HTMLTableElement,\n\tinitialNode: BlockNode,\n\tgetState: () => EditorState,\n\tdispatch: (tr: Transaction) => void,\n): TableControlsHandle {\n\tlet tableId: BlockId = initialNode.id;\n\tlet numRows: number = countRows(initialNode);\n\tlet numCols: number = countCols(initialNode);\n\n\t// --- Create DOM elements ---\n\n\tconst colBar: HTMLDivElement = buildHandleBar('ntbl-col-bar');\n\tconst rowBar: HTMLDivElement = buildHandleBar('ntbl-row-bar');\n\tconst insertLineH: HTMLDivElement = buildInsertLine('horizontal');\n\tconst insertLineV: HTMLDivElement = buildInsertLine('vertical');\n\tconst addRowZone: HTMLButtonElement = buildAddButton('ntbl-add-row', 'Add row');\n\tconst addColZone: HTMLButtonElement = buildAddButton('ntbl-add-col', 'Add column');\n\tconst deleteTableBtn: HTMLButtonElement = createButton(\n\t\t'ntbl-delete-table-btn',\n\t\tTABLE_DELETE_SVG,\n\t\t'Delete table',\n\t);\n\n\t// --- Insert line state ---\n\n\tlet activeRowIndex = -1;\n\tlet activeColIndex = -1;\n\n\t// --- Append to container ---\n\n\tcontainer.append(\n\t\tcolBar,\n\t\trowBar,\n\t\tinsertLineH,\n\t\tinsertLineV,\n\t\taddRowZone,\n\t\taddColZone,\n\t\tdeleteTableBtn,\n\t);\n\n\t// --- Build handles ---\n\n\trebuildColHandles();\n\trebuildRowHandles();\n\n\t// --- Event handlers ---\n\n\tconst insertBtnH: HTMLButtonElement = insertLineH.querySelector(\n\t\t'.ntbl-insert-btn',\n\t) as HTMLButtonElement;\n\tconst insertBtnV: HTMLButtonElement = insertLineV.querySelector(\n\t\t'.ntbl-insert-btn',\n\t) as HTMLButtonElement;\n\n\tinsertBtnH.addEventListener('click', () => {\n\t\tif (activeRowIndex >= 0) {\n\t\t\tinsertRowAtIndex(getState, dispatch, tableId, activeRowIndex);\n\t\t}\n\t});\n\n\tinsertBtnV.addEventListener('click', () => {\n\t\tif (activeColIndex >= 0) {\n\t\t\tinsertColumnAtIndex(getState, dispatch, tableId, activeColIndex);\n\t\t}\n\t});\n\n\taddRowZone.addEventListener('click', () => {\n\t\tinsertRowAtIndex(getState, dispatch, tableId, numRows);\n\t});\n\n\taddColZone.addEventListener('click', () => {\n\t\tinsertColumnAtIndex(getState, dispatch, tableId, numCols);\n\t});\n\n\tdeleteTableBtn.addEventListener('click', () => {\n\t\tdeleteTableAtRoot(getState, dispatch, tableId);\n\t});\n\n\tcontainer.addEventListener('mousemove', onMouseMove);\n\tcontainer.addEventListener('mouseleave', onMouseLeave);\n\n\t// --- Positioning ---\n\n\tconst observer: ResizeObserver = new ResizeObserver(() => {\n\t\tpositionControls();\n\t});\n\tobserver.observe(tableEl);\n\trequestAnimationFrame(() => positionControls());\n\n\t// --- Functions ---\n\n\tfunction countRows(node: BlockNode): number {\n\t\treturn getBlockChildren(node).length;\n\t}\n\n\tfunction countCols(node: BlockNode): number {\n\t\tconst rows: readonly BlockNode[] = getBlockChildren(node);\n\t\treturn rows[0] ? getBlockChildren(rows[0]).length : 0;\n\t}\n\n\t/** Returns the table's offset relative to the container (walks offsetParent chain). */\n\tfunction getTableOffset(): { top: number; left: number } {\n\t\tlet top = 0;\n\t\tlet left = 0;\n\t\tlet el: HTMLElement | null = tableEl;\n\t\twhile (el && el !== container) {\n\t\t\ttop += el.offsetTop;\n\t\t\tleft += el.offsetLeft;\n\t\t\tel = el.offsetParent as HTMLElement | null;\n\t\t}\n\t\treturn { top, left };\n\t}\n\n\tfunction measureRowBorders(): BorderInfo[] {\n\t\tconst trs: NodeListOf<HTMLTableRowElement> = tableEl.querySelectorAll(':scope > tbody > tr');\n\t\tconst tableTop: number = tableEl.offsetTop;\n\t\tconst borders: BorderInfo[] = [];\n\n\t\tfor (let i = 1; i < trs.length; i++) {\n\t\t\tconst tr: HTMLTableRowElement | undefined = trs[i];\n\t\t\tif (!tr) continue;\n\t\t\tborders.push({\n\t\t\t\tposition: tr.offsetTop - tableTop,\n\t\t\t\tindex: i,\n\t\t\t});\n\t\t}\n\n\t\treturn borders;\n\t}\n\n\tfunction measureColBorders(): BorderInfo[] {\n\t\tif (numCols <= 1) return [];\n\t\tconst tableWidth: number = tableEl.offsetWidth;\n\t\tconst colWidth: number = tableWidth / numCols;\n\t\tconst borders: BorderInfo[] = [];\n\n\t\tfor (let i = 1; i < numCols; i++) {\n\t\t\tborders.push({\n\t\t\t\tposition: Math.round(colWidth * i),\n\t\t\t\tindex: i,\n\t\t\t});\n\t\t}\n\n\t\treturn borders;\n\t}\n\n\tfunction positionControls(): void {\n\t\tpositionColHandles();\n\t\tpositionRowHandles();\n\t\tpositionAddButtons();\n\t}\n\n\tfunction positionColHandles(): void {\n\t\tconst handles: HTMLCollection = colBar.children;\n\t\tif (handles.length === 0) return;\n\n\t\tconst tableWidth: number = tableEl.offsetWidth;\n\t\tconst colWidth: number = tableWidth / numCols;\n\n\t\tfor (let i = 0; i < handles.length; i++) {\n\t\t\tconst h = handles[i] as HTMLElement;\n\t\t\th.style.left = `${Math.round(colWidth * i)}px`;\n\t\t\th.style.width = `${Math.round(colWidth)}px`;\n\t\t}\n\n\t\tcolBar.style.width = `${tableWidth}px`;\n\t}\n\n\tfunction positionRowHandles(): void {\n\t\tconst handles: HTMLCollection = rowBar.children;\n\t\tif (handles.length === 0) return;\n\n\t\tconst trs: NodeListOf<HTMLTableRowElement> = tableEl.querySelectorAll(':scope > tbody > tr');\n\n\t\tconst tableTop: number = tableEl.offsetTop;\n\t\tlet totalHeight = 0;\n\n\t\tfor (let i = 0; i < handles.length; i++) {\n\t\t\tconst h = handles[i] as HTMLElement;\n\t\t\tconst tr: HTMLTableRowElement | undefined = trs[i];\n\t\t\tif (tr) {\n\t\t\t\tconst top: number = tr.offsetTop - tableTop;\n\t\t\t\tconst height: number = tr.offsetHeight;\n\t\t\t\th.style.top = `${top}px`;\n\t\t\t\th.style.height = `${height}px`;\n\t\t\t\ttotalHeight = top + height;\n\t\t\t}\n\t\t}\n\n\t\trowBar.style.height = `${totalHeight}px`;\n\t}\n\n\tfunction positionAddButtons(): void {\n\t\tconst offset = getTableOffset();\n\t\tconst tableHeight: number = tableEl.offsetHeight;\n\t\tconst tableWidth: number = tableEl.offsetWidth;\n\n\t\taddRowZone.style.width = `${tableWidth}px`;\n\t\taddRowZone.style.left = `${offset.left}px`;\n\n\t\taddColZone.style.height = `${tableHeight}px`;\n\t\taddColZone.style.top = `${offset.top}px`;\n\t}\n\n\tfunction onMouseMove(e: MouseEvent): void {\n\t\tconst tableRect: DOMRect = tableEl.getBoundingClientRect();\n\t\tconst x: number = e.clientX - tableRect.left;\n\t\tconst y: number = e.clientY - tableRect.top;\n\n\t\t// Check if mouse is inside table bounds (with margin)\n\t\tconst inTable: boolean =\n\t\t\tx >= -BORDER_THRESHOLD &&\n\t\t\tx <= tableRect.width + BORDER_THRESHOLD &&\n\t\t\ty >= -BORDER_THRESHOLD &&\n\t\t\ty <= tableRect.height + BORDER_THRESHOLD;\n\n\t\tif (!inTable) {\n\t\t\thideInsertLines();\n\t\t\treturn;\n\t\t}\n\n\t\t// Find nearest row border\n\t\tconst rowBorders: BorderInfo[] = measureRowBorders();\n\t\tlet nearestRowDist: number = Number.POSITIVE_INFINITY;\n\t\tlet nearestRowBorder: BorderInfo | null = null;\n\n\t\tfor (const border of rowBorders) {\n\t\t\tconst dist: number = Math.abs(y - border.position);\n\t\t\tif (dist < nearestRowDist && dist < BORDER_THRESHOLD) {\n\t\t\t\tnearestRowDist = dist;\n\t\t\t\tnearestRowBorder = border;\n\t\t\t}\n\t\t}\n\n\t\t// Find nearest column border\n\t\tconst colBorders: BorderInfo[] = measureColBorders();\n\t\tlet nearestColDist: number = Number.POSITIVE_INFINITY;\n\t\tlet nearestColBorder: BorderInfo | null = null;\n\n\t\tfor (const border of colBorders) {\n\t\t\tconst dist: number = Math.abs(x - border.position);\n\t\t\tif (dist < nearestColDist && dist < BORDER_THRESHOLD) {\n\t\t\t\tnearestColDist = dist;\n\t\t\t\tnearestColBorder = border;\n\t\t\t}\n\t\t}\n\n\t\t// Show the nearest line (prefer the closer one)\n\t\tif (nearestRowBorder && (!nearestColBorder || nearestRowDist <= nearestColDist)) {\n\t\t\tshowHorizontalLine(nearestRowBorder);\n\t\t\thideVerticalLine();\n\t\t} else if (nearestColBorder) {\n\t\t\tshowVerticalLine(nearestColBorder);\n\t\t\thideHorizontalLine();\n\t\t} else {\n\t\t\thideInsertLines();\n\t\t}\n\t}\n\n\tfunction onMouseLeave(): void {\n\t\thideInsertLines();\n\t}\n\n\tfunction showHorizontalLine(border: BorderInfo): void {\n\t\tactiveRowIndex = border.index;\n\t\tconst offset = getTableOffset();\n\t\tinsertLineH.style.top = `${offset.top + border.position - 1}px`;\n\t\tinsertLineH.style.left = `${offset.left}px`;\n\t\tinsertLineH.style.width = `${tableEl.offsetWidth}px`;\n\t\tinsertLineH.classList.add('ntbl-insert-line--visible');\n\t}\n\n\tfunction showVerticalLine(border: BorderInfo): void {\n\t\tactiveColIndex = border.index;\n\t\tconst offset = getTableOffset();\n\t\tinsertLineV.style.left = `${offset.left + border.position - 1}px`;\n\t\tinsertLineV.style.top = `${offset.top}px`;\n\t\tinsertLineV.style.height = `${tableEl.offsetHeight}px`;\n\t\tinsertLineV.classList.add('ntbl-insert-line--visible');\n\t}\n\n\tfunction hideInsertLines(): void {\n\t\thideHorizontalLine();\n\t\thideVerticalLine();\n\t}\n\n\tfunction hideHorizontalLine(): void {\n\t\tinsertLineH.classList.remove('ntbl-insert-line--visible');\n\t\tactiveRowIndex = -1;\n\t}\n\n\tfunction hideVerticalLine(): void {\n\t\tinsertLineV.classList.remove('ntbl-insert-line--visible');\n\t\tactiveColIndex = -1;\n\t}\n\n\tfunction rebuildColHandles(): void {\n\t\tcolBar.innerHTML = '';\n\t\tfor (let i = 0; i < numCols; i++) {\n\t\t\tconst handle: HTMLDivElement = buildHandle('ntbl-col-handle', i, (idx: number) => {\n\t\t\t\tdeleteColumnAtIndex(getState, dispatch, tableId, idx);\n\t\t\t});\n\t\t\tcolBar.appendChild(handle);\n\t\t}\n\t}\n\n\tfunction rebuildRowHandles(): void {\n\t\trowBar.innerHTML = '';\n\t\tfor (let i = 0; i < numRows; i++) {\n\t\t\tconst handle: HTMLDivElement = buildHandle('ntbl-row-handle', i, (idx: number) => {\n\t\t\t\tdeleteRowAtIndex(getState, dispatch, tableId, idx);\n\t\t\t});\n\t\t\trowBar.appendChild(handle);\n\t\t}\n\t}\n\n\t// --- Public API ---\n\n\treturn {\n\t\tupdate(node: BlockNode): void {\n\t\t\ttableId = node.id;\n\t\t\tconst newRows: number = countRows(node);\n\t\t\tconst newCols: number = countCols(node);\n\n\t\t\tif (newRows !== numRows || newCols !== numCols) {\n\t\t\t\tnumRows = newRows;\n\t\t\t\tnumCols = newCols;\n\t\t\t\trebuildColHandles();\n\t\t\t\trebuildRowHandles();\n\t\t\t}\n\n\t\t\trequestAnimationFrame(() => positionControls());\n\t\t},\n\n\t\tdestroy(): void {\n\t\t\tobserver.disconnect();\n\t\t\tcontainer.removeEventListener('mousemove', onMouseMove);\n\t\t\tcontainer.removeEventListener('mouseleave', onMouseLeave);\n\t\t\tcolBar.remove();\n\t\t\trowBar.remove();\n\t\t\tinsertLineH.remove();\n\t\t\tinsertLineV.remove();\n\t\t\taddRowZone.remove();\n\t\t\taddColZone.remove();\n\t\t\tdeleteTableBtn.remove();\n\t\t},\n\t};\n}\n","/**\n * NodeViewFactories for table, table_row, and table_cell.\n * Provides custom DOM rendering with proper HTML table elements and ARIA.\n * The table NodeView includes interactive controls for row/column management.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { getBlockChildren } from '../../model/Document.js';\nimport type { SchemaRegistry } from '../../model/SchemaRegistry.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { NodeView, NodeViewFactory } from '../../view/NodeView.js';\nimport { type TableControlsHandle, createTableControls } from './TableControls.js';\n\n/**\n * Creates a NodeViewFactory for the table node type.\n * Renders as outer container with controls + table + tbody.\n */\nexport function createTableNodeViewFactory(_registry: SchemaRegistry): NodeViewFactory {\n\treturn (\n\t\tnode: BlockNode,\n\t\tgetState: () => EditorState,\n\t\tdispatch: (tr: Transaction) => void,\n\t): NodeView => {\n\t\t// Outer container: holds controls + wrapper\n\t\tconst container: HTMLDivElement = document.createElement('div');\n\t\tcontainer.className = 'ntbl-container';\n\t\tcontainer.setAttribute('data-block-id', node.id);\n\t\tcontainer.setAttribute('data-selectable', 'true');\n\n\t\t// Table wrapper: provides overflow scrolling\n\t\tconst wrapper: HTMLDivElement = document.createElement('div');\n\t\twrapper.className = 'notectl-table-wrapper';\n\n\t\tconst table: HTMLTableElement = document.createElement('table');\n\t\ttable.className = 'notectl-table';\n\t\ttable.setAttribute('role', 'table');\n\n\t\tconst rows: readonly BlockNode[] = getBlockChildren(node);\n\t\tconst totalRows: number = rows.length;\n\t\tconst totalCols: number = rows[0] ? getBlockChildren(rows[0]).length : 0;\n\t\ttable.setAttribute('aria-label', `Table with ${totalRows} rows and ${totalCols} columns`);\n\n\t\tconst tbody: HTMLTableSectionElement = document.createElement('tbody');\n\t\ttable.appendChild(tbody);\n\t\twrapper.appendChild(table);\n\t\tcontainer.appendChild(wrapper);\n\n\t\t// Live region for screen reader announcements\n\t\tconst liveRegion: HTMLDivElement = document.createElement('div');\n\t\tliveRegion.className = 'notectl-sr-only';\n\t\tliveRegion.setAttribute('aria-live', 'polite');\n\t\tliveRegion.setAttribute('aria-atomic', 'true');\n\t\tcontainer.appendChild(liveRegion);\n\n\t\t// Initialize interactive controls\n\t\tconst controls: TableControlsHandle = createTableControls(\n\t\t\tcontainer,\n\t\t\ttable,\n\t\t\tnode,\n\t\t\tgetState,\n\t\t\tdispatch,\n\t\t);\n\n\t\treturn {\n\t\t\tdom: container,\n\t\t\tcontentDOM: tbody,\n\t\t\tupdate(updatedNode: BlockNode): boolean {\n\t\t\t\tif (updatedNode.type !== 'table') return false;\n\t\t\t\tcontainer.setAttribute('data-block-id', updatedNode.id);\n\t\t\t\tcontainer.setAttribute('data-selectable', 'true');\n\t\t\t\tconst updatedRows: readonly BlockNode[] = getBlockChildren(updatedNode);\n\t\t\t\tconst newTotalRows: number = updatedRows.length;\n\t\t\t\tconst newTotalCols: number = updatedRows[0] ? getBlockChildren(updatedRows[0]).length : 0;\n\t\t\t\ttable.setAttribute(\n\t\t\t\t\t'aria-label',\n\t\t\t\t\t`Table with ${newTotalRows} rows and ${newTotalCols} columns`,\n\t\t\t\t);\n\n\t\t\t\t// Update controls to reflect new structure\n\t\t\t\tcontrols.update(updatedNode);\n\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tdestroy(): void {\n\t\t\t\tcontrols.destroy();\n\t\t\t},\n\t\t\tselectNode(): void {\n\t\t\t\tcontainer.classList.add('notectl-table--selected');\n\t\t\t},\n\t\t\tdeselectNode(): void {\n\t\t\t\tcontainer.classList.remove('notectl-table--selected');\n\t\t\t},\n\t\t};\n\t};\n}\n\n/**\n * Creates a NodeViewFactory for the table_row node type.\n * Renders as `<tr role=\"row\">`.\n */\nexport function createTableRowNodeViewFactory(_registry: SchemaRegistry): NodeViewFactory {\n\treturn (\n\t\tnode: BlockNode,\n\t\t_getState: () => EditorState,\n\t\t_dispatch: (tr: Transaction) => void,\n\t): NodeView => {\n\t\tconst tr: HTMLTableRowElement = document.createElement('tr');\n\t\ttr.setAttribute('data-block-id', node.id);\n\t\ttr.setAttribute('role', 'row');\n\n\t\treturn {\n\t\t\tdom: tr,\n\t\t\tcontentDOM: tr,\n\t\t\tupdate(updatedNode: BlockNode): boolean {\n\t\t\t\tif (updatedNode.type !== 'table_row') return false;\n\t\t\t\ttr.setAttribute('data-block-id', updatedNode.id);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tdestroy(): void {\n\t\t\t\t// No cleanup needed\n\t\t\t},\n\t\t};\n\t};\n}\n\n/**\n * Creates a NodeViewFactory for the table_cell node type.\n * Renders as `<td role=\"cell\">` with text content rendered inside.\n */\nexport function createTableCellNodeViewFactory(_registry: SchemaRegistry): NodeViewFactory {\n\treturn (\n\t\tnode: BlockNode,\n\t\t_getState: () => EditorState,\n\t\t_dispatch: (tr: Transaction) => void,\n\t): NodeView => {\n\t\tconst td: HTMLTableCellElement = document.createElement('td');\n\t\ttd.setAttribute('data-block-id', node.id);\n\t\ttd.setAttribute('role', 'cell');\n\n\t\tconst colspan: number = (node.attrs?.colspan as number | undefined) ?? 1;\n\t\tconst rowspan: number = (node.attrs?.rowspan as number | undefined) ?? 1;\n\t\tif (colspan > 1) td.colSpan = colspan;\n\t\tif (rowspan > 1) td.rowSpan = rowspan;\n\n\t\t// Apply alignment from AlignmentPlugin's patched attribute\n\t\tconst align: string | undefined = node.attrs?.align as string | undefined;\n\t\tif (align && align !== 'left') {\n\t\t\ttd.style.textAlign = align;\n\t\t}\n\n\t\treturn {\n\t\t\tdom: td,\n\t\t\tcontentDOM: td,\n\t\t\tupdate(updatedNode: BlockNode): boolean {\n\t\t\t\tif (updatedNode.type !== 'table_cell') return false;\n\t\t\t\ttd.setAttribute('data-block-id', updatedNode.id);\n\n\t\t\t\tconst newColspan: number = (updatedNode.attrs?.colspan as number | undefined) ?? 1;\n\t\t\t\tconst newRowspan: number = (updatedNode.attrs?.rowspan as number | undefined) ?? 1;\n\t\t\t\tif (newColspan > 1) {\n\t\t\t\t\ttd.colSpan = newColspan;\n\t\t\t\t} else {\n\t\t\t\t\ttd.removeAttribute('colspan');\n\t\t\t\t}\n\t\t\t\tif (newRowspan > 1) {\n\t\t\t\t\ttd.rowSpan = newRowspan;\n\t\t\t\t} else {\n\t\t\t\t\ttd.removeAttribute('rowspan');\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tdestroy(): void {\n\t\t\t\t// No cleanup needed\n\t\t\t},\n\t\t};\n\t};\n}\n","/**\n * Multi-cell selection service for tables.\n * Tracks selected cell range and provides IDs for bulk formatting.\n */\n\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport { ServiceKey } from '../Plugin.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { findTableContext, getCellAt } from './TableHelpers.js';\n\n/** Rectangular range of cells within a table. */\nexport interface CellRange {\n\treadonly tableId: BlockId;\n\treadonly fromRow: number;\n\treadonly fromCol: number;\n\treadonly toRow: number;\n\treadonly toCol: number;\n}\n\n/** Service for managing multi-cell selection. */\nexport interface TableSelectionService {\n\tgetSelectedRange(): CellRange | null;\n\tsetSelectedRange(range: CellRange | null): void;\n\tgetSelectedCellIds(): readonly BlockId[];\n\tisSelected(cellId: BlockId): boolean;\n}\n\nexport const TableSelectionServiceKey = new ServiceKey<TableSelectionService>('tableSelection');\n\n/** Creates and registers the TableSelectionService. */\nexport function createTableSelectionService(context: PluginContext): TableSelectionService {\n\tlet selectedRange: CellRange | null = null;\n\tlet cachedCellIds: readonly BlockId[] = [];\n\tlet cachedCellIdSet: Set<BlockId> = new Set();\n\n\tfunction updateCache(): void {\n\t\tif (!selectedRange) {\n\t\t\tcachedCellIds = [];\n\t\t\tcachedCellIdSet = new Set();\n\t\t\treturn;\n\t\t}\n\n\t\tconst state: EditorState = context.getState();\n\t\tconst ids: BlockId[] = [];\n\n\t\tconst minRow: number = Math.min(selectedRange.fromRow, selectedRange.toRow);\n\t\tconst maxRow: number = Math.max(selectedRange.fromRow, selectedRange.toRow);\n\t\tconst minCol: number = Math.min(selectedRange.fromCol, selectedRange.toCol);\n\t\tconst maxCol: number = Math.max(selectedRange.fromCol, selectedRange.toCol);\n\n\t\tfor (let r = minRow; r <= maxRow; r++) {\n\t\t\tfor (let c = minCol; c <= maxCol; c++) {\n\t\t\t\tconst cellId: BlockId | null = getCellAt(state, selectedRange.tableId, r, c);\n\t\t\t\tif (cellId) ids.push(cellId);\n\t\t\t}\n\t\t}\n\n\t\tcachedCellIds = ids;\n\t\tcachedCellIdSet = new Set(ids);\n\t}\n\n\tconst service: TableSelectionService = {\n\t\tgetSelectedRange(): CellRange | null {\n\t\t\treturn selectedRange;\n\t\t},\n\n\t\tsetSelectedRange(range: CellRange | null): void {\n\t\t\tselectedRange = range;\n\t\t\tupdateCache();\n\t\t\tupdateCellHighlights(context, cachedCellIdSet);\n\t\t},\n\n\t\tgetSelectedCellIds(): readonly BlockId[] {\n\t\t\treturn cachedCellIds;\n\t\t},\n\n\t\tisSelected(cellId: BlockId): boolean {\n\t\t\treturn cachedCellIdSet.has(cellId);\n\t\t},\n\t};\n\n\tcontext.registerService(TableSelectionServiceKey, service);\n\treturn service;\n}\n\n/** Updates CSS class on selected cells for visual highlighting. */\nfunction updateCellHighlights(context: PluginContext, selectedIds: Set<BlockId>): void {\n\tconst container: HTMLElement = context.getContainer();\n\tconst cells: NodeListOf<Element> = container.querySelectorAll('td[data-block-id]');\n\n\tfor (const cell of cells) {\n\t\tconst cellId = cell.getAttribute('data-block-id') as BlockId;\n\t\tif (selectedIds.has(cellId)) {\n\t\t\tcell.classList.add('notectl-table-cell--selected');\n\t\t} else {\n\t\t\tcell.classList.remove('notectl-table-cell--selected');\n\t\t}\n\t}\n}\n\n/**\n * Installs mouse handlers for multi-cell selection on the editor container.\n * Returns a cleanup function.\n */\nexport function installMouseSelection(\n\tcontext: PluginContext,\n\tservice: TableSelectionService,\n): () => void {\n\tconst container: HTMLElement = context.getContainer();\n\tlet anchorCell: { tableId: BlockId; row: number; col: number } | null = null;\n\tlet isDragging = false;\n\n\tfunction handleMouseDown(e: MouseEvent): void {\n\t\tconst target = e.target as HTMLElement;\n\t\tconst cellEl: HTMLElement | null = target.closest('td[data-block-id]');\n\t\tif (!cellEl) {\n\t\t\tservice.setSelectedRange(null);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!e.shiftKey) {\n\t\t\t// Clear any existing multi-cell selection before starting a new anchor\n\t\t\tservice.setSelectedRange(null);\n\t\t\t// Start new selection anchor\n\t\t\tconst state: EditorState = context.getState();\n\t\t\tconst cellId = cellEl.getAttribute('data-block-id') as BlockId;\n\t\t\tconst tableCtx = findTableContext(state, cellId);\n\t\t\tif (!tableCtx) return;\n\n\t\t\tanchorCell = {\n\t\t\t\ttableId: tableCtx.tableId,\n\t\t\t\trow: tableCtx.rowIndex,\n\t\t\t\tcol: tableCtx.colIndex,\n\t\t\t};\n\t\t\tisDragging = true;\n\t\t\t// Don't set range yet — wait for mousemove to avoid interfering with clicks\n\t\t} else if (anchorCell) {\n\t\t\t// Shift-click: extend selection\n\t\t\tconst state: EditorState = context.getState();\n\t\t\tconst cellId = cellEl.getAttribute('data-block-id') as BlockId;\n\t\t\tconst tableCtx = findTableContext(state, cellId);\n\t\t\tif (!tableCtx || tableCtx.tableId !== anchorCell.tableId) return;\n\n\t\t\te.preventDefault();\n\t\t\tservice.setSelectedRange({\n\t\t\t\ttableId: anchorCell.tableId,\n\t\t\t\tfromRow: anchorCell.row,\n\t\t\t\tfromCol: anchorCell.col,\n\t\t\t\ttoRow: tableCtx.rowIndex,\n\t\t\t\ttoCol: tableCtx.colIndex,\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction handleMouseMove(e: MouseEvent): void {\n\t\tif (!isDragging || !anchorCell) return;\n\n\t\tconst target = e.target as HTMLElement;\n\t\tconst cellEl: HTMLElement | null = target.closest('td[data-block-id]');\n\t\tif (!cellEl) return;\n\n\t\tconst state: EditorState = context.getState();\n\t\tconst cellId = cellEl.getAttribute('data-block-id') as BlockId;\n\t\tconst tableCtx = findTableContext(state, cellId);\n\t\tif (!tableCtx || tableCtx.tableId !== anchorCell.tableId) return;\n\n\t\t// Only set range if we've moved to a different cell\n\t\tif (tableCtx.rowIndex !== anchorCell.row || tableCtx.colIndex !== anchorCell.col) {\n\t\t\te.preventDefault();\n\t\t\tservice.setSelectedRange({\n\t\t\t\ttableId: anchorCell.tableId,\n\t\t\t\tfromRow: anchorCell.row,\n\t\t\t\tfromCol: anchorCell.col,\n\t\t\t\ttoRow: tableCtx.rowIndex,\n\t\t\t\ttoCol: tableCtx.colIndex,\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction handleMouseUp(): void {\n\t\tisDragging = false;\n\t}\n\n\tcontainer.addEventListener('mousedown', handleMouseDown);\n\tcontainer.addEventListener('mousemove', handleMouseMove);\n\tdocument.addEventListener('mouseup', handleMouseUp);\n\n\treturn () => {\n\t\tcontainer.removeEventListener('mousedown', handleMouseDown);\n\t\tcontainer.removeEventListener('mousemove', handleMouseMove);\n\t\tdocument.removeEventListener('mouseup', handleMouseUp);\n\t};\n}\n","/**\n * TablePlugin: registers table, table_row, and table_cell node types\n * with NodeSpecs, NodeViews, commands, keyboard navigation, toolbar\n * grid picker, multi-cell selection, and context menu.\n */\n\nimport { isNodeSelection } from '../../model/Selection.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { insertTable, registerTableCommands } from './TableCommands.js';\nimport { isInsideTable } from './TableHelpers.js';\nimport { registerTableKeymaps } from './TableNavigation.js';\nimport {\n\tcreateTableCellNodeViewFactory,\n\tcreateTableNodeViewFactory,\n\tcreateTableRowNodeViewFactory,\n} from './TableNodeViews.js';\nimport {\n\ttype TableSelectionService,\n\tcreateTableSelectionService,\n\tinstallMouseSelection,\n} from './TableSelection.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\ttable: Record<string, never>;\n\t\ttable_row: Record<string, never>;\n\t\ttable_cell: { colspan?: number; rowspan?: number };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface TableConfig {\n\t/** Maximum rows in grid picker. Defaults to 8. */\n\treadonly maxPickerRows?: number;\n\t/** Maximum columns in grid picker. Defaults to 8. */\n\treadonly maxPickerCols?: number;\n\t/** When true, a separator is rendered after the table toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: TableConfig = {\n\tmaxPickerRows: 8,\n\tmaxPickerCols: 8,\n};\n\n// --- SVG Icon ---\n\nconst TABLE_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">' +\n\t'<path d=\"M3 3h18v18H3V3zm2 2v4h6V5H5zm8 0v4h6V5h-6zm-8 6v4h6v-4H5z' +\n\t'm8 0v4h6v-4h-6zm-8 6v4h6v-4H5zm8 0v4h6v-4h-6z\"/></svg>';\n\n// --- Plugin ---\n\nexport class TablePlugin implements Plugin {\n\treadonly id = 'table';\n\treadonly name = 'Table';\n\treadonly priority = 40;\n\n\tprivate readonly config: TableConfig;\n\tprivate selectionService: TableSelectionService | null = null;\n\tprivate cleanupMouseSelection: (() => void) | null = null;\n\tprivate context: PluginContext | null = null;\n\n\tconstructor(config?: Partial<TableConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.context = context;\n\n\t\tthis.registerNodeSpecs(context);\n\t\tthis.registerNodeViews(context);\n\t\tregisterTableCommands(context);\n\t\tregisterTableKeymaps(context);\n\t\tthis.registerToolbarItem(context);\n\t\tthis.selectionService = createTableSelectionService(context);\n\t}\n\n\tonReady(): void {\n\t\tif (this.context && this.selectionService) {\n\t\t\tthis.cleanupMouseSelection = installMouseSelection(this.context, this.selectionService);\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.cleanupMouseSelection?.();\n\t\tthis.cleanupMouseSelection = null;\n\t\tthis.selectionService = null;\n\t\tthis.context = null;\n\t}\n\n\tonStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\t// Clear multi-cell selection when cursor moves outside table\n\t\tif (this.selectionService?.getSelectedRange()) {\n\t\t\tconst sel = newState.selection;\n\t\t\tif (isNodeSelection(sel) || !isInsideTable(newState, sel.anchor.blockId)) {\n\t\t\t\tthis.selectionService.setSelectedRange(null);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate registerNodeSpecs(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'table',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['table_row'], min: 1 },\n\t\t\tisolating: true,\n\t\t\tselectable: true,\n\t\t\ttoDOM(node) {\n\t\t\t\tconst wrapper: HTMLDivElement = document.createElement('div');\n\t\t\t\twrapper.className = 'notectl-table-wrapper';\n\t\t\t\twrapper.setAttribute('data-block-id', node.id);\n\t\t\t\treturn wrapper;\n\t\t\t},\n\t\t});\n\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'table_row',\n\t\t\tgroup: 'table_content',\n\t\t\tcontent: { allow: ['table_cell'], min: 1 },\n\t\t\ttoDOM(node) {\n\t\t\t\tconst tr: HTMLTableRowElement = document.createElement('tr');\n\t\t\t\ttr.setAttribute('data-block-id', node.id);\n\t\t\t\ttr.setAttribute('role', 'row');\n\t\t\t\treturn tr;\n\t\t\t},\n\t\t});\n\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'table_cell',\n\t\t\tgroup: 'table_content',\n\t\t\tcontent: {\n\t\t\t\tallow: ['paragraph', 'list_item', 'heading', 'blockquote', 'image', 'horizontal_rule'],\n\t\t\t},\n\t\t\tisolating: true,\n\t\t\ttoDOM(node) {\n\t\t\t\tconst td: HTMLTableCellElement = document.createElement('td');\n\t\t\t\ttd.setAttribute('data-block-id', node.id);\n\t\t\t\ttd.setAttribute('role', 'cell');\n\t\t\t\treturn td;\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerNodeViews(context: PluginContext): void {\n\t\tconst registry = context.getSchemaRegistry();\n\n\t\tcontext.registerNodeView('table', createTableNodeViewFactory(registry));\n\t\tcontext.registerNodeView('table_row', createTableRowNodeViewFactory(registry));\n\t\tcontext.registerNodeView('table_cell', createTableCellNodeViewFactory(registry));\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst maxRows: number = this.config.maxPickerRows ?? 8;\n\t\tconst maxCols: number = this.config.maxPickerCols ?? 8;\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'table',\n\t\t\tgroup: 'insert',\n\t\t\ticon: TABLE_ICON,\n\t\t\tlabel: 'Insert Table',\n\t\t\ttooltip: 'Insert Table',\n\t\t\tcommand: 'insertTable',\n\t\t\tpriority: 80,\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\tpopupType: 'gridPicker',\n\t\t\tpopupConfig: {\n\t\t\t\tmaxRows,\n\t\t\t\tmaxCols,\n\t\t\t\tonSelect: (rows: number, cols: number) => {\n\t\t\t\t\tinsertTable(context, rows, cols);\n\t\t\t\t},\n\t\t\t},\n\t\t\tisActive: (state: EditorState) => {\n\t\t\t\tif (isNodeSelection(state.selection)) return false;\n\t\t\t\treturn isInsideTable(state, state.selection.anchor.blockId);\n\t\t\t},\n\t\t});\n\t}\n}\n","/**\n * HighlightPlugin: registers a highlight (background-color) mark with attrs,\n * toolbar button with a color picker popup, and removeHighlight command.\n */\n\nimport { isMarkOfType } from '../../model/AttrRegistry.js';\nimport { getBlockMarksAtOffset, hasMark } from '../../model/Document.js';\nimport { isCollapsed, isNodeSelection, selectionRange } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\thighlight: { color: string };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface HighlightConfig {\n\t/**\n\t * Restricts the color picker to a specific set of hex colors.\n\t * Each value must be a valid hex color code (`#RGB` or `#RRGGBB`).\n\t * Duplicates are removed automatically (case-insensitive).\n\t * When omitted, the full default palette is shown.\n\t */\n\treadonly colors?: readonly string[];\n\t/** When true, a separator is rendered after the highlight toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: HighlightConfig = {};\n\n// --- Color Validation ---\n\nconst HEX_COLOR_PATTERN: RegExp = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;\n\nfunction isValidHexColor(value: string): boolean {\n\treturn HEX_COLOR_PATTERN.test(value);\n}\n\n/**\n * Validates, deduplicates, and normalizes the user-supplied color list.\n * Returns the default palette when no custom colors are provided.\n *\n * @throws {Error} if any value is not a valid hex color code.\n */\nfunction resolveColors(colors: readonly string[] | undefined): readonly string[] {\n\tif (!colors || colors.length === 0) return HIGHLIGHT_PALETTE;\n\n\tconst invalid: string[] = colors.filter((c) => !isValidHexColor(c));\n\tif (invalid.length > 0) {\n\t\tthrow new Error(\n\t\t\t`HighlightPlugin: invalid hex color(s): ${invalid.join(', ')}. Expected format: #RGB or #RRGGBB.`,\n\t\t);\n\t}\n\n\tconst seen: Set<string> = new Set();\n\tconst unique: string[] = [];\n\tfor (const color of colors) {\n\t\tconst normalized: string = color.toLowerCase();\n\t\tif (!seen.has(normalized)) {\n\t\t\tseen.add(normalized);\n\t\t\tunique.push(normalized);\n\t\t}\n\t}\n\treturn unique;\n}\n\n// --- Color Palette (Highlight-optimized: 10 columns x 5 rows) ---\n\nconst HIGHLIGHT_PALETTE: readonly string[] = [\n\t// Row 1 — Classic highlighter colors (bright, vivid)\n\t'#fff176',\n\t'#aed581',\n\t'#4dd0e1',\n\t'#64b5f6',\n\t'#ce93d8',\n\t'#f48fb1',\n\t'#ffab91',\n\t'#ff8a65',\n\t'#e6ee9c',\n\t'#80cbc4',\n\n\t// Row 2 — Light pastels\n\t'#fff9c4',\n\t'#dcedc8',\n\t'#e0f7fa',\n\t'#e3f2fd',\n\t'#f3e5f5',\n\t'#fce4ec',\n\t'#fff3e0',\n\t'#fbe9e7',\n\t'#f9fbe7',\n\t'#e0f2f1',\n\n\t// Row 3 — Medium pastels\n\t'#fff59d',\n\t'#c5e1a5',\n\t'#80deea',\n\t'#90caf9',\n\t'#e1bee7',\n\t'#f8bbd0',\n\t'#ffcc80',\n\t'#ffab91',\n\t'#e6ee9c',\n\t'#a5d6a7',\n\n\t// Row 4 — Bold pastels\n\t'#ffee58',\n\t'#9ccc65',\n\t'#26c6da',\n\t'#42a5f5',\n\t'#ab47bc',\n\t'#ec407a',\n\t'#ffa726',\n\t'#ff7043',\n\t'#d4e157',\n\t'#66bb6a',\n\n\t// Row 5 — Grays and neutral highlights\n\t'#ffffff',\n\t'#fafafa',\n\t'#f5f5f5',\n\t'#eeeeee',\n\t'#e0e0e0',\n\t'#bdbdbd',\n\t'#e8eaf6',\n\t'#efebe9',\n\t'#eceff1',\n\t'#fafafa',\n];\n\n// --- Plugin ---\n\nexport class HighlightPlugin implements Plugin {\n\treadonly id = 'highlight';\n\treadonly name = 'Highlight';\n\treadonly priority = 24;\n\n\tprivate readonly config: HighlightConfig;\n\tprivate readonly colors: readonly string[];\n\n\tconstructor(config?: Partial<HighlightConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t\tthis.colors = resolveColors(config?.colors);\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'highlight',\n\t\t\trank: 4,\n\t\t\tattrs: {\n\t\t\t\tcolor: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst span = document.createElement('span');\n\t\t\t\tconst color = mark.attrs?.color ?? '';\n\t\t\t\tspan.style.backgroundColor = color;\n\t\t\t\treturn span;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst color: string = String(mark.attrs?.color ?? '');\n\t\t\t\treturn `<span style=\"background-color: ${color}\">${content}</span>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst color: string = el.style.backgroundColor;\n\t\t\t\t\t\tif (!color) return false;\n\t\t\t\t\t\treturn { color };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['span'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('removeHighlight', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.removeHighlight(context, state);\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst pathD =\n\t\t\t'M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2z' + 'm-1.38 9L12 5.67 14.38 12H9.62z';\n\t\tconst icon: string = [\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\"',\n\t\t\t' viewBox=\"0 0 24 24\">',\n\t\t\t`<path d=\"${pathD}\"/>`,\n\t\t\t'<rect x=\"3\" y=\"17\" width=\"18\" height=\"6\"',\n\t\t\t' rx=\"0.5\" fill=\"#fff176\"/>',\n\t\t\t'</svg>',\n\t\t].join('');\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'highlight',\n\t\t\tgroup: 'format',\n\t\t\ticon,\n\t\t\tlabel: 'Highlight',\n\t\t\ttooltip: 'Highlight Color',\n\t\t\tcommand: 'removeHighlight',\n\t\t\tpriority: 46,\n\t\t\tpopupType: 'custom',\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\trenderPopup: (container, ctx) => {\n\t\t\t\tthis.renderHighlightPopup(container, ctx);\n\t\t\t},\n\t\t\tisActive: (state) => this.isHighlightActive(state),\n\t\t});\n\t}\n\n\t// --- State Queries ---\n\n\tprivate isHighlightActive(state: EditorState): boolean {\n\t\treturn this.getActiveColor(state) !== null;\n\t}\n\n\tprivate getActiveColor(state: EditorState): string | null {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return null;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tif (state.storedMarks) {\n\t\t\t\tconst mark = state.storedMarks.find((m) => m.type === 'highlight');\n\t\t\t\treturn mark && isMarkOfType(mark, 'highlight') ? (mark.attrs.color ?? null) : null;\n\t\t\t}\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return null;\n\t\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\t\tconst mark = marks.find((m) => m.type === 'highlight');\n\t\t\treturn mark && isMarkOfType(mark, 'highlight') ? (mark.attrs.color ?? null) : null;\n\t\t}\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return null;\n\t\tconst marks = getBlockMarksAtOffset(block, sel.anchor.offset);\n\t\tconst mark = marks.find((m) => m.type === 'highlight');\n\t\treturn mark && isMarkOfType(mark, 'highlight') ? (mark.attrs.color ?? null) : null;\n\t}\n\n\t// --- Highlight Application ---\n\n\tprivate applyHighlight(context: PluginContext, state: EditorState, color: string): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!anchorBlock) return false;\n\t\t\tconst currentMarks =\n\t\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\t\tconst withoutHighlight = currentMarks.filter((m) => m.type !== 'highlight');\n\t\t\tconst newMarks = [...withoutHighlight, { type: markType('highlight'), attrs: { color } }];\n\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t\tconst mark = { type: markType('highlight'), attrs: { color } };\n\n\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\tbuilder.removeMark(blockId, from, to, {\n\t\t\t\t\ttype: markType('highlight'),\n\t\t\t\t});\n\t\t\t\tbuilder.addMark(blockId, from, to, mark);\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\tprivate removeHighlight(context: PluginContext, state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!anchorBlock) return false;\n\t\t\tconst currentMarks =\n\t\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\t\tif (!hasMark(currentMarks, markType('highlight'))) return false;\n\n\t\t\tconst newMarks = currentMarks.filter((m) => m.type !== 'highlight');\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\tconst blockOrder = state.getBlockOrder();\n\t\tconst range = selectionRange(sel, blockOrder);\n\t\tconst builder = state.transaction('command');\n\n\t\tconst fromIdx = blockOrder.indexOf(range.from.blockId);\n\t\tconst toIdx = blockOrder.indexOf(range.to.blockId);\n\n\t\tfor (let i = fromIdx; i <= toIdx; i++) {\n\t\t\tconst blockId = blockOrder[i];\n\t\t\tif (!blockId) continue;\n\t\t\tconst block = state.getBlock(blockId);\n\t\t\tif (!block) continue;\n\t\t\tconst blockLen = block.children.reduce(\n\t\t\t\t(sum, c) => sum + ('text' in c ? c.text.length : 0),\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tconst from = i === fromIdx ? range.from.offset : 0;\n\t\t\tconst to = i === toIdx ? range.to.offset : blockLen;\n\n\t\t\tif (from !== to) {\n\t\t\t\tbuilder.removeMark(blockId, from, to, {\n\t\t\t\t\ttype: markType('highlight'),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tbuilder.setSelection(sel);\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\t// --- Popup Rendering ---\n\n\tprivate renderHighlightPopup(container: HTMLElement, context: PluginContext): void {\n\t\tcontainer.classList.add('notectl-color-picker');\n\n\t\tconst state = context.getState();\n\t\tconst activeColor = this.getActiveColor(state);\n\n\t\tconst defaultBtn = document.createElement('button');\n\t\tdefaultBtn.type = 'button';\n\t\tdefaultBtn.className = 'notectl-color-picker__default';\n\t\tdefaultBtn.textContent = 'None';\n\t\tdefaultBtn.addEventListener('mousedown', (e) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tcontext.executeCommand('removeHighlight');\n\t\t});\n\t\tcontainer.appendChild(defaultBtn);\n\n\t\tconst grid = document.createElement('div');\n\t\tgrid.className = 'notectl-color-picker__grid';\n\n\t\tfor (const color of this.colors) {\n\t\t\tconst swatch = document.createElement('button');\n\t\t\tswatch.type = 'button';\n\t\t\tswatch.className = 'notectl-color-picker__swatch';\n\t\t\tif (activeColor && activeColor.toLowerCase() === color.toLowerCase()) {\n\t\t\t\tswatch.classList.add('notectl-color-picker__swatch--active');\n\t\t\t}\n\t\t\tswatch.style.backgroundColor = color;\n\t\t\tif (color === '#ffffff') {\n\t\t\t\tswatch.style.border = '1px solid #d0d0d0';\n\t\t\t}\n\t\t\tswatch.title = color;\n\t\t\tswatch.setAttribute('aria-label', `Highlight color ${color}`);\n\n\t\t\tswatch.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.applyHighlight(context, context.getState(), color);\n\t\t\t});\n\n\t\t\tgrid.appendChild(swatch);\n\t\t}\n\n\t\tcontainer.appendChild(grid);\n\t}\n}\n","/**\n * SuperSubPlugin: registers superscript and subscript inline marks with\n * MarkSpecs, toggle commands, keyboard shortcuts, toolbar buttons, and\n * a middleware that enforces mutual exclusivity between the two marks.\n *\n * Data-driven — each mark type is defined declaratively and all\n * registrations are derived from the same definition table.\n */\n\nimport { isMarkActive, toggleMark } from '../../commands/Commands.js';\nimport type { Mark } from '../../model/Document.js';\nimport type { ParseRule } from '../../model/ParseRule.js';\nimport type { SanitizeConfig } from '../../model/SanitizeConfig.js';\nimport { markType as mkType } from '../../model/TypeBrands.js';\nimport type { RemoveMarkStep, Step } from '../../state/Transaction.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tsuperscript: Record<string, never>;\n\t\tsubscript: Record<string, never>;\n\t}\n}\n\n// --- Configuration ---\n\n/** Controls toolbar button visibility per mark. */\nexport interface SuperSubToolbarConfig {\n\treadonly superscript?: boolean;\n\treadonly subscript?: boolean;\n}\n\n/** Controls which marks are enabled and which toolbar buttons are shown. */\nexport interface SuperSubConfig {\n\treadonly superscript: boolean;\n\treadonly subscript: boolean;\n\treadonly toolbar?: SuperSubToolbarConfig;\n\t/** When true, a separator is rendered after the last toolbar item. */\n\treadonly separatorAfter?: boolean;\n}\n\nconst DEFAULT_CONFIG: SuperSubConfig = {\n\tsuperscript: true,\n\tsubscript: true,\n};\n\n// --- Mark Definitions ---\n\ninterface MarkDefinition {\n\treadonly type: 'superscript' | 'subscript';\n\treadonly opposite: 'superscript' | 'subscript';\n\treadonly configKey: keyof Omit<SuperSubConfig, 'toolbar' | 'separatorAfter'>;\n\treadonly rank: number;\n\treadonly tag: string;\n\treadonly label: string;\n\treadonly icon: string;\n\treadonly keyBinding: string;\n\treadonly toolbarPriority: number;\n\treadonly toHTMLString: (content: string) => string;\n\treadonly parseHTML: readonly ParseRule[];\n\treadonly sanitize: SanitizeConfig;\n}\n\nconst SUPERSCRIPT_ICON: string = [\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">',\n\t'<path d=\"M16 7.41L11.41 12 16 16.59 14.59 18l-6-6 6-6z\"',\n\t' fill=\"none\"/>',\n\t'<path d=\"M9.64 7.64c.23-.5.36-1.05.36-1.64',\n\t' 0-2.21-1.79-4-4-4H2v14h4.36c2.34 0 4.24-1.9',\n\t' 4.24-4.24 0-1.6-.89-2.99-2.2-3.71zM4.5 4.5H6c.83',\n\t' 0 1.5.67 1.5 1.5S6.83 7.5 6 7.5H4.5v-3zm2 9H4.5v-3H6.5c.83',\n\t' 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z\" fill=\"none\"/>',\n\t'<path d=\"M15.97 3.84c0-.47.19-.91.53-1.21.34-.31.8-.49',\n\t' 1.3-.49.5 0 .95.18 1.28.48.32.3.5.7.51 1.15h1.59c-.02',\n\t'-.96-.43-1.83-1.13-2.42C19.36.77 18.45.44 17.5.44c-.88',\n\t' 0-1.74.28-2.39.8-.67.53-1.06 1.28-1.06 2.1 0 .76.34',\n\t' 1.47.93 1.97.59.49 1.41.84 2.32 1.15.7.24 1.26.5 1.62.8.35.3.53.64.53',\n\t' 1.02 0 .48-.2.93-.55 1.24-.36.3-.84.48-1.37.48-.55 0-1.04-.2-1.39-.54',\n\t'-.34-.33-.53-.8-.53-1.32h-1.58c.01 1.02.43 1.95 1.16 2.57.72.62 1.67.96',\n\t' 2.67.96.92 0 1.81-.3 2.46-.84.67-.56 1.04-1.33 1.04-2.18 0-.81-.36-1.56',\n\t'-.99-2.08-.62-.51-1.48-.88-2.43-1.2-.67-.23-1.2-.47-1.52-.75-.32-.27-.46',\n\t'-.59-.46-.94z\"/>',\n\t'<path d=\"M5.88 20h2.66l3.4-5.42L15.3 20h2.67l-4.73-7.38',\n\t' 4.37-6.62h-2.6l-3.07 4.98L8.92 6h-2.6l4.26 6.58z\"/>',\n\t'</svg>',\n].join('');\n\nconst SUBSCRIPT_ICON: string = [\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">',\n\t'<path d=\"M15.97 16.84c0-.47.19-.91.53-1.21.34-.31.8-.49',\n\t' 1.3-.49.5 0 .95.18 1.28.48.32.3.5.7.51 1.15h1.59c-.02',\n\t'-.96-.43-1.83-1.13-2.42-.7-.58-1.61-.91-2.56-.91-.88',\n\t' 0-1.74.28-2.39.8-.67.53-1.06 1.28-1.06 2.1 0 .76.34',\n\t' 1.47.93 1.97.59.49 1.41.84 2.32 1.15.7.24 1.26.5 1.62.8.35.3.53.64.53',\n\t' 1.02 0 .48-.2.93-.55 1.24-.36.3-.84.48-1.37.48-.55 0-1.04-.2-1.39-.54',\n\t'-.34-.33-.53-.8-.53-1.32h-1.58c.01 1.02.43 1.95 1.16 2.57.72.62 1.67.96',\n\t' 2.67.96.92 0 1.81-.3 2.46-.84.67-.56 1.04-1.33 1.04-2.18 0-.81-.36-1.56',\n\t'-.99-2.08-.62-.51-1.48-.88-2.43-1.2-.67-.23-1.2-.47-1.52-.75-.32-.27-.46',\n\t'-.59-.46-.94z\"/>',\n\t'<path d=\"M5.88 18h2.66l3.4-5.42L15.3 18h2.67l-4.73-7.38',\n\t' 4.37-6.62h-2.6l-3.07 4.98L8.92 4h-2.6l4.26 6.58z\"/>',\n\t'</svg>',\n].join('');\n\nconst MARK_DEFINITIONS: readonly MarkDefinition[] = [\n\t{\n\t\ttype: 'superscript',\n\t\topposite: 'subscript',\n\t\tconfigKey: 'superscript',\n\t\trank: 4,\n\t\ttag: 'sup',\n\t\tlabel: 'Superscript',\n\t\ticon: SUPERSCRIPT_ICON,\n\t\tkeyBinding: 'Mod-.',\n\t\ttoolbarPriority: 50,\n\t\ttoHTMLString: (content) => `<sup>${content}</sup>`,\n\t\tparseHTML: [{ tag: 'sup' }],\n\t\tsanitize: { tags: ['sup'] },\n\t},\n\t{\n\t\ttype: 'subscript',\n\t\topposite: 'superscript',\n\t\tconfigKey: 'subscript',\n\t\trank: 4,\n\t\ttag: 'sub',\n\t\tlabel: 'Subscript',\n\t\ticon: SUBSCRIPT_ICON,\n\t\tkeyBinding: 'Mod-,',\n\t\ttoolbarPriority: 51,\n\t\ttoHTMLString: (content) => `<sub>${content}</sub>`,\n\t\tparseHTML: [{ tag: 'sub' }],\n\t\tsanitize: { tags: ['sub'] },\n\t},\n];\n\n// --- Plugin ---\n\nexport class SuperSubPlugin implements Plugin {\n\treadonly id = 'super-sub';\n\treadonly name = 'Superscript & Subscript';\n\treadonly priority = 23;\n\n\tprivate readonly config: SuperSubConfig;\n\n\tconstructor(config?: Partial<SuperSubConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tconst enabledMarks: MarkDefinition[] = MARK_DEFINITIONS.filter(\n\t\t\t(def) => this.config[def.configKey],\n\t\t);\n\n\t\tconst visibleToolbarMarks: MarkDefinition[] = enabledMarks.filter((def) =>\n\t\t\tthis.isToolbarVisible(def.configKey),\n\t\t);\n\t\tconst lastVisibleMark: MarkDefinition | undefined = visibleToolbarMarks.at(-1);\n\n\t\tfor (const def of enabledMarks) {\n\t\t\tconst isSeparatorTarget: boolean = !!this.config.separatorAfter && def === lastVisibleMark;\n\t\t\tthis.registerMark(context, def, isSeparatorTarget);\n\t\t}\n\n\t\tthis.registerKeymaps(context, enabledMarks);\n\t\tthis.registerExclusivityMiddleware(context, enabledMarks);\n\t\tthis.registerDisabledToolbarItems(context);\n\t}\n\n\tprivate registerMark(context: PluginContext, def: MarkDefinition, separatorAfter: boolean): void {\n\t\tconst commandName: string = toCommandName(def.type);\n\t\tconst toolbarVisible: boolean = this.isToolbarVisible(def.configKey);\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: def.type,\n\t\t\trank: def.rank,\n\t\t\ttoDOM() {\n\t\t\t\treturn document.createElement(def.tag);\n\t\t\t},\n\t\t\ttoHTMLString: (_mark, content) => def.toHTMLString(content),\n\t\t\tparseHTML: def.parseHTML,\n\t\t\tsanitize: def.sanitize,\n\t\t});\n\n\t\tcontext.registerCommand(commandName, () => {\n\t\t\tconst tr = toggleMark(context.getState(), mkType(def.type));\n\t\t\tif (tr) {\n\t\t\t\tcontext.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\tif (toolbarVisible) {\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: def.type,\n\t\t\t\tgroup: 'format',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel: def.label,\n\t\t\t\ttooltip: `${def.label} (${formatShortcut(def.keyBinding)})`,\n\t\t\t\tcommand: commandName,\n\t\t\t\tpriority: def.toolbarPriority,\n\t\t\t\tseparatorAfter,\n\t\t\t\tisActive: (state) => isMarkActive(state, mkType(def.type)),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext, marks: readonly MarkDefinition[]): void {\n\t\tconst keymap: Record<string, () => boolean> = {};\n\t\tfor (const def of marks) {\n\t\t\tconst commandName: string = toCommandName(def.type);\n\t\t\tkeymap[def.keyBinding] = () => context.executeCommand(commandName);\n\t\t}\n\t\tif (Object.keys(keymap).length > 0) {\n\t\t\tcontext.registerKeymap(keymap);\n\t\t}\n\t}\n\n\t/**\n\t * Ensures superscript and subscript are mutually exclusive.\n\t * When an addMark step for one type is found, a removeMark step\n\t * for the opposite type is injected. For stored marks, the opposite\n\t * mark is filtered out.\n\t */\n\tprivate registerExclusivityMiddleware(\n\t\tcontext: PluginContext,\n\t\tenabledMarks: readonly MarkDefinition[],\n\t): void {\n\t\tconst bothEnabled: boolean =\n\t\t\tenabledMarks.some((d) => d.type === 'superscript') &&\n\t\t\tenabledMarks.some((d) => d.type === 'subscript');\n\n\t\tif (!bothEnabled) return;\n\n\t\tcontext.registerMiddleware((tr, _state, next) => {\n\t\t\tlet patched = false;\n\n\t\t\t// Handle addMark steps: inject removeMark for the opposite type\n\t\t\tconst patchedSteps: Step[] = [];\n\t\t\tfor (const step of tr.steps) {\n\t\t\t\tif (step.type !== 'addMark') {\n\t\t\t\t\tpatchedSteps.push(step);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst markName: string = step.mark.type;\n\t\t\t\tconst def: MarkDefinition | undefined = MARK_DEFINITIONS.find((d) => d.type === markName);\n\t\t\t\tif (!def) {\n\t\t\t\t\tpatchedSteps.push(step);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tpatched = true;\n\t\t\t\tconst removeStep: RemoveMarkStep = {\n\t\t\t\t\ttype: 'removeMark',\n\t\t\t\t\tblockId: step.blockId,\n\t\t\t\t\tfrom: step.from,\n\t\t\t\t\tto: step.to,\n\t\t\t\t\tmark: { type: mkType(def.opposite) },\n\t\t\t\t\t...(step.path ? { path: step.path } : {}),\n\t\t\t\t};\n\t\t\t\tpatchedSteps.push(removeStep, step);\n\t\t\t}\n\n\t\t\t// Handle stored marks: remove the opposite mark\n\t\t\tlet storedMarksAfter: readonly Mark[] | null = tr.storedMarksAfter;\n\t\t\tif (storedMarksAfter) {\n\t\t\t\tconst hasSup: boolean = storedMarksAfter.some((m) => m.type === 'superscript');\n\t\t\t\tconst hasSub: boolean = storedMarksAfter.some((m) => m.type === 'subscript');\n\n\t\t\t\tif (hasSup && hasSub) {\n\t\t\t\t\t// Keep the one that was most recently added (last in array)\n\t\t\t\t\tconst lastSupIdx: number = storedMarksAfter.findLastIndex(\n\t\t\t\t\t\t(m) => m.type === 'superscript',\n\t\t\t\t\t);\n\t\t\t\t\tconst lastSubIdx: number = storedMarksAfter.findLastIndex((m) => m.type === 'subscript');\n\t\t\t\t\tconst removeType: string = lastSupIdx > lastSubIdx ? 'subscript' : 'superscript';\n\n\t\t\t\t\tstoredMarksAfter = storedMarksAfter.filter((m) => m.type !== removeType);\n\t\t\t\t\tpatched = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnext(patched ? { ...tr, steps: patchedSteps, storedMarksAfter } : tr);\n\t\t});\n\t}\n\n\t/**\n\t * Registers disabled toolbar buttons for marks whose feature is disabled\n\t * but whose toolbar button is explicitly requested.\n\t */\n\tprivate registerDisabledToolbarItems(context: PluginContext): void {\n\t\tif (!this.config.toolbar) return;\n\n\t\tfor (const def of MARK_DEFINITIONS) {\n\t\t\tconst featureEnabled: boolean = this.config[def.configKey];\n\t\t\tconst toolbarVisible: boolean = this.config.toolbar[def.configKey] ?? true;\n\n\t\t\tif (!featureEnabled && toolbarVisible) {\n\t\t\t\tcontext.registerToolbarItem({\n\t\t\t\t\tid: def.type,\n\t\t\t\t\tgroup: 'format',\n\t\t\t\t\ticon: def.icon,\n\t\t\t\t\tlabel: def.label,\n\t\t\t\t\tcommand: toCommandName(def.type),\n\t\t\t\t\tpriority: def.toolbarPriority,\n\t\t\t\t\tisEnabled: () => false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isToolbarVisible(\n\t\tconfigKey: keyof Omit<SuperSubConfig, 'toolbar' | 'separatorAfter'>,\n\t): boolean {\n\t\tif (!this.config.toolbar) return true;\n\t\treturn this.config.toolbar[configKey] ?? true;\n\t}\n}\n\n/** Converts a mark type to its toggle command name (e.g. 'superscript' → 'toggleSuperscript'). */\nfunction toCommandName(markType: string): string {\n\treturn `toggle${markType.charAt(0).toUpperCase()}${markType.slice(1)}`;\n}\n","/**\n * Image plugin commands: insert, remove, and attribute updates.\n * Supports both root-level and nested contexts (e.g. images inside table cells).\n */\n\nimport type { BlockAttrs, BlockNode } from '../../model/Document.js';\nimport { createBlockNode, getBlockChildren, isBlockNode } from '../../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tisNodeSelection,\n} from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport { nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { PluginContext } from '../Plugin.js';\nimport type { ImageAttrs } from './ImageUpload.js';\n\n/**\n * Inserts an image block. When the cursor is inside a table cell,\n * the image is inserted as a child of the cell. Otherwise it is\n * inserted after the current block at document root.\n */\nexport function insertImage(\n\tcontext: PluginContext,\n\tattrs: Partial<ImageAttrs> & { readonly src: string },\n): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\n\tconst imageAttrs: BlockAttrs = {\n\t\tsrc: attrs.src,\n\t\talt: attrs.alt ?? '',\n\t\talign: attrs.align ?? 'center',\n\t\t...(attrs.width !== undefined ? { width: attrs.width } : {}),\n\t\t...(attrs.height !== undefined ? { height: attrs.height } : {}),\n\t};\n\n\tconst anchorBlockId: BlockId = isNodeSelection(sel) ? sel.nodeId : sel.anchor.blockId;\n\n\t// Check if we're inside a table cell\n\tconst cellId: BlockId | undefined = findTableCellAncestor(state, anchorBlockId);\n\tif (cellId) {\n\t\treturn insertImageIntoCell(state, context, cellId, imageAttrs);\n\t}\n\n\treturn insertImageAtRoot(state, context, anchorBlockId, imageAttrs);\n}\n\n/** Finds a table_cell ancestor for the given block (or the block itself). */\nfunction findTableCellAncestor(state: EditorState, bid: BlockId): BlockId | undefined {\n\tconst block: BlockNode | undefined = state.getBlock(bid);\n\tif (block?.type === 'table_cell') return bid;\n\n\tconst path: BlockId[] | undefined = state.getNodePath(bid);\n\tif (!path) return undefined;\n\n\tfor (const id of path) {\n\t\tconst node: BlockNode | undefined = state.getBlock(id);\n\t\tif (node?.type === 'table_cell') return id;\n\t}\n\treturn undefined;\n}\n\n/** Inserts an image at document root after the anchor block. */\nfunction insertImageAtRoot(\n\tstate: EditorState,\n\tcontext: PluginContext,\n\tanchorBlockId: BlockId,\n\timageAttrs: BlockAttrs,\n): boolean {\n\tconst blockIndex: number = state.doc.children.findIndex((b) => b.id === anchorBlockId);\n\tif (blockIndex === -1) return false;\n\n\tconst imageBlock: BlockNode = createBlockNode(nodeType('image'), [], undefined, imageAttrs);\n\tconst newParagraph: BlockNode = createBlockNode(nodeType('paragraph'));\n\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.insertNode([], blockIndex + 1, imageBlock)\n\t\t.insertNode([], blockIndex + 2, newParagraph)\n\t\t.setSelection(createNodeSelection(imageBlock.id, []))\n\t\t.build();\n\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Inserts an image as a child of a table cell. */\nfunction insertImageIntoCell(\n\tstate: EditorState,\n\tcontext: PluginContext,\n\tcellId: BlockId,\n\timageAttrs: BlockAttrs,\n): boolean {\n\tconst cellPath: BlockId[] | undefined = state.getNodePath(cellId);\n\tif (!cellPath) return false;\n\n\tconst imageBlock: BlockNode = createBlockNode(nodeType('image'), [], undefined, imageAttrs);\n\n\t// Remove existing block children first (if any)\n\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\tif (!cell) return false;\n\n\tconst builder = state.transaction('command');\n\tconst blockChildren: readonly BlockNode[] = getBlockChildren(cell);\n\tfor (let i = blockChildren.length - 1; i >= 0; i--) {\n\t\t// Find the raw index in children array\n\t\tconst rawIndex: number = cell.children.findIndex(\n\t\t\t(c) => isBlockNode(c) && c.id === blockChildren[i]?.id,\n\t\t);\n\t\tif (rawIndex !== -1) {\n\t\t\tbuilder.removeNode(cellPath, rawIndex);\n\t\t}\n\t}\n\n\t// Insert image at index 0 (before any text nodes)\n\tbuilder.insertNode(cellPath, 0, imageBlock);\n\tbuilder.setSelection(createNodeSelection(imageBlock.id, [...cellPath, imageBlock.id]));\n\n\tcontext.dispatch(builder.build());\n\treturn true;\n}\n\n/** Removes the currently selected image block (works for nested images too). */\nexport function removeImage(context: PluginContext): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (!isNodeSelection(sel)) return false;\n\n\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\tif (!block || block.type !== 'image') return false;\n\n\tconst nodePath: BlockId[] | undefined = state.getNodePath(sel.nodeId);\n\tif (!nodePath || nodePath.length === 0) return false;\n\n\t// parentPath = all IDs except the last (the image itself)\n\tconst parentPath: BlockId[] = nodePath.slice(0, -1);\n\n\t// Find the index of the image in its parent's children\n\tlet parent: BlockNode | { readonly children: readonly BlockNode[] } | undefined;\n\tif (parentPath.length === 0) {\n\t\tparent = state.doc;\n\t} else {\n\t\tconst parentId: BlockId | undefined = parentPath[parentPath.length - 1];\n\t\tparent = parentId ? state.getBlock(parentId) : undefined;\n\t}\n\tif (!parent) return false;\n\n\tconst imageIndex: number = parent.children.findIndex(\n\t\t(c) => isBlockNode(c) && c.id === sel.nodeId,\n\t);\n\tif (imageIndex === -1) return false;\n\n\t// Determine where to place the cursor after removal\n\tconst selectionTarget: BlockId | undefined = findSelectionTargetAfterRemoval(\n\t\tstate,\n\t\tparentPath,\n\t\tsel.nodeId,\n\t);\n\tif (!selectionTarget) return false;\n\n\tconst tr = state\n\t\t.transaction('command')\n\t\t.removeNode(parentPath, imageIndex)\n\t\t.setSelection(createCollapsedSelection(selectionTarget, 0))\n\t\t.build();\n\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Finds a suitable block to select after removing an image. */\nfunction findSelectionTargetAfterRemoval(\n\tstate: EditorState,\n\tparentPath: readonly BlockId[],\n\tremovedId: BlockId,\n): BlockId | undefined {\n\tif (parentPath.length === 0) {\n\t\t// Root level: select adjacent block\n\t\tconst rootChildren: readonly BlockNode[] = state.doc.children;\n\t\tconst idx: number = rootChildren.findIndex((b) => b.id === removedId);\n\t\tconst adjacent: BlockNode | undefined = rootChildren[idx + 1] ?? rootChildren[idx - 1];\n\t\treturn adjacent?.id;\n\t}\n\n\t// Nested (e.g. inside table cell): select the cell itself\n\tconst cellId: BlockId | undefined = parentPath[parentPath.length - 1];\n\treturn cellId;\n}\n\n/** Updates attributes on the currently selected image block. */\nexport function setImageAttr(context: PluginContext, attrs: Partial<ImageAttrs>): boolean {\n\tconst state = context.getState();\n\tconst sel = state.selection;\n\tif (!isNodeSelection(sel)) return false;\n\n\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\tif (!block || block.type !== 'image') return false;\n\n\tconst path: BlockId[] | undefined = state.getNodePath(sel.nodeId);\n\tif (!path) return false;\n\n\tconst merged: BlockAttrs = { ...(block.attrs ?? {}), ...attrs };\n\tconst tr = state.transaction('command').setNodeAttr(path, merged).build();\n\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Registers all image commands on the plugin context. */\nexport function registerImageCommands(context: PluginContext): void {\n\tcontext.registerCommand('insertImage', () => {\n\t\treturn insertImage(context, { src: '' });\n\t});\n\n\tcontext.registerCommand('removeImage', () => {\n\t\treturn removeImage(context);\n\t});\n}\n","/**\n * NodeView factory for image blocks.\n * Renders <figure> with <img>, handles selection state, upload overlay,\n * and resize with 4 corner handles + live size indicator.\n */\n\nimport type { BlockAttrs, BlockNode } from '../../model/Document.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { NodeView, NodeViewFactory } from '../../view/NodeView.js';\nimport type { ImagePluginConfig, UploadState } from './ImageUpload.js';\n\nconst ALIGNMENT_CLASSES: Record<string, string> = {\n\tleft: 'notectl-image--left',\n\tcenter: 'notectl-image--center',\n\tright: 'notectl-image--right',\n};\n\nconst MIN_IMAGE_WIDTH = 50;\n\ntype HandlePosition = 'nw' | 'ne' | 'sw' | 'se';\n\nconst HANDLE_CURSORS: Readonly<Record<HandlePosition, string>> = {\n\tnw: 'nwse-resize',\n\tne: 'nesw-resize',\n\tsw: 'nesw-resize',\n\tse: 'nwse-resize',\n};\n\n/** +1 means dragging right increases width; -1 means dragging left does. */\nconst HANDLE_X_SIGN: Readonly<Record<HandlePosition, 1 | -1>> = {\n\tnw: -1,\n\tne: 1,\n\tsw: -1,\n\tse: 1,\n};\n\nconst HANDLE_LABELS: Readonly<Record<HandlePosition, string>> = {\n\tnw: 'Resize top-left',\n\tne: 'Resize top-right',\n\tsw: 'Resize bottom-left',\n\tse: 'Resize bottom-right',\n};\n\n// --- Global cursor override during resize ---\n\nlet activeCursorStyle: HTMLStyleElement | null = null;\n\nfunction setGlobalResizeCursor(cursor: string): void {\n\tclearGlobalResizeCursor();\n\tactiveCursorStyle = document.createElement('style');\n\tactiveCursorStyle.textContent = `*{cursor:${cursor}!important;user-select:none!important}`;\n\tdocument.head.appendChild(activeCursorStyle);\n}\n\nfunction clearGlobalResizeCursor(): void {\n\tif (activeCursorStyle) {\n\t\tactiveCursorStyle.remove();\n\t\tactiveCursorStyle = null;\n\t}\n}\n\n/** Creates a NodeViewFactory for image blocks. */\nexport function createImageNodeViewFactory(\n\tconfig: ImagePluginConfig,\n\tuploadStates: Map<BlockId, UploadState>,\n): NodeViewFactory {\n\treturn (\n\t\tnode: BlockNode,\n\t\tgetState: () => EditorState,\n\t\tdispatch: (tr: Transaction) => void,\n\t): NodeView => {\n\t\t// --- DOM Construction ---\n\t\tconst figure: HTMLElement = document.createElement('figure');\n\t\tfigure.className = 'notectl-image';\n\t\tfigure.setAttribute('data-block-id', node.id);\n\t\tfigure.setAttribute('data-void', 'true');\n\t\tfigure.setAttribute('data-selectable', 'true');\n\n\t\tconst container: HTMLDivElement = document.createElement('div');\n\t\tcontainer.className = 'notectl-image__container';\n\n\t\tconst img: HTMLImageElement = document.createElement('img');\n\t\timg.className = 'notectl-image__img';\n\t\timg.draggable = false;\n\n\t\tconst overlay: HTMLDivElement = document.createElement('div');\n\t\toverlay.className = 'notectl-image__overlay';\n\n\t\tcontainer.appendChild(img);\n\t\tcontainer.appendChild(overlay);\n\t\tfigure.appendChild(container);\n\n\t\tlet currentNodeId: BlockId = node.id;\n\t\tlet resizeOverlay: HTMLDivElement | null = null;\n\n\t\t// --- Attribute Application ---\n\n\t\tfunction applyAttrs(n: BlockNode): void {\n\t\t\tconst src: string = (n.attrs?.src as string | undefined) ?? '';\n\t\t\tconst alt: string = (n.attrs?.alt as string | undefined) ?? '';\n\t\t\tconst width: number | undefined = n.attrs?.width as number | undefined;\n\t\t\tconst height: number | undefined = n.attrs?.height as number | undefined;\n\t\t\tconst align: string = (n.attrs?.align as string | undefined) ?? 'center';\n\n\t\t\timg.src = src;\n\t\t\timg.alt = alt;\n\n\t\t\tif (width !== undefined) {\n\t\t\t\timg.style.width = `${width}px`;\n\t\t\t} else {\n\t\t\t\timg.style.width = '';\n\t\t\t}\n\t\t\tif (height !== undefined) {\n\t\t\t\timg.style.height = `${height}px`;\n\t\t\t} else {\n\t\t\t\timg.style.height = '';\n\t\t\t}\n\n\t\t\tfor (const cls of Object.values(ALIGNMENT_CLASSES)) {\n\t\t\t\tfigure.classList.remove(cls);\n\t\t\t}\n\t\t\tconst alignClass: string | undefined = ALIGNMENT_CLASSES[align];\n\t\t\tif (alignClass) {\n\t\t\t\tfigure.classList.add(alignClass);\n\t\t\t}\n\n\t\t\tconst uploadState: UploadState = uploadStates.get(n.id) ?? 'idle';\n\t\t\tconst isUploading: boolean = uploadState === 'uploading';\n\t\t\toverlay.classList.toggle('notectl-image__overlay--uploading', isUploading);\n\t\t\toverlay.classList.toggle('notectl-image__overlay--error', uploadState === 'error');\n\t\t\toverlay.textContent = isUploading ? 'Uploading...' : '';\n\n\t\t\tif (isUploading) {\n\t\t\t\tfigure.setAttribute('aria-busy', 'true');\n\t\t\t} else {\n\t\t\t\tfigure.removeAttribute('aria-busy');\n\t\t\t}\n\t\t}\n\n\t\tapplyAttrs(node);\n\n\t\t// --- Resize Logic ---\n\n\t\tfunction clampWidth(width: number): number {\n\t\t\treturn Math.max(MIN_IMAGE_WIDTH, Math.min(config.maxWidth, width));\n\t\t}\n\n\t\tfunction commitResize(nodeId: BlockId, width: number, height: number): void {\n\t\t\tconst state: EditorState = getState();\n\t\t\tconst block: BlockNode | undefined = state.getBlock(nodeId);\n\t\t\tif (!block) return;\n\n\t\t\tconst prevWidth: number | undefined = block.attrs?.width as number | undefined;\n\t\t\tconst prevHeight: number | undefined = block.attrs?.height as number | undefined;\n\t\t\tif (prevWidth === width && prevHeight === height) return;\n\n\t\t\tconst path: BlockId[] | undefined = state.getNodePath(nodeId);\n\t\t\tif (!path) return;\n\n\t\t\tconst merged: BlockAttrs = {\n\t\t\t\t...(block.attrs ?? {}),\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t};\n\n\t\t\tconst tr: Transaction = state.transaction('command').setNodeAttr(path, merged).build();\n\t\t\tdispatch(tr);\n\t\t}\n\n\t\tfunction attachHandleListeners(\n\t\t\thandle: HTMLDivElement,\n\t\t\tposition: HandlePosition,\n\t\t\tnodeId: BlockId,\n\t\t\tsizeIndicator: HTMLDivElement,\n\t\t): void {\n\t\t\tlet startX = 0;\n\t\t\tlet startWidth = 0;\n\t\t\tlet aspectRatio = 1;\n\n\t\t\tconst onPointerMove = (e: PointerEvent): void => {\n\t\t\t\tconst deltaX: number = e.clientX - startX;\n\t\t\t\tconst newWidth: number = clampWidth(startWidth + deltaX * HANDLE_X_SIGN[position]);\n\t\t\t\tconst newHeight: number = Math.round(newWidth / aspectRatio);\n\n\t\t\t\timg.style.width = `${newWidth}px`;\n\t\t\t\timg.style.height = `${newHeight}px`;\n\n\t\t\t\tsizeIndicator.textContent = `${Math.round(newWidth)} \\u00D7 ${newHeight}`;\n\t\t\t};\n\n\t\t\tconst onPointerUp = (e: PointerEvent): void => {\n\t\t\t\tdocument.removeEventListener('pointermove', onPointerMove);\n\t\t\t\tdocument.removeEventListener('pointerup', onPointerUp);\n\n\t\t\t\tfigure.classList.remove('notectl-image--resizing');\n\t\t\t\tsizeIndicator.classList.remove('notectl-image__size-indicator--visible');\n\t\t\t\tclearGlobalResizeCursor();\n\n\t\t\t\tconst finalWidth: number = Math.round(img.getBoundingClientRect().width);\n\t\t\t\tconst finalHeight: number = Math.round(finalWidth / aspectRatio);\n\n\t\t\t\tcommitResize(nodeId, finalWidth, finalHeight);\n\n\t\t\t\t(e.target as HTMLElement | null)?.releasePointerCapture?.(e.pointerId);\n\t\t\t};\n\n\t\t\thandle.addEventListener('pointerdown', (e: PointerEvent) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\n\t\t\t\tstartX = e.clientX;\n\t\t\t\tstartWidth = img.getBoundingClientRect().width;\n\t\t\t\tconst imgHeight: number = img.getBoundingClientRect().height;\n\t\t\t\taspectRatio = imgHeight > 0 ? startWidth / imgHeight : 1;\n\n\t\t\t\tfigure.classList.add('notectl-image--resizing');\n\t\t\t\tsizeIndicator.textContent = `${Math.round(startWidth)} \\u00D7 ${Math.round(imgHeight)}`;\n\t\t\t\tsizeIndicator.classList.add('notectl-image__size-indicator--visible');\n\t\t\t\tsetGlobalResizeCursor(HANDLE_CURSORS[position]);\n\n\t\t\t\t(e.target as HTMLElement).setPointerCapture(e.pointerId);\n\t\t\t\tdocument.addEventListener('pointermove', onPointerMove);\n\t\t\t\tdocument.addEventListener('pointerup', onPointerUp);\n\t\t\t});\n\t\t}\n\n\t\tfunction createResizeOverlay(nodeId: BlockId): void {\n\t\t\tif (!config.resizable || resizeOverlay) return;\n\n\t\t\tresizeOverlay = document.createElement('div');\n\t\t\tresizeOverlay.className = 'notectl-image__resize-overlay';\n\n\t\t\tconst sizeIndicator: HTMLDivElement = document.createElement('div');\n\t\t\tsizeIndicator.className = 'notectl-image__size-indicator';\n\t\t\tresizeOverlay.appendChild(sizeIndicator);\n\n\t\t\tconst positions: readonly HandlePosition[] = ['nw', 'ne', 'sw', 'se'];\n\t\t\tfor (const pos of positions) {\n\t\t\t\tconst handle: HTMLDivElement = document.createElement('div');\n\t\t\t\thandle.className = `notectl-image__resize-handle notectl-image__resize-handle--${pos}`;\n\t\t\t\thandle.setAttribute('aria-label', HANDLE_LABELS[pos]);\n\t\t\t\thandle.setAttribute('aria-roledescription', 'resize handle');\n\t\t\t\tattachHandleListeners(handle, pos, nodeId, sizeIndicator);\n\t\t\t\tresizeOverlay.appendChild(handle);\n\t\t\t}\n\n\t\t\tcontainer.appendChild(resizeOverlay);\n\t\t}\n\n\t\tfunction removeResizeOverlay(): void {\n\t\t\tclearGlobalResizeCursor();\n\t\t\tif (resizeOverlay) {\n\t\t\t\tresizeOverlay.remove();\n\t\t\t\tresizeOverlay = null;\n\t\t\t}\n\t\t}\n\n\t\t// --- NodeView Interface ---\n\n\t\treturn {\n\t\t\tdom: figure,\n\t\t\tcontentDOM: null,\n\n\t\t\tupdate(updatedNode: BlockNode): boolean {\n\t\t\t\tif (updatedNode.type !== 'image') return false;\n\t\t\t\tcurrentNodeId = updatedNode.id;\n\t\t\t\tfigure.setAttribute('data-block-id', updatedNode.id);\n\t\t\t\tapplyAttrs(updatedNode);\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\tselectNode(): void {\n\t\t\t\tfigure.classList.add('notectl-image--selected');\n\t\t\t\tcreateResizeOverlay(currentNodeId);\n\t\t\t},\n\n\t\t\tdeselectNode(): void {\n\t\t\t\tfigure.classList.remove('notectl-image--selected');\n\t\t\t\tremoveResizeOverlay();\n\t\t\t},\n\n\t\t\tdestroy(): void {\n\t\t\t\tremoveResizeOverlay();\n\t\t\t\t// Do NOT revoke blob URLs here — the URL may still be referenced\n\t\t\t\t// by the clipboard (cut/paste) or undo history. Blob URLs are\n\t\t\t\t// automatically released when the document is unloaded.\n\t\t\t},\n\t\t};\n\t};\n}\n","/**\n * Image plugin types, configuration, and service key.\n */\n\nimport { ServiceKey } from '../Plugin.js';\n\n// --- Image Attributes ---\n\nexport interface ImageAttrs {\n\treadonly src: string;\n\treadonly alt: string;\n\treadonly width?: number;\n\treadonly height?: number;\n\treadonly align: 'left' | 'center' | 'right';\n}\n\n// --- Upload Types ---\n\nexport interface ImageUploadResult {\n\treadonly url: string;\n\treadonly width?: number;\n\treadonly height?: number;\n}\n\nexport interface ImageUploadService {\n\tupload(file: File): Promise<ImageUploadResult>;\n}\n\nexport const IMAGE_UPLOAD_SERVICE = new ServiceKey<ImageUploadService>('image:upload');\n\nexport type UploadState = 'idle' | 'uploading' | 'complete' | 'error';\n\n// --- Configuration ---\n\nexport interface ImagePluginConfig {\n\treadonly maxWidth: number;\n\treadonly maxFileSize: number;\n\treadonly acceptedTypes: readonly string[];\n\treadonly resizable: boolean;\n\treadonly separatorAfter?: boolean;\n}\n\nexport const DEFAULT_IMAGE_CONFIG: ImagePluginConfig = {\n\tmaxWidth: 800,\n\tmaxFileSize: 10 * 1024 * 1024,\n\tacceptedTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml'],\n\tresizable: true,\n};\n","/**\n * ImagePlugin: registers an image void block type with NodeSpec,\n * NodeView, commands, file handler, and toolbar button.\n */\n\nimport type { BlockAttrs, BlockNode } from '../../model/Document.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { createBlockElement } from '../../model/NodeSpec.js';\nimport { isNodeSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { insertImage, registerImageCommands } from './ImageCommands.js';\nimport { createImageNodeViewFactory } from './ImageNodeView.js';\nimport {\n\tDEFAULT_IMAGE_CONFIG,\n\tIMAGE_UPLOAD_SERVICE,\n\ttype ImagePluginConfig,\n\ttype UploadState,\n} from './ImageUpload.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\timage: {\n\t\t\tsrc: string;\n\t\t\talt: string;\n\t\t\twidth?: number;\n\t\t\theight?: number;\n\t\t\talign: 'left' | 'center' | 'right';\n\t\t};\n\t}\n}\n\n// --- Plugin ---\n\nexport class ImagePlugin implements Plugin {\n\treadonly id = 'image';\n\treadonly name = 'Image';\n\treadonly priority = 45;\n\n\tprivate readonly config: ImagePluginConfig;\n\tprivate readonly uploadStates = new Map<BlockId, UploadState>();\n\tprivate readonly blobUrls = new Set<string>();\n\n\tconstructor(config?: Partial<ImagePluginConfig>) {\n\t\tthis.config = { ...DEFAULT_IMAGE_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerNodeView(context);\n\t\tregisterImageCommands(context);\n\t\tthis.registerFileHandler(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tdestroy(): void {\n\t\tfor (const url of this.blobUrls) {\n\t\t\tURL.revokeObjectURL(url);\n\t\t}\n\t\tthis.blobUrls.clear();\n\t\tthis.uploadStates.clear();\n\t}\n\n\tonStateChange(_oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\t// Clean up upload states for removed blocks (searches full tree)\n\t\tfor (const id of this.uploadStates.keys()) {\n\t\t\tif (!newState.getBlock(id)) {\n\t\t\t\tthis.uploadStates.delete(id);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'image',\n\t\t\tgroup: 'block',\n\t\t\tisVoid: true,\n\t\t\tselectable: true,\n\t\t\tattrs: {\n\t\t\t\tsrc: { default: '' },\n\t\t\t\talt: { default: '' },\n\t\t\t\talign: { default: 'center' },\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst figure = createBlockElement('figure', node.id);\n\t\t\t\tfigure.className = 'notectl-image';\n\t\t\t\tfigure.setAttribute('data-void', 'true');\n\t\t\t\tfigure.setAttribute('data-selectable', 'true');\n\n\t\t\t\tconst imgContainer: HTMLDivElement = document.createElement('div');\n\t\t\t\timgContainer.className = 'notectl-image__container';\n\n\t\t\t\tconst img: HTMLImageElement = document.createElement('img');\n\t\t\t\timg.className = 'notectl-image__img';\n\t\t\t\timg.src = (node.attrs?.src as string | undefined) ?? '';\n\t\t\t\timg.alt = (node.attrs?.alt as string | undefined) ?? '';\n\t\t\t\timg.draggable = false;\n\n\t\t\t\tconst width: number | undefined = node.attrs?.width as number | undefined;\n\t\t\t\tconst height: number | undefined = node.attrs?.height as number | undefined;\n\t\t\t\tif (width !== undefined) img.style.width = `${width}px`;\n\t\t\t\tif (height !== undefined) img.style.height = `${height}px`;\n\n\t\t\t\tconst align: string = (node.attrs?.align as string | undefined) ?? 'center';\n\t\t\t\tconst alignClass: string | undefined = {\n\t\t\t\t\tleft: 'notectl-image--left',\n\t\t\t\t\tcenter: 'notectl-image--center',\n\t\t\t\t\tright: 'notectl-image--right',\n\t\t\t\t}[align];\n\t\t\t\tif (alignClass) figure.classList.add(alignClass);\n\n\t\t\t\timgContainer.appendChild(img);\n\t\t\t\tfigure.appendChild(imgContainer);\n\t\t\t\treturn figure;\n\t\t\t},\n\t\t\ttoHTML(node) {\n\t\t\t\tconst src: string = escapeHTML((node.attrs?.src as string | undefined) ?? '');\n\t\t\t\tconst alt: string = escapeHTML((node.attrs?.alt as string | undefined) ?? '');\n\t\t\t\tconst width: number | undefined = node.attrs?.width as number | undefined;\n\t\t\t\tconst height: number | undefined = node.attrs?.height as number | undefined;\n\t\t\t\tconst align: string = (node.attrs?.align as string | undefined) ?? 'center';\n\n\t\t\t\tconst sizeAttrs: string =\n\t\t\t\t\t(width !== undefined ? ` width=\"${width}\"` : '') +\n\t\t\t\t\t(height !== undefined ? ` height=\"${height}\"` : '');\n\n\t\t\t\treturn `<figure class=\"notectl-image notectl-image--${escapeHTML(align)}\"><img src=\"${src}\" alt=\"${alt}\"${sizeAttrs}></figure>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'figure',\n\t\t\t\t\tgetAttrs(el) {\n\t\t\t\t\t\tconst img: HTMLImageElement | null = el.querySelector('img');\n\t\t\t\t\t\tif (!img) return false;\n\t\t\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t\t\tsrc: img.getAttribute('src') ?? '',\n\t\t\t\t\t\t\talt: img.getAttribute('alt') ?? '',\n\t\t\t\t\t\t\talign: 'center',\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst width: string | null = img.getAttribute('width');\n\t\t\t\t\t\tconst height: string | null = img.getAttribute('height');\n\t\t\t\t\t\tif (width) attrs.width = Number.parseInt(width, 10);\n\t\t\t\t\t\tif (height) attrs.height = Number.parseInt(height, 10);\n\n\t\t\t\t\t\tif (el.classList.contains('notectl-image--left')) attrs.align = 'left';\n\t\t\t\t\t\tif (el.classList.contains('notectl-image--right')) attrs.align = 'right';\n\t\t\t\t\t\treturn attrs;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'img',\n\t\t\t\t\tgetAttrs(el) {\n\t\t\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t\t\tsrc: el.getAttribute('src') ?? '',\n\t\t\t\t\t\t\talt: el.getAttribute('alt') ?? '',\n\t\t\t\t\t\t\talign: 'center',\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst width: string | null = el.getAttribute('width');\n\t\t\t\t\t\tconst height: string | null = el.getAttribute('height');\n\t\t\t\t\t\tif (width) attrs.width = Number.parseInt(width, 10);\n\t\t\t\t\t\tif (height) attrs.height = Number.parseInt(height, 10);\n\t\t\t\t\t\treturn attrs;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: {\n\t\t\t\ttags: ['figure', 'img'],\n\t\t\t\tattrs: ['src', 'alt', 'width', 'height', 'class'],\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerNodeView(context: PluginContext): void {\n\t\tcontext.registerNodeView('image', createImageNodeViewFactory(this.config, this.uploadStates));\n\t}\n\n\tprivate registerFileHandler(context: PluginContext): void {\n\t\tcontext.registerFileHandler('image/*', async (files, _position) => {\n\t\t\tconst imageFiles: File[] = files.filter((f) => this.isAcceptedType(f.type));\n\t\t\tif (imageFiles.length === 0) return false;\n\n\t\t\tfor (const file of imageFiles) {\n\t\t\t\tthis.handleFileInsert(context, file);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t});\n\t}\n\n\tprivate handleFileInsert(context: PluginContext, file: File): void {\n\t\tif (file.size > this.config.maxFileSize) return;\n\n\t\tconst blobUrl: string = URL.createObjectURL(file);\n\t\tthis.blobUrls.add(blobUrl);\n\n\t\tconst inserted: boolean = insertImage(context, { src: blobUrl });\n\t\tif (!inserted) {\n\t\t\tURL.revokeObjectURL(blobUrl);\n\t\t\tthis.blobUrls.delete(blobUrl);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find the newly inserted image block\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\t\tconst imageBlockId: BlockId = sel.nodeId;\n\n\t\tthis.uploadStates.set(imageBlockId, 'uploading');\n\n\t\t// Upload if service is registered\n\t\tconst uploadService = context.getService(IMAGE_UPLOAD_SERVICE);\n\t\tif (uploadService) {\n\t\t\tthis.uploadFile(context, file, imageBlockId, blobUrl);\n\t\t} else {\n\t\t\tthis.uploadStates.set(imageBlockId, 'complete');\n\t\t}\n\t}\n\n\tprivate async uploadFile(\n\t\tcontext: PluginContext,\n\t\tfile: File,\n\t\timageBlockId: BlockId,\n\t\tblobUrl: string,\n\t): Promise<void> {\n\t\tconst uploadService = context.getService(IMAGE_UPLOAD_SERVICE);\n\t\tif (!uploadService) return;\n\n\t\ttry {\n\t\t\tconst result = await uploadService.upload(file);\n\t\t\tthis.uploadStates.set(imageBlockId, 'complete');\n\n\t\t\t// Replace blob URL with uploaded URL\n\t\t\tconst state: EditorState = context.getState();\n\t\t\tconst block: BlockNode | undefined = state.getBlock(imageBlockId);\n\t\t\tif (!block) return;\n\n\t\t\tconst path: BlockId[] | undefined = state.getNodePath(imageBlockId);\n\t\t\tif (!path) return;\n\n\t\t\tconst merged: BlockAttrs = {\n\t\t\t\t...(block.attrs ?? {}),\n\t\t\t\tsrc: result.url,\n\t\t\t\t...(result.width !== undefined ? { width: result.width } : {}),\n\t\t\t\t...(result.height !== undefined ? { height: result.height } : {}),\n\t\t\t};\n\n\t\t\tconst tr: Transaction = state.transaction('command').setNodeAttr(path, merged).build();\n\t\t\tcontext.dispatch(tr);\n\n\t\t\t// Clean up blob URL\n\t\t\tURL.revokeObjectURL(blobUrl);\n\t\t\tthis.blobUrls.delete(blobUrl);\n\t\t} catch {\n\t\t\tthis.uploadStates.set(imageBlockId, 'error');\n\t\t}\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'image',\n\t\t\tgroup: 'insert',\n\t\t\ticon,\n\t\t\tlabel: 'Insert Image',\n\t\t\ttooltip: 'Insert Image',\n\t\t\tcommand: 'insertImage',\n\t\t\tpriority: 50,\n\t\t\tpopupType: 'custom',\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\trenderPopup: (container, ctx) => {\n\t\t\t\tthis.renderImagePopup(container, ctx);\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate renderImagePopup(container: HTMLElement, context: PluginContext): void {\n\t\tcontainer.style.padding = '8px';\n\t\tcontainer.style.minWidth = '240px';\n\n\t\t// --- File upload ---\n\t\tconst fileInput: HTMLInputElement = document.createElement('input');\n\t\tfileInput.type = 'file';\n\t\tfileInput.accept = this.config.acceptedTypes.join(',');\n\t\tfileInput.style.cssText = 'position:absolute;width:0;height:0;overflow:hidden;opacity:0;';\n\n\t\tconst uploadLabel: HTMLLabelElement = document.createElement('label');\n\t\tuploadLabel.textContent = 'Upload from computer';\n\t\tuploadLabel.setAttribute('aria-label', 'Upload image from computer');\n\t\tuploadLabel.style.cssText =\n\t\t\t'display:block;width:100%;padding:8px 12px;cursor:pointer;' +\n\t\t\t'text-align:center;box-sizing:border-box;' +\n\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t'background:var(--notectl-surface-raised);color:var(--notectl-fg);';\n\t\tuploadLabel.appendChild(fileInput);\n\n\t\tuploadLabel.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.stopPropagation();\n\t\t});\n\n\t\tfileInput.addEventListener('change', () => {\n\t\t\tconst file: File | undefined = fileInput.files?.[0];\n\t\t\tif (file) {\n\t\t\t\tthis.handleFileInsert(context, file);\n\t\t\t}\n\t\t});\n\n\t\tcontainer.appendChild(uploadLabel);\n\n\t\t// --- Separator ---\n\t\tconst separator: HTMLDivElement = document.createElement('div');\n\t\tseparator.style.cssText =\n\t\t\t'display:flex;align-items:center;margin:8px 0;' +\n\t\t\t'color:var(--notectl-fg-muted);font-size:12px;';\n\t\tconst line1: HTMLSpanElement = document.createElement('span');\n\t\tline1.style.cssText = 'flex:1;height:1px;background:var(--notectl-border);';\n\t\tconst orText: HTMLSpanElement = document.createElement('span');\n\t\torText.textContent = 'or';\n\t\torText.style.cssText = 'padding:0 8px;';\n\t\tconst line2: HTMLSpanElement = document.createElement('span');\n\t\tline2.style.cssText = 'flex:1;height:1px;background:var(--notectl-border);';\n\t\tseparator.appendChild(line1);\n\t\tseparator.appendChild(orText);\n\t\tseparator.appendChild(line2);\n\t\tcontainer.appendChild(separator);\n\n\t\t// --- URL input ---\n\t\tconst urlInput: HTMLInputElement = document.createElement('input');\n\t\turlInput.type = 'url';\n\t\turlInput.placeholder = 'https://...';\n\t\turlInput.setAttribute('aria-label', 'Image URL');\n\t\turlInput.style.cssText =\n\t\t\t'width:100%;padding:6px 8px;box-sizing:border-box;' +\n\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t'background:var(--notectl-bg);color:var(--notectl-fg);';\n\n\t\tconst insertBtn: HTMLButtonElement = document.createElement('button');\n\t\tinsertBtn.type = 'button';\n\t\tinsertBtn.textContent = 'Insert';\n\t\tinsertBtn.setAttribute('aria-label', 'Insert image');\n\t\tinsertBtn.style.cssText =\n\t\t\t'width:100%;padding:8px 12px;margin-top:4px;cursor:pointer;' +\n\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t'background:var(--notectl-surface-raised);color:var(--notectl-fg);';\n\n\t\tconst applyUrl = (): void => {\n\t\t\tconst src: string = urlInput.value.trim();\n\t\t\tif (src) {\n\t\t\t\tinsertImage(context, { src });\n\t\t\t}\n\t\t};\n\n\t\tinsertBtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tapplyUrl();\n\t\t});\n\n\t\turlInput.addEventListener('keydown', (e: KeyboardEvent) => {\n\t\t\tif (e.key === 'Enter') {\n\t\t\t\te.preventDefault();\n\t\t\t\tapplyUrl();\n\t\t\t}\n\t\t});\n\n\t\tcontainer.appendChild(urlInput);\n\t\tcontainer.appendChild(insertBtn);\n\n\t\trequestAnimationFrame(() => urlInput.focus());\n\t}\n\n\tprivate isAcceptedType(mimeType: string): boolean {\n\t\treturn this.config.acceptedTypes.some(\n\t\t\t(accepted) =>\n\t\t\t\taccepted === mimeType ||\n\t\t\t\t(accepted.endsWith('/*') && mimeType.startsWith(accepted.slice(0, -1))),\n\t\t);\n\t}\n}\n","/**\n * HardBreakPlugin: registers a hard line break (Shift+Enter → `<br>`)\n * as an InlineNode, with command and keymap bindings.\n */\n\nimport { insertHardBreakCommand } from '../../commands/Commands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface InlineNodeAttrRegistry {\n\t\thard_break: Record<string, never>;\n\t}\n}\n\n// --- Plugin ---\n\nexport class HardBreakPlugin implements Plugin {\n\treadonly id = 'hard-break';\n\treadonly name = 'Hard Break';\n\treadonly priority = 10;\n\n\tinit(context: PluginContext): void {\n\t\tthis.registerInlineNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymap(context);\n\t}\n\n\tprivate registerInlineNodeSpec(context: PluginContext): void {\n\t\tcontext.registerInlineNodeSpec({\n\t\t\ttype: 'hard_break',\n\t\t\ttoDOM() {\n\t\t\t\treturn document.createElement('br');\n\t\t\t},\n\t\t\ttoHTMLString() {\n\t\t\t\treturn '<br>';\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'br' }],\n\t\t\tsanitize: { tags: ['br'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('insertHardBreak', () => {\n\t\t\tconst state = context.getState();\n\t\t\tconst tr = insertHardBreakCommand(state);\n\t\t\tif (!tr) return false;\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Shift-Enter': () => {\n\t\t\t\tconst state = context.getState();\n\t\t\t\tconst tr = insertHardBreakCommand(state);\n\t\t\t\tif (!tr) return false;\n\t\t\t\tcontext.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t},\n\t\t});\n\t}\n}\n","/**\n * NodeView factory for code blocks.\n * Renders <pre> with a non-editable header (language label + copy button)\n * and a <code> content area where the Reconciler renders text.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { getBlockText } from '../../model/Document.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { NodeView, NodeViewFactory } from '../../view/NodeView.js';\nimport type { CodeBlockConfig } from './CodeBlockPlugin.js';\n\nconst COPY_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"14\" height=\"14\"><path d=\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z\"/></svg>';\n\n/** Creates a NodeViewFactory for code_block nodes. */\nexport function createCodeBlockNodeViewFactory(config: CodeBlockConfig): NodeViewFactory {\n\treturn (\n\t\tnode: BlockNode,\n\t\tgetState: () => EditorState,\n\t\t_dispatch: (tr: Transaction) => void,\n\t): NodeView => {\n\t\t// --- DOM Construction ---\n\t\tconst pre: HTMLElement = document.createElement('pre');\n\t\tpre.className = 'notectl-code-block';\n\t\tpre.setAttribute('data-block-id', node.id);\n\t\tpre.setAttribute('role', 'group');\n\t\tpre.setAttribute('aria-roledescription', 'code block');\n\n\t\t// Header (non-editable)\n\t\tconst header: HTMLDivElement = document.createElement('div');\n\t\theader.className = 'notectl-code-block__header';\n\t\theader.setAttribute('contenteditable', 'false');\n\n\t\tconst langLabel: HTMLSpanElement = document.createElement('span');\n\t\tlangLabel.className = 'notectl-code-block__language';\n\n\t\tconst showCopy: boolean = config.showCopyButton !== false;\n\t\tlet copyBtn: HTMLButtonElement | null = null;\n\n\t\tif (showCopy) {\n\t\t\tcopyBtn = document.createElement('button');\n\t\t\tcopyBtn.className = 'notectl-code-block__copy';\n\t\t\tcopyBtn.setAttribute('aria-label', 'Copy code');\n\t\t\tcopyBtn.type = 'button';\n\t\t\tcopyBtn.innerHTML = COPY_ICON;\n\t\t}\n\n\t\t// Screen reader live region for copy feedback\n\t\tconst copyAnnouncer: HTMLSpanElement = document.createElement('span');\n\t\tcopyAnnouncer.className = 'notectl-sr-only';\n\t\tcopyAnnouncer.setAttribute('aria-live', 'assertive');\n\t\tcopyAnnouncer.setAttribute('aria-atomic', 'true');\n\n\t\theader.appendChild(langLabel);\n\t\tif (copyBtn) {\n\t\t\theader.appendChild(copyBtn);\n\t\t}\n\t\theader.appendChild(copyAnnouncer);\n\n\t\t// Content area (Reconciler target)\n\t\tconst code: HTMLElement = document.createElement('code');\n\t\tcode.className = 'notectl-code-block__content';\n\n\t\t// Escape hint (visible only when focused, CSS-driven)\n\t\tconst escHint: HTMLDivElement = document.createElement('div');\n\t\tescHint.className = 'notectl-code-block__esc-hint';\n\t\tescHint.setAttribute('contenteditable', 'false');\n\t\tescHint.setAttribute('aria-hidden', 'true');\n\t\tescHint.textContent = 'Esc to exit';\n\n\t\tpre.appendChild(header);\n\t\tpre.appendChild(code);\n\t\tpre.appendChild(escHint);\n\n\t\t// Apply config-level color overrides as CSS custom properties\n\t\tif (config.background) {\n\t\t\tpre.style.setProperty('--notectl-code-block-bg', config.background);\n\t\t}\n\t\tif (config.headerBackground) {\n\t\t\tpre.style.setProperty('--notectl-code-block-header-bg', config.headerBackground);\n\t\t}\n\t\tif (config.textColor) {\n\t\t\tpre.style.setProperty('--notectl-code-block-color', config.textColor);\n\t\t}\n\t\tif (config.headerColor) {\n\t\t\tpre.style.setProperty('--notectl-code-block-header-color', config.headerColor);\n\t\t}\n\n\t\tlet currentNodeId: BlockId = node.id;\n\n\t\t// --- Attribute Application ---\n\n\t\tfunction applyAttrs(n: BlockNode): void {\n\t\t\tconst lang: string = (n.attrs?.language as string) ?? '';\n\t\t\tconst langName: string = lang || 'plain';\n\t\t\tlangLabel.textContent = langName;\n\t\t\tpre.setAttribute('aria-label', `${langName} code block. Press Escape to exit.`);\n\n\t\t\tif (lang) {\n\t\t\t\tcode.setAttribute('data-language', lang);\n\t\t\t} else {\n\t\t\t\tcode.removeAttribute('data-language');\n\t\t\t}\n\n\t\t\tconst bg: string = (n.attrs?.backgroundColor as string) ?? '';\n\t\t\tpre.style.backgroundColor = bg || '';\n\t\t}\n\n\t\tapplyAttrs(node);\n\n\t\t// --- Copy Button Handler ---\n\n\t\tif (copyBtn) {\n\t\t\tcopyBtn.addEventListener('click', (e: MouseEvent) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\n\t\t\t\tconst state: EditorState = getState();\n\t\t\t\tconst block: BlockNode | undefined = state.getBlock(currentNodeId);\n\t\t\t\tif (!block) return;\n\n\t\t\t\tconst text: string = getBlockText(block);\n\t\t\t\tnavigator.clipboard.writeText(text);\n\n\t\t\t\t// Announce to screen readers\n\t\t\t\tcopyAnnouncer.textContent = 'Copied to clipboard';\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tcopyAnnouncer.textContent = '';\n\t\t\t\t}, 1000);\n\t\t\t});\n\t\t}\n\n\t\t// --- NodeView Interface ---\n\n\t\treturn {\n\t\t\tdom: pre,\n\t\t\tcontentDOM: code,\n\n\t\t\tupdate(updatedNode: BlockNode): boolean {\n\t\t\t\tif (updatedNode.type !== 'code_block') return false;\n\t\t\t\tcurrentNodeId = updatedNode.id;\n\t\t\t\tpre.setAttribute('data-block-id', updatedNode.id);\n\t\t\t\tapplyAttrs(updatedNode);\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\tselectNode(): void {\n\t\t\t\tpre.classList.add('notectl-code-block--selected');\n\t\t\t},\n\n\t\t\tdeselectNode(): void {\n\t\t\t\tpre.classList.remove('notectl-code-block--selected');\n\t\t\t},\n\n\t\t\tdestroy(): void {\n\t\t\t\t// No cleanup needed\n\t\t\t},\n\t\t};\n\t};\n}\n","/**\n * CodeBlockPlugin: registers a code block type with NodeSpec, custom NodeView,\n * keyboard handling (Enter → newline, Tab → indent, Escape → exit),\n * input rules (``` → code block), mark prevention middleware,\n * toolbar button, and a typed service API.\n */\n\nimport type { DecorationSet } from '../../decorations/Decoration.js';\nimport { inline as inlineDecoration } from '../../decorations/Decoration.js';\nimport { DecorationSet as DecorationSetClass } from '../../decorations/Decoration.js';\nimport type { BlockAttrs, BlockNode } from '../../model/Document.js';\nimport {\n\tgenerateBlockId,\n\tgetBlockLength,\n\tgetBlockText,\n\tgetInlineChildren,\n\tisTextNode,\n} from '../../model/Document.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { findNodePath } from '../../model/NodeResolver.js';\nimport { createBlockElement } from '../../model/NodeSpec.js';\nimport { createCollapsedSelection, isCollapsed, isNodeSelection } from '../../model/Selection.js';\nimport type { BlockId } 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 type { Plugin, PluginContext } from '../Plugin.js';\nimport { ServiceKey } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\nimport { createCodeBlockNodeViewFactory } from './CodeBlockNodeView.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tcode_block: {\n\t\t\tlanguage: string;\n\t\t\tbackgroundColor: string;\n\t\t};\n\t}\n}\n\n// --- Syntax Highlighting Types ---\n\nexport interface SyntaxToken {\n\treadonly from: number;\n\treadonly to: number;\n\treadonly type: string;\n}\n\nexport interface SyntaxHighlighter {\n\ttokenize(code: string, language: string): readonly SyntaxToken[];\n\tgetSupportedLanguages(): readonly string[];\n}\n\n// --- Configuration ---\n\n/**\n * Configurable keyboard bindings for CodeBlockPlugin actions.\n * Omit a slot to use the default; set to `null` to disable the binding.\n *\n * Key descriptor format: `'Mod-Enter'`, `'Mod-Shift-M'`, etc.\n * `Mod` resolves to Cmd on macOS, Ctrl on Windows/Linux.\n */\nexport interface CodeBlockKeymap {\n\t/**\n\t * Insert a new paragraph below the code block and move the cursor there.\n\t * @default 'Mod-Enter'\n\t */\n\treadonly insertAfter?: string | null;\n\n\t/**\n\t * Toggle the current block between code block and paragraph.\n\t * @default 'Mod-Shift-M'\n\t */\n\treadonly toggle?: string | null;\n}\n\nconst DEFAULT_KEYMAP: Readonly<Record<keyof CodeBlockKeymap, string>> = {\n\tinsertAfter: 'Mod-Enter',\n\ttoggle: 'Mod-Shift-M',\n};\n\nexport interface CodeBlockConfig {\n\treadonly highlighter?: SyntaxHighlighter;\n\treadonly defaultLanguage?: string;\n\treadonly useSpaces?: boolean;\n\treadonly spaceCount?: number;\n\treadonly showCopyButton?: boolean;\n\treadonly separatorAfter?: boolean;\n\t/** Default body background color (overrides --notectl-code-block-bg). */\n\treadonly background?: string;\n\t/** Default header background color (overrides --notectl-code-block-header-bg). */\n\treadonly headerBackground?: string;\n\t/** Default text color (overrides --notectl-code-block-color). */\n\treadonly textColor?: string;\n\t/** Default header/label text color (overrides --notectl-code-block-header-color). */\n\treadonly headerColor?: string;\n\t/** Customize keyboard bindings for code block actions. */\n\treadonly keymap?: CodeBlockKeymap;\n}\n\nconst DEFAULT_CONFIG: CodeBlockConfig = {\n\tdefaultLanguage: '',\n\tuseSpaces: false,\n\tspaceCount: 2,\n\tshowCopyButton: true,\n};\n\n// --- Service Types ---\n\nexport interface CodeBlockService {\n\tsetLanguage(blockId: BlockId, language: string): void;\n\tgetLanguage(blockId: BlockId): string;\n\tsetBackground(blockId: BlockId, color: string): void;\n\tgetBackground(blockId: BlockId): string;\n\tisCodeBlock(blockId: BlockId): boolean;\n\tgetSupportedLanguages(): readonly string[];\n}\n\nexport const CODE_BLOCK_SERVICE_KEY = new ServiceKey<CodeBlockService>('codeBlock');\n\n// --- SVG Icon ---\n\nconst CODE_BLOCK_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z\"/></svg>';\n\n// --- Plugin ---\n\nexport class CodeBlockPlugin implements Plugin {\n\treadonly id = 'code-block';\n\treadonly name = 'Code Block';\n\treadonly priority = 36;\n\n\tprivate readonly config: CodeBlockConfig;\n\tprivate readonly resolvedKeymap: Readonly<Record<keyof CodeBlockKeymap, string | null>>;\n\tprivate context: PluginContext | null = null;\n\n\tconstructor(config?: Partial<CodeBlockConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t\tthis.resolvedKeymap = { ...DEFAULT_KEYMAP, ...config?.keymap };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.context = context;\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerNodeView(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerInputRule(context);\n\t\tthis.registerToolbarItem(context);\n\t\tthis.registerMiddleware(context);\n\t\tthis.registerService(context);\n\t\tthis.patchTableCellContent(context);\n\t}\n\n\tdestroy(): void {\n\t\tthis.context = null;\n\t}\n\n\tonStateChange(oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tif (!this.context) return;\n\n\t\tconst oldBlockId: BlockId | null = isNodeSelection(oldState.selection)\n\t\t\t? null\n\t\t\t: oldState.selection.anchor.blockId;\n\t\tconst newBlockId: BlockId | null = isNodeSelection(newState.selection)\n\t\t\t? null\n\t\t\t: newState.selection.anchor.blockId;\n\n\t\tconst oldBlock: BlockNode | undefined = oldBlockId ? oldState.getBlock(oldBlockId) : undefined;\n\t\tconst newBlock: BlockNode | undefined = newBlockId ? newState.getBlock(newBlockId) : undefined;\n\n\t\tconst wasInCode: boolean = oldBlock?.type === 'code_block';\n\t\tconst nowInCode: boolean = newBlock?.type === 'code_block';\n\n\t\t// Toggle focused class on DOM\n\t\tif (wasInCode && oldBlockId) {\n\t\t\tthis.setBlockFocused(oldBlockId, false);\n\t\t}\n\t\tif (nowInCode && newBlockId) {\n\t\t\tthis.setBlockFocused(newBlockId, true);\n\t\t}\n\n\t\t// Announce transitions\n\t\tif (!wasInCode && nowInCode) {\n\t\t\tthis.context.announce('Entered code block. Press Escape to exit.');\n\t\t} else if (wasInCode && !nowInCode) {\n\t\t\tthis.context.announce('Left code block.');\n\t\t}\n\t}\n\n\tdecorations(state: EditorState): DecorationSet {\n\t\tif (!this.config.highlighter) return DecorationSetClass.empty;\n\n\t\tconst decorations: ReturnType<typeof inlineDecoration>[] = [];\n\t\tconst highlighter = this.config.highlighter;\n\n\t\tfor (const bid of state.getBlockOrder()) {\n\t\t\tconst block: BlockNode | undefined = state.getBlock(bid);\n\t\t\tif (!block || block.type !== 'code_block') continue;\n\n\t\t\tconst lang: string = (block.attrs?.language as string) ?? '';\n\t\t\tif (!lang) continue;\n\n\t\t\tconst text: string = getBlockText(block);\n\t\t\tif (!text) continue;\n\n\t\t\tconst tokens: readonly SyntaxToken[] = highlighter.tokenize(text, lang);\n\t\t\tfor (const token of tokens) {\n\t\t\t\tdecorations.push(\n\t\t\t\t\tinlineDecoration(bid, token.from, token.to, {\n\t\t\t\t\t\tclass: `notectl-token--${token.type}`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn DecorationSetClass.create(decorations);\n\t}\n\n\t// --- NodeSpec ---\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'code_block',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\tselectable: true,\n\t\t\tattrs: {\n\t\t\t\tlanguage: { default: '' },\n\t\t\t\tbackgroundColor: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst pre: HTMLElement = createBlockElement('pre', node.id);\n\t\t\t\tpre.className = 'notectl-code-block';\n\t\t\t\tconst code: HTMLElement = document.createElement('code');\n\t\t\t\tcode.className = 'notectl-code-block__content';\n\t\t\t\tpre.appendChild(code);\n\t\t\t\treturn pre;\n\t\t\t},\n\t\t\ttoHTML(node, content) {\n\t\t\t\tconst lang: string = escapeHTML((node.attrs?.language as string) ?? '');\n\t\t\t\tconst bg: string = escapeHTML((node.attrs?.backgroundColor as string) ?? '');\n\t\t\t\tconst langAttr: string = lang ? ` data-language=\"${lang}\"` : '';\n\t\t\t\tconst bgStyle: string = bg ? ` style=\"background-color: ${bg}\"` : '';\n\t\t\t\treturn `<pre${bgStyle}><code${langAttr}>${content || ''}</code></pre>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'pre',\n\t\t\t\t\tgetAttrs(el: HTMLElement) {\n\t\t\t\t\t\tconst code: HTMLElement | null = el.querySelector('code');\n\t\t\t\t\t\tconst langClass: string = code?.className.match(/language-(\\S+)/)?.[1] ?? '';\n\t\t\t\t\t\tconst dataLang: string = code?.getAttribute('data-language') ?? '';\n\t\t\t\t\t\treturn { language: dataLang || langClass };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: {\n\t\t\t\ttags: ['pre', 'code'],\n\t\t\t\tattrs: ['data-language', 'class', 'style'],\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- NodeView ---\n\n\tprivate registerNodeView(context: PluginContext): void {\n\t\tcontext.registerNodeView('code_block', createCodeBlockNodeViewFactory(this.config));\n\t}\n\n\t// --- Commands ---\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleCodeBlock', () => {\n\t\t\treturn this.toggleCodeBlock(context);\n\t\t});\n\n\t\tcontext.registerCommand('insertCodeBlock', () => {\n\t\t\treturn this.insertCodeBlock(context);\n\t\t});\n\n\t\tcontext.registerCommand('setCodeBlockLanguage', () => {\n\t\t\treturn false;\n\t\t});\n\n\t\tcontext.registerCommand('setCodeBlockBackground', () => {\n\t\t\treturn false;\n\t\t});\n\n\t\tcontext.registerCommand('exitCodeBlock', () => {\n\t\t\treturn this.handleEscape(context);\n\t\t});\n\t}\n\n\t// --- Keymaps ---\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tconst keymap: Record<string, () => boolean> = {\n\t\t\tEnter: () => this.handleEnter(context),\n\t\t\tBackspace: () => this.handleBackspace(context),\n\t\t\tTab: () => this.handleTab(context),\n\t\t\t'Shift-Tab': () => this.handleShiftTab(context),\n\t\t\tEscape: () => this.handleEscape(context),\n\t\t\tArrowDown: () => this.handleArrowDown(context),\n\t\t\tArrowUp: () => this.handleArrowUp(context),\n\t\t\tArrowRight: () => this.handleArrowRight(context),\n\t\t\tArrowLeft: () => this.handleArrowLeft(context),\n\t\t};\n\n\t\tconst { insertAfter, toggle } = this.resolvedKeymap;\n\n\t\tif (insertAfter) {\n\t\t\tkeymap[insertAfter] = () => this.handleModEnter(context);\n\t\t}\n\t\tif (toggle) {\n\t\t\tkeymap[toggle] = () => context.executeCommand('toggleCodeBlock');\n\t\t}\n\n\t\tcontext.registerKeymap(keymap);\n\t}\n\n\t// --- Input Rule ---\n\n\tprivate registerInputRule(context: PluginContext): void {\n\t\tcontext.registerInputRule({\n\t\t\tpattern: /^```(\\w*) $/,\n\t\t\thandler: (state, match, start, _end) => {\n\t\t\t\tconst sel = state.selection;\n\t\t\t\tif (isNodeSelection(sel)) return null;\n\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\tconst language: string = match[1] ?? '';\n\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\tlanguage,\n\t\t\t\t\tbackgroundColor: '',\n\t\t\t\t};\n\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + match[0].length)\n\t\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('code_block'), attrs)\n\t\t\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, 0))\n\t\t\t\t\t.build();\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- Toolbar ---\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'code_block',\n\t\t\tgroup: 'block',\n\t\t\ticon: CODE_BLOCK_ICON,\n\t\t\tlabel: 'Code Block',\n\t\t\ttooltip: this.resolvedKeymap.toggle\n\t\t\t\t? `Code Block (${formatShortcut(this.resolvedKeymap.toggle)})`\n\t\t\t\t: 'Code Block',\n\t\t\tcommand: 'toggleCodeBlock',\n\t\t\tpriority: 56,\n\t\t\tseparatorAfter: this.config.separatorAfter,\n\t\t\tisActive: (state) => {\n\t\t\t\tif (isNodeSelection(state.selection)) return false;\n\t\t\t\tconst block: BlockNode | undefined = state.getBlock(state.selection.anchor.blockId);\n\t\t\t\treturn block?.type === 'code_block';\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- Middleware (Mark Prevention) ---\n\n\tprivate registerMiddleware(context: PluginContext): void {\n\t\tcontext.registerMiddleware((tr, state, next) => {\n\t\t\tconst hasMarkInCodeBlock: boolean = tr.steps.some((step) => {\n\t\t\t\tif (step.type !== 'addMark') return false;\n\t\t\t\tconst block: BlockNode | undefined = state.getBlock(step.blockId);\n\t\t\t\treturn block?.type === 'code_block';\n\t\t\t});\n\n\t\t\tif (!hasMarkInCodeBlock) {\n\t\t\t\tnext(tr);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst filtered = tr.steps.filter((step) => {\n\t\t\t\tif (step.type !== 'addMark') return true;\n\t\t\t\tconst block: BlockNode | undefined = state.getBlock(step.blockId);\n\t\t\t\treturn block?.type !== 'code_block';\n\t\t\t});\n\n\t\t\tnext({ ...tr, steps: filtered });\n\t\t}, 50);\n\t}\n\n\t// --- Service ---\n\n\tprivate registerService(context: PluginContext): void {\n\t\tconst plugin = this;\n\n\t\tcontext.registerService(CODE_BLOCK_SERVICE_KEY, {\n\t\t\tsetLanguage(bid: BlockId, language: string): void {\n\t\t\t\tplugin.setAttr(context, bid, 'language', language);\n\t\t\t},\n\t\t\tgetLanguage(bid: BlockId): string {\n\t\t\t\tconst ctx: PluginContext | null = plugin.context;\n\t\t\t\tif (!ctx) return '';\n\t\t\t\tconst block: BlockNode | undefined = ctx.getState().getBlock(bid);\n\t\t\t\tif (!block || block.type !== 'code_block') return '';\n\t\t\t\treturn (block.attrs?.language as string) ?? '';\n\t\t\t},\n\t\t\tsetBackground(bid: BlockId, color: string): void {\n\t\t\t\tplugin.setAttr(context, bid, 'backgroundColor', color);\n\t\t\t},\n\t\t\tgetBackground(bid: BlockId): string {\n\t\t\t\tconst ctx: PluginContext | null = plugin.context;\n\t\t\t\tif (!ctx) return '';\n\t\t\t\tconst block: BlockNode | undefined = ctx.getState().getBlock(bid);\n\t\t\t\tif (!block || block.type !== 'code_block') return '';\n\t\t\t\treturn (block.attrs?.backgroundColor as string) ?? '';\n\t\t\t},\n\t\t\tisCodeBlock(bid: BlockId): boolean {\n\t\t\t\tconst ctx: PluginContext | null = plugin.context;\n\t\t\t\tif (!ctx) return false;\n\t\t\t\tconst block: BlockNode | undefined = ctx.getState().getBlock(bid);\n\t\t\t\treturn block?.type === 'code_block';\n\t\t\t},\n\t\t\tgetSupportedLanguages(): readonly string[] {\n\t\t\t\tif (plugin.config.highlighter) {\n\t\t\t\t\treturn plugin.config.highlighter.getSupportedLanguages();\n\t\t\t\t}\n\t\t\t\treturn [];\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- Table Cell Patching ---\n\n\tprivate patchTableCellContent(context: PluginContext): void {\n\t\tconst registry = context.getSchemaRegistry();\n\t\tconst cellSpec = registry.getNodeSpec('table_cell');\n\t\tif (!cellSpec?.content) return;\n\n\t\tconst currentAllow: readonly string[] = cellSpec.content.allow ?? [];\n\t\tif (currentAllow.includes('code_block')) return;\n\n\t\tregistry.removeNodeSpec('table_cell');\n\t\tregistry.registerNodeSpec({\n\t\t\t...cellSpec,\n\t\t\tcontent: {\n\t\t\t\t...cellSpec.content,\n\t\t\t\tallow: [...currentAllow, 'code_block'],\n\t\t\t},\n\t\t});\n\t}\n\n\t// --- Keyboard Handlers ---\n\n\t/**\n\t * Handles Backspace at the start of a code block.\n\t * Converts the code block back to a paragraph, preserving text.\n\t */\n\tprivate handleBackspace(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\t\tif (sel.anchor.offset !== 0) return false;\n\n\t\tconst tr: Transaction = state\n\t\t\t.transaction('input')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate handleEnter(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tconst text: string = getBlockText(block);\n\t\tconst offset: number = sel.anchor.offset;\n\n\t\t// Exit heuristic: Enter on empty last line (text ends with \\n and cursor at end)\n\t\tif (text.endsWith('\\n') && offset === text.length) {\n\t\t\treturn this.exitOnDoubleEnter(context, sel.anchor.blockId, text);\n\t\t}\n\n\t\t// Insert newline character\n\t\tconst tr: Transaction = state\n\t\t\t.transaction('input')\n\t\t\t.insertText(sel.anchor.blockId, offset, '\\n', [])\n\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, offset + 1))\n\t\t\t.build();\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate handleTab(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tconst indent: string = this.config.useSpaces ? ' '.repeat(this.config.spaceCount ?? 2) : '\\t';\n\t\tconst offset: number = sel.anchor.offset;\n\n\t\tconst tr: Transaction = state\n\t\t\t.transaction('input')\n\t\t\t.insertText(sel.anchor.blockId, offset, indent, [])\n\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, offset + indent.length))\n\t\t\t.build();\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate handleShiftTab(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tconst text: string = getBlockText(block);\n\t\tconst offset: number = sel.anchor.offset;\n\n\t\t// Find start of current line\n\t\tconst lineStart: number = text.lastIndexOf('\\n', offset - 1) + 1;\n\n\t\tif (this.config.useSpaces) {\n\t\t\tconst spaceCount: number = this.config.spaceCount ?? 2;\n\t\t\tconst linePrefix: string = text.slice(lineStart, lineStart + spaceCount);\n\t\t\tif (linePrefix === ' '.repeat(spaceCount)) {\n\t\t\t\tconst tr: Transaction = state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, lineStart, lineStart + spaceCount)\n\t\t\t\t\t.setSelection(\n\t\t\t\t\t\tcreateCollapsedSelection(sel.anchor.blockId, Math.max(lineStart, offset - spaceCount)),\n\t\t\t\t\t)\n\t\t\t\t\t.build();\n\t\t\t\tcontext.dispatch(tr);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (text[lineStart] === '\\t') {\n\t\t\tconst tr: Transaction = state\n\t\t\t\t.transaction('input')\n\t\t\t\t.deleteTextAt(sel.anchor.blockId, lineStart, lineStart + 1)\n\t\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, Math.max(lineStart, offset - 1)))\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn true; // Consume event even if no dedent possible\n\t}\n\n\tprivate handleEscape(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tconst blockOrder: readonly BlockId[] = state.getBlockOrder();\n\t\tconst idx: number = blockOrder.indexOf(sel.anchor.blockId);\n\n\t\tif (idx < blockOrder.length - 1) {\n\t\t\t// Navigate to next block\n\t\t\tconst nextId: BlockId = blockOrder[idx + 1] as BlockId;\n\t\t\tconst tr: Transaction = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setSelection(createCollapsedSelection(nextId, 0))\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t} else {\n\t\t\t// Create a new paragraph after code block\n\t\t\tthis.insertParagraphAfter(context, sel.anchor.blockId);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles ArrowDown at the last line of a code block.\n\t * Exits to the next block or creates a paragraph below.\n\t */\n\tprivate handleArrowDown(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tconst text: string = getBlockText(block);\n\t\tconst offset: number = sel.anchor.offset;\n\n\t\t// Only exit if cursor is on the last line\n\t\tconst nextNewline: number = text.indexOf('\\n', offset);\n\t\tif (nextNewline !== -1) return false;\n\n\t\tconst blockOrder: readonly BlockId[] = state.getBlockOrder();\n\t\tconst idx: number = blockOrder.indexOf(sel.anchor.blockId);\n\n\t\tif (idx < blockOrder.length - 1) {\n\t\t\tconst nextId: BlockId = blockOrder[idx + 1] as BlockId;\n\t\t\tconst tr: Transaction = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setSelection(createCollapsedSelection(nextId, 0))\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t} else {\n\t\t\tthis.insertParagraphAfter(context, sel.anchor.blockId);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles ArrowUp at the first line of a code block.\n\t * Exits to the previous block.\n\t */\n\tprivate handleArrowUp(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tconst text: string = getBlockText(block);\n\t\tconst offset: number = sel.anchor.offset;\n\n\t\t// Only exit if cursor is on the first line\n\t\tconst firstNewline: number = text.indexOf('\\n');\n\t\tif (firstNewline !== -1 && offset > firstNewline) return false;\n\n\t\tconst blockOrder: readonly BlockId[] = state.getBlockOrder();\n\t\tconst idx: number = blockOrder.indexOf(sel.anchor.blockId);\n\n\t\tif (idx > 0) {\n\t\t\tconst prevId: BlockId = blockOrder[idx - 1] as BlockId;\n\t\t\tconst prevBlock: BlockNode | undefined = state.getBlock(prevId);\n\t\t\tconst prevLen: number = prevBlock ? getBlockLength(prevBlock) : 0;\n\t\t\tconst tr: Transaction = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setSelection(createCollapsedSelection(prevId, prevLen))\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Handles ArrowRight at the end of a code block.\n\t * Exits to the next block or creates a paragraph below.\n\t */\n\tprivate handleArrowRight(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tconst text: string = getBlockText(block);\n\t\tif (sel.anchor.offset !== text.length) return false;\n\n\t\tconst blockOrder: readonly BlockId[] = state.getBlockOrder();\n\t\tconst idx: number = blockOrder.indexOf(sel.anchor.blockId);\n\n\t\tif (idx < blockOrder.length - 1) {\n\t\t\tconst nextId: BlockId = blockOrder[idx + 1] as BlockId;\n\t\t\tconst tr: Transaction = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setSelection(createCollapsedSelection(nextId, 0))\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t} else {\n\t\t\tthis.insertParagraphAfter(context, sel.anchor.blockId);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles ArrowLeft at the start of a code block.\n\t * Exits to the previous block at end.\n\t */\n\tprivate handleArrowLeft(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tif (sel.anchor.offset !== 0) return false;\n\n\t\tconst blockOrder: readonly BlockId[] = state.getBlockOrder();\n\t\tconst idx: number = blockOrder.indexOf(sel.anchor.blockId);\n\n\t\tif (idx > 0) {\n\t\t\tconst prevId: BlockId = blockOrder[idx - 1] as BlockId;\n\t\t\tconst prevBlock: BlockNode | undefined = state.getBlock(prevId);\n\t\t\tconst prevLen: number = prevBlock ? getBlockLength(prevBlock) : 0;\n\t\t\tconst tr: Transaction = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setSelection(createCollapsedSelection(prevId, prevLen))\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Handles Mod+Enter: always creates a paragraph below and moves cursor there.\n\t */\n\tprivate handleModEnter(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'code_block') return false;\n\n\t\tthis.insertParagraphAfter(context, sel.anchor.blockId);\n\t\treturn true;\n\t}\n\n\t// --- Helpers ---\n\n\tprivate setBlockFocused(bid: BlockId, focused: boolean): void {\n\t\tif (!this.context) return;\n\t\tconst container: HTMLElement = this.context.getContainer();\n\t\tconst el: Element | null = container.querySelector(`[data-block-id=\"${bid}\"]`);\n\t\tif (el) el.classList.toggle('notectl-code-block--focused', focused);\n\t}\n\n\tprivate toggleCodeBlock(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tif (isNodeSelection(state.selection)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tif (block.type === 'code_block') {\n\t\t\tconst tr: Transaction = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setBlockType(state.selection.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(state.selection)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn this.insertCodeBlock(context);\n\t}\n\n\tprivate insertCodeBlock(context: PluginContext): boolean {\n\t\tconst state: EditorState = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel)) return false;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type === 'code_block') return false;\n\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlanguage: this.config.defaultLanguage ?? '',\n\t\t\tbackgroundColor: '',\n\t\t};\n\n\t\tconst builder: TransactionBuilder = state.transaction('command');\n\t\tthis.stripAllMarks(builder, block);\n\t\tbuilder\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('code_block'), attrs)\n\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, 0));\n\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t}\n\n\tprivate exitOnDoubleEnter(context: PluginContext, bid: BlockId, text: string): boolean {\n\t\tconst state: EditorState = context.getState();\n\n\t\t// Remove trailing newline and convert to paragraph after\n\t\tconst trimmedLen: number = text.length - 1;\n\n\t\tconst newId: BlockId = generateBlockId();\n\n\t\tconst tr: Transaction = state\n\t\t\t.transaction('input')\n\t\t\t.deleteTextAt(bid, trimmedLen, text.length)\n\t\t\t.splitBlock(bid, trimmedLen, 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\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate insertParagraphAfter(context: PluginContext, bid: BlockId): void {\n\t\tconst state: EditorState = context.getState();\n\t\tconst blockLength: number = getBlockLength(state.getBlock(bid) as BlockNode);\n\t\tconst newId: BlockId = generateBlockId();\n\n\t\tconst tr: Transaction = state\n\t\t\t.transaction('command')\n\t\t\t.splitBlock(bid, blockLength, 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\tcontext.dispatch(tr);\n\t}\n\n\tprivate setAttr(context: PluginContext, bid: BlockId, key: string, value: string): void {\n\t\tconst state: EditorState = context.getState();\n\t\tconst block: BlockNode | undefined = state.getBlock(bid);\n\t\tif (!block || block.type !== 'code_block') return;\n\n\t\tconst path: string[] | undefined = findNodePath(state.doc, bid);\n\t\tif (!path) return;\n\n\t\tconst newAttrs: BlockAttrs = { ...block.attrs, [key]: value };\n\t\tconst tr: Transaction = state\n\t\t\t.transaction('command')\n\t\t\t.setNodeAttr(path as BlockId[], newAttrs)\n\t\t\t.build();\n\n\t\tcontext.dispatch(tr);\n\t}\n\n\t/**\n\t * Strips all marks from a block's inline content.\n\t * Used when converting to code_block so no formatting carries over.\n\t */\n\tprivate stripAllMarks(builder: TransactionBuilder, block: BlockNode): void {\n\t\tconst blockLength: number = getBlockLength(block);\n\t\tif (blockLength === 0) return;\n\n\t\tconst inlineChildren = getInlineChildren(block);\n\t\tlet offset = 0;\n\n\t\tfor (const child of inlineChildren) {\n\t\t\tif (isTextNode(child)) {\n\t\t\t\tif (child.text.length > 0) {\n\t\t\t\t\tfor (const mark of child.marks) {\n\t\t\t\t\t\tbuilder.removeMark(block.id, offset, offset + child.text.length, mark);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\toffset += child.text.length;\n\t\t\t} else {\n\t\t\t\toffset += 1;\n\t\t\t}\n\t\t}\n\t}\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\t// biome-ignore lint/suspicious/noExplicitAny: dynamic path resolution\n\tlet current: any = theme;\n\tfor (const part of parts) {\n\t\tif (current === undefined || current === null) return undefined;\n\t\tcurrent = current[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 * 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 type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { isNodeSelection } from '../model/Selection.js';\nimport type { Transaction } from '../state/Transaction.js';\n\nimport type { EditorState } from '../state/EditorState.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\tschemaRegistry?: SchemaRegistry;\n}\n\nexport class InputHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly syncSelection: SyncSelectionFn;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate composing = false;\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.schemaRegistry = options.schemaRegistry;\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\t// During composition, let the browser handle it\n\t\tif (this.composing && 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\tthis.composing = true;\n\t}\n\n\tprivate onCompositionEnd(e: CompositionEvent): void {\n\t\tthis.composing = false;\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.schemaRegistry) return;\n\t\tconst rules = this.schemaRegistry.getInputRules();\n\t\tif (rules.length === 0) return;\n\n\t\tconst state = this.getState();\n\t\tif (isNodeSelection(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 { createBlockNode, createTextNode, generateBlockId } from '../model/Document.js';\nimport type { TextSegment } from '../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tisCollapsed,\n\tisNodeSelection,\n\tselectionRange,\n} from '../model/Selection.js';\nimport { nodeType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction, TransactionBuilder } from '../state/Transaction.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\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tconst range = isCollapsed(sel) ? null : selectionRange(sel, state.getBlockOrder());\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst insertBlockId = range ? range.from.blockId : sel.anchor.blockId;\n\tconst insertOffset: number = range ? range.from.offset : sel.anchor.offset;\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\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tconst range = isCollapsed(sel) ? null : selectionRange(sel, state.getBlockOrder());\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst insertBlockId = range ? range.from.blockId : sel.anchor.blockId;\n\tconst insertOffset: number = range ? range.from.offset : sel.anchor.offset;\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\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tconst range = isCollapsed(sel) ? null : selectionRange(sel, state.getBlockOrder());\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst blockId = range ? range.from.blockId : sel.anchor.blockId;\n\tconst offset: number = range ? range.from.offset : sel.anchor.offset;\n\tconst blockOrder = state.getBlockOrder();\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 * 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 {\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 [\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\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\tmarks.push({ type: markType('bold') });\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\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 * 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 { schemaFromRegistry } from '../model/Schema.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\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 { DispatchFn, GetStateFn } from './InputHandler.js';\nimport { type RichBlockData, consumeRichClipboard } from './InternalClipboard.js';\n\nexport interface PasteHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tschemaRegistry?: SchemaRegistry;\n}\n\nexport class PasteHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\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\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\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\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(html, {\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\tif (this.schemaRegistry && !this.schemaRegistry.getNodeSpec(typeName)) 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) ? sel.nodeId : sel.anchor.blockId;\n\n\t\tconst newBlockId: BlockId = generateBlockId();\n\t\tconst attrs: Record<string, string | number | boolean> | undefined = parsed.attrs\n\t\t\t? (parsed.attrs as Record<string, string | number | boolean>)\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 builder = state.transaction('paste');\n\t\tbuilder.insertNode(parentPath, index + 1, 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) ? sel.nodeId : 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 blockData of blocks) {\n\t\t\tif (!blockData.type) 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\tlet insertIndex: number = anchorIndex + 1;\n\t\tconst builder = state.transaction('paste');\n\t\tlet lastBlockId: BlockId | undefined;\n\t\tlet lastTextLen = 0;\n\n\t\tfor (const blockData of blocks) {\n\t\t\tif (!blockData.type) 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\n\t\tif (isAnchorEmpty) {\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/** 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.schemaRegistry) 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\tfor (const file of files) {\n\t\t\tconst handlers = this.schemaRegistry.matchFileHandlers(file.type);\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = handler(files, null);\n\t\t\t\tif (result === true) return true;\n\t\t\t\t// If handler returns a Promise, treat as handled\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t// Fire-and-forget for async handlers\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\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 { MarkAttrsFor, NodeAttrsFor } from '../model/AttrRegistry.js';\nimport type { BlockNode, InlineNode, Mark, 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 type { NodeView } from './NodeView.js';\n\nexport interface ReconcileOptions {\n\tregistry?: SchemaRegistry;\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}\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\tunwrapBlocks(container);\n\n\tconst oldBlockMap = new Map<BlockId, HTMLElement>();\n\tfor (const child of Array.from(container.children)) {\n\t\tconst el = child as HTMLElement;\n\t\tconst bid = el.getAttribute('data-block-id');\n\t\tif (bid) {\n\t\t\toldBlockMap.set(toBlockId(bid), el);\n\t\t}\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\tcontainer.removeChild(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\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\tcontainer.replaceChild(newEl, existingEl);\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\tif (previousSibling?.nextSibling) {\n\t\t\t\tcontainer.insertBefore(newEl, previousSibling.nextSibling);\n\t\t\t} else if (!previousSibling && container.firstChild) {\n\t\t\t\tcontainer.insertBefore(newEl, container.firstChild);\n\t\t\t} else {\n\t\t\t\tcontainer.appendChild(newEl);\n\t\t\t}\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\twrapBlocks(container, newBlocks, registry);\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\tif (registry && nodeViews && options?.getState && options?.dispatch) {\n\t\tconst factory = registry.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\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\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\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\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) => markOrder(a, registry) - markOrder(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\nfunction markOrder(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\t// Fallback order for built-in marks\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\nfunction 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}\n\t// Fallback for built-in marks\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// --- 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) => markOrder(a, registry) - markOrder(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 * Selection synchronization between editor state and DOM.\n */\n\nimport type { EditorSelection, Position, Selection } from '../model/Selection.js';\nimport { createPosition, createSelection, isNodeSelection } from '../model/Selection.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport { blockId as toBlockId } from '../model/TypeBrands.js';\n\ninterface DOMPosition {\n\tnode: Node;\n\toffset: number;\n}\n\n/** Gets the selection object, preferring shadow root's selection for Shadow DOM. */\nfunction getSelection(container: HTMLElement): globalThis.Selection | null {\n\tconst root = container.getRootNode();\n\tif (root instanceof ShadowRoot && 'getSelection' in root) {\n\t\treturn (root as ShadowRoot & { getSelection(): globalThis.Selection | null }).getSelection();\n\t}\n\treturn window.getSelection();\n}\n\n/** Syncs the editor state selection to the DOM. */\nexport function syncSelectionToDOM(container: HTMLElement, selection: EditorSelection): void {\n\tconst domSel = getSelection(container);\n\tif (!domSel) return;\n\n\t// NodeSelection: select the entire block element\n\tif (isNodeSelection(selection)) {\n\t\tconst blockEl = container.querySelector(`[data-block-id=\"${selection.nodeId}\"]`);\n\t\tif (!blockEl) return;\n\t\tconst parent = blockEl.parentNode;\n\t\tif (!parent) return;\n\t\tconst childIdx = childIndexOf(parent, blockEl);\n\t\ttry {\n\t\t\tdomSel.setBaseAndExtent(parent, childIdx, parent, childIdx + 1);\n\t\t} catch {\n\t\t\t// Selection may fail if DOM is not yet rendered\n\t\t}\n\t\treturn;\n\t}\n\n\tconst anchorPos = statePositionToDOM(container, selection.anchor);\n\tconst headPos = statePositionToDOM(container, selection.head);\n\n\tif (!anchorPos || !headPos) return;\n\n\ttry {\n\t\tdomSel.setBaseAndExtent(anchorPos.node, anchorPos.offset, headPos.node, headPos.offset);\n\t} catch {\n\t\t// Selection may fail if DOM is not yet rendered\n\t}\n}\n\n/** Reads the current DOM selection and converts it to a state selection. */\nexport function readSelectionFromDOM(container: HTMLElement): Selection | null {\n\tconst domSel = getSelection(container);\n\tif (!domSel || domSel.rangeCount === 0) return null;\n\n\tconst anchorNode = domSel.anchorNode;\n\tconst focusNode = domSel.focusNode;\n\n\tif (!anchorNode || !focusNode) return null;\n\tif (!container.contains(anchorNode) || !container.contains(focusNode)) return null;\n\n\tconst anchor = domPositionToState(container, anchorNode, domSel.anchorOffset);\n\tconst head = domPositionToState(container, focusNode, domSel.focusOffset);\n\n\tif (!anchor || !head) return null;\n\n\treturn createSelection(anchor, head);\n}\n\n/** Converts a state position (blockId + offset) to a DOM position (node + offset). */\nfunction statePositionToDOM(container: HTMLElement, pos: Position): DOMPosition | null {\n\t// If path is available, navigate directly to the leaf block\n\tlet blockEl: Element | null = null;\n\tif (pos.path && pos.path.length > 0) {\n\t\tlet current: Element = container;\n\t\tfor (const id of pos.path) {\n\t\t\tconst found = current.querySelector(`:scope [data-block-id=\"${id}\"]`);\n\t\t\tif (!found) break;\n\t\t\tcurrent = found;\n\t\t}\n\t\tif (current !== container && current.getAttribute('data-block-id') === pos.blockId) {\n\t\t\tblockEl = current;\n\t\t}\n\t}\n\tblockEl ??= container.querySelector(`[data-block-id=\"${pos.blockId}\"]`);\n\tif (!blockEl) return null;\n\n\t// Use contentDOM if available (NodeView blocks like code_block)\n\tconst contentEl: Element = resolveContentRoot(blockEl);\n\n\t// Handle empty paragraphs with <br>\n\tif (contentEl.childNodes.length === 1 && contentEl.firstChild?.nodeName === 'BR') {\n\t\treturn { node: contentEl, offset: 0 };\n\t}\n\n\t// Walk through text nodes and inline elements to find the correct position\n\tlet remaining = pos.offset;\n\tconst walker = createInlineContentWalker(contentEl);\n\n\tlet current = walker.nextNode();\n\twhile (current) {\n\t\tif (current.nodeType === Node.TEXT_NODE) {\n\t\t\tconst len = current.textContent?.length ?? 0;\n\t\t\tif (remaining <= len) {\n\t\t\t\treturn { node: current, offset: remaining };\n\t\t\t}\n\t\t\tremaining -= len;\n\t\t} else if (\n\t\t\tcurrent instanceof HTMLElement &&\n\t\t\tcurrent.getAttribute('contenteditable') === 'false'\n\t\t) {\n\t\t\t// InlineNode element — width 1 in state offset space\n\t\t\tif (remaining === 0) {\n\t\t\t\t// Position before this inline element\n\t\t\t\tconst parent = current.parentNode;\n\t\t\t\tif (parent) {\n\t\t\t\t\tconst childIndex = childIndexOf(parent, current);\n\t\t\t\t\treturn { node: parent, offset: childIndex };\n\t\t\t\t}\n\t\t\t}\n\t\t\tremaining -= 1;\n\t\t}\n\t\tcurrent = walker.nextNode();\n\t}\n\n\t// Fallback: position at end of block\n\tconst lastChild = contentEl.lastChild;\n\tif (lastChild) {\n\t\tif (lastChild.nodeType === Node.TEXT_NODE) {\n\t\t\treturn { node: lastChild, offset: lastChild.textContent?.length ?? 0 };\n\t\t}\n\t\treturn { node: contentEl, offset: contentEl.childNodes.length };\n\t}\n\n\treturn { node: contentEl, offset: 0 };\n}\n\n/** Converts a DOM position to a state position, including nested path. */\nexport function domPositionToState(\n\tcontainer: HTMLElement,\n\tnode: Node,\n\tdomOffset: number,\n): Position | null {\n\t// Find the innermost block element\n\tconst blockEl = findBlockElement(container, node);\n\tif (!blockEl) return null;\n\n\tconst rawBlockId = blockEl.getAttribute('data-block-id');\n\tif (!rawBlockId) return null;\n\tconst bid = toBlockId(rawBlockId);\n\n\t// Build path by collecting all data-block-id ancestors from leaf to root\n\tconst path = buildBlockPath(container, blockEl);\n\n\t// Use contentDOM if available (NodeView blocks like code_block)\n\tconst contentEl: Element = resolveContentRoot(blockEl);\n\n\t// Handle clicks on the block or content element itself (e.g. empty paragraph with <br>)\n\tif (node === blockEl || node === contentEl) {\n\t\tconst targetEl: Element = node === contentEl ? contentEl : blockEl;\n\t\tlet childOffset = 0;\n\t\tlet childIdx = 0;\n\t\tfor (const child of Array.from(targetEl.childNodes)) {\n\t\t\tif (childIdx >= domOffset) break;\n\t\t\tchildOffset += inlineContentWidth(child);\n\t\t\tchildIdx++;\n\t\t}\n\t\treturn createPosition(bid, childOffset, path.length > 1 ? path : undefined);\n\t}\n\n\t// If node is outside the contentDOM (e.g. in NodeView header), map to offset 0\n\tif (contentEl !== blockEl && !contentEl.contains(node)) {\n\t\treturn createPosition(bid, 0, path.length > 1 ? path : undefined);\n\t}\n\n\t// Calculate offset by walking text nodes and inline elements\n\tlet offset = 0;\n\tconst walker = createInlineContentWalker(contentEl);\n\n\tlet walkerNode = walker.nextNode();\n\twhile (walkerNode) {\n\t\tif (walkerNode === node) {\n\t\t\tif (walkerNode.nodeType === Node.TEXT_NODE) {\n\t\t\t\treturn createPosition(bid, offset + domOffset, path.length > 1 ? path : undefined);\n\t\t\t}\n\t\t\t// Node is an inline element — return offset at its start\n\t\t\treturn createPosition(bid, offset, path.length > 1 ? path : undefined);\n\t\t}\n\t\tif (walkerNode.nodeType === Node.TEXT_NODE) {\n\t\t\toffset += walkerNode.textContent?.length ?? 0;\n\t\t} else if (\n\t\t\twalkerNode instanceof HTMLElement &&\n\t\t\twalkerNode.getAttribute('contenteditable') === 'false'\n\t\t) {\n\t\t\toffset += 1;\n\t\t}\n\t\twalkerNode = walker.nextNode();\n\t}\n\n\t// If the node is not a text node, try to find the offset from element context\n\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\tlet childOffset = 0;\n\t\tlet childIdx = 0;\n\n\t\tfor (const child of Array.from(node.childNodes)) {\n\t\t\tif (childIdx >= domOffset) break;\n\t\t\tchildOffset += inlineContentWidth(child);\n\t\t\tchildIdx++;\n\t\t}\n\n\t\treturn createPosition(bid, childOffset, path.length > 1 ? path : undefined);\n\t}\n\n\treturn createPosition(bid, 0, path.length > 1 ? path : undefined);\n}\n\n/** Builds an array of block IDs from root to leaf by walking up from a block element. */\nfunction buildBlockPath(container: HTMLElement, leafBlockEl: HTMLElement): BlockId[] {\n\tconst path: BlockId[] = [];\n\tlet current: HTMLElement | null = leafBlockEl;\n\n\twhile (current && current !== container) {\n\t\tif (current.hasAttribute('data-block-id')) {\n\t\t\tpath.unshift(toBlockId(current.getAttribute('data-block-id') ?? ''));\n\t\t}\n\t\tcurrent = current.parentElement;\n\t}\n\n\treturn path;\n}\n\n/** Finds the closest block element ancestor. */\nfunction findBlockElement(container: HTMLElement, node: Node): HTMLElement | null {\n\tlet current: Node | null = node;\n\twhile (current && current !== container) {\n\t\tif (current instanceof HTMLElement && current.hasAttribute('data-block-id')) {\n\t\t\treturn current;\n\t\t}\n\t\tcurrent = current.parentNode;\n\t}\n\treturn null;\n}\n\n/** Checks if a node is inside a contentEditable=\"false\" inline element. */\nfunction isInsideInlineElement(node: Node, root: Element): boolean {\n\tlet parent: Node | null = node.parentNode;\n\twhile (parent && parent !== root) {\n\t\tif (parent instanceof HTMLElement && parent.getAttribute('contenteditable') === 'false') {\n\t\t\treturn true;\n\t\t}\n\t\tparent = parent.parentNode;\n\t}\n\treturn false;\n}\n\n/**\n * Creates a TreeWalker that visits text nodes and contentEditable=\"false\"\n * inline elements within a block, skipping mark wrappers and nested blocks.\n */\nfunction createInlineContentWalker(blockEl: Element): TreeWalker {\n\treturn document.createTreeWalker(blockEl, NodeFilter.SHOW_ALL, {\n\t\tacceptNode: (n: Node) => {\n\t\t\t// Skip anything inside an inline element (contentEditable=\"false\")\n\t\t\tif (isInsideInlineElement(n, blockEl)) return NodeFilter.FILTER_REJECT;\n\t\t\t// Skip nested block elements and their descendants\n\t\t\tif (n instanceof HTMLElement && n.hasAttribute('data-block-id') && n !== blockEl) {\n\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t}\n\t\t\t// Accept text nodes\n\t\t\tif (n.nodeType === Node.TEXT_NODE) return NodeFilter.FILTER_ACCEPT;\n\t\t\t// Accept inline elements (contentEditable=\"false\")\n\t\t\tif (n instanceof HTMLElement && n.getAttribute('contenteditable') === 'false') {\n\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t}\n\t\t\t// Skip other elements (mark wrappers, decoration wrappers) — descend\n\t\t\treturn NodeFilter.FILTER_SKIP;\n\t\t},\n\t});\n}\n\n/** Returns the child index of a node within its parent. */\nfunction childIndexOf(parent: Node, child: Node): number {\n\tlet idx = 0;\n\tfor (const c of Array.from(parent.childNodes)) {\n\t\tif (c === child) return idx;\n\t\tidx++;\n\t}\n\treturn idx;\n}\n\n/**\n * Resolves the content root for inline content walking.\n * If the block element has a contentDOM (marked with data-content-dom),\n * returns it so the walker skips NodeView structural elements (headers, etc.).\n */\nfunction resolveContentRoot(blockEl: Element): Element {\n\tconst contentDOM: Element | null = blockEl.querySelector('[data-content-dom]');\n\treturn contentDOM ?? blockEl;\n}\n\n/** Counts the inline content width of a DOM node (text length + 1 per inline element). */\nfunction inlineContentWidth(node: Node): number {\n\tif (node.nodeType === Node.TEXT_NODE) {\n\t\treturn node.textContent?.length ?? 0;\n\t}\n\tif (node instanceof HTMLElement && node.getAttribute('contenteditable') === 'false') {\n\t\treturn 1;\n\t}\n\t// Mark wrapper or other element — sum children\n\tlet width = 0;\n\tfor (const child of Array.from(node.childNodes)) {\n\t\twidth += inlineContentWidth(child);\n\t}\n\treturn width;\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 { InputHandler } from '../input/InputHandler.js';\nimport { KeyboardHandler } from '../input/KeyboardHandler.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\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 type { NodeView } from './NodeView.js';\nimport { 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\tmaxHistoryDepth?: number;\n\tonStateChange?: StateChangeCallback;\n\tgetDecorations?: (state: EditorState, tr?: Transaction) => DecorationSet;\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 isUpdating = false;\n\tprivate pendingNodeSelectionClear = false;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate readonly nodeViews = new Map<string, NodeView>();\n\tprivate decorations: DecorationSet = DecorationSet.empty;\n\tprivate readonly getDecorations?: (state: EditorState, tr?: Transaction) => DecorationSet;\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.getDecorations = options.getDecorations;\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\tschemaRegistry: this.schemaRegistry,\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\tschemaRegistry: this.schemaRegistry,\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});\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});\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\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\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});\n\t\t\tsyncSelectionToDOM(this.contentElement, newState.selection);\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} 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\t// Guard needed here: history.undo() mutates stacks before applyUpdate runs\n\t\tif (this.isUpdating) 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\t// Guard needed here: history.redo() mutates stacks before applyUpdate runs\n\t\tif (this.isUpdating) 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});\n\t\t\tsyncSelectionToDOM(this.contentElement, newState.selection);\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// If NodeSelection 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\tthis.pendingNodeSelectionClear = 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\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 is active,\n\t\t\t// allow the next syncSelectionFromDOM to override the NodeSelection\n\t\t\tif (isNodeSelection(this.state.selection)) {\n\t\t\t\tthis.pendingNodeSelectionClear = 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\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\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.schemaRegistry) 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.schemaRegistry) 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\tfor (const file of files) {\n\t\t\tconst handlers = this.schemaRegistry.matchFileHandlers(file.type);\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = handler(files, position);\n\t\t\t\tif (result === true) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\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\n\t\tlet domNode: Node | null = null;\n\t\tlet domOffset = 0;\n\n\t\t// Standard API (caretPositionFromPoint)\n\t\tif ('caretPositionFromPoint' in root) {\n\t\t\tconst cp = (root as Document).caretPositionFromPoint(x, y);\n\t\t\tif (cp) {\n\t\t\t\tdomNode = cp.offsetNode;\n\t\t\t\tdomOffset = cp.offset;\n\t\t\t}\n\t\t}\n\n\t\t// Fallback (caretRangeFromPoint)\n\t\tif (!domNode && 'caretRangeFromPoint' in root) {\n\t\t\tconst range = (root as Document).caretRangeFromPoint(x, y);\n\t\t\tif (range) {\n\t\t\t\tdomNode = range.startContainer;\n\t\t\t\tdomOffset = range.startOffset;\n\t\t\t}\n\t\t}\n\n\t\tif (!domNode) return null;\n\t\tif (!this.contentElement.contains(domNode)) return null;\n\n\t\treturn domPositionToState(this.contentElement, domNode, domOffset);\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(oldSelection?: import('../model/Selection.js').EditorSelection) {\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\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/** Cleans up all event listeners and handlers. */\n\tdestroy(): void {\n\t\tthis.inputHandler.destroy();\n\t\tthis.keyboardHandler.destroy();\n\t\tthis.pasteHandler.destroy();\n\t\tthis.clipboardHandler.destroy();\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// 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","/**\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\nconst EDITOR_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/* Toolbar */\n.notectl-plugin-container--top {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tborder-bottom: 1px solid var(--notectl-border);\n\tbackground: var(--notectl-toolbar-bg, var(--notectl-surface-raised));\n\tmin-height: 40px;\n}\n\n.notectl-toolbar {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 2px;\n\tpadding: 4px 8px;\n}\n\n.notectl-toolbar-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid transparent;\n\tborder-radius: 4px;\n\tbackground: transparent;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n\tline-height: 1;\n\tpadding: 0;\n\ttransition: background 0.1s, border-color 0.1s;\n}\n\n.notectl-toolbar-btn:hover {\n\tbackground: var(--notectl-hover-bg);\n\tborder-color: var(--notectl-border);\n}\n\n.notectl-toolbar-btn--active {\n\tbackground: var(--notectl-active-bg);\n\tborder-color: var(--notectl-primary-muted);\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-toolbar-btn:focus-visible {\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n\toutline: none;\n}\n\n.notectl-toolbar-btn:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n.notectl-toolbar-btn:disabled:hover {\n\tbackground: transparent;\n\tborder-color: transparent;\n}\n\n.notectl-toolbar-btn__icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpointer-events: none;\n}\n\n.notectl-toolbar-btn__icon svg {\n\tdisplay: block;\n\twidth: 18px;\n\theight: 18px;\n\tfill: currentColor;\n}\n\n/* Tooltip (rendered as fixed-position element in shadow root) */\n.notectl-toolbar-tooltip {\n\tposition: fixed;\n\tpadding: 4px 8px;\n\tborder-radius: 4px;\n\tbackground: var(--notectl-tooltip-bg);\n\tcolor: var(--notectl-tooltip-fg);\n\tfont-size: 11px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\tpointer-events: none;\n\tz-index: 10001;\n\tline-height: 1.4;\n\tletter-spacing: 0.01em;\n\tfont-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.notectl-toolbar-separator {\n\tdisplay: inline-block;\n\twidth: 1px;\n\theight: 20px;\n\tbackground: var(--notectl-border);\n\tmargin: 0 4px;\n\tvertical-align: middle;\n}\n\n/* Toolbar Popups */\n.notectl-toolbar-popup {\n\tbackground: var(--notectl-surface-overlay);\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\tbox-shadow: 0 4px 12px var(--notectl-shadow);\n\toverflow: hidden;\n}\n\n/* Grid Picker */\n.notectl-grid-picker__cell:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n\n/* Dropdown */\n.notectl-dropdown {\n\tmin-width: 160px;\n\tpadding: 4px 0;\n}\n\n.notectl-dropdown__item {\n\tdisplay: flex;\n\talign-items: center;\n\twidth: 100%;\n\tpadding: 8px 12px;\n\ttext-align: left;\n\tborder: none;\n\tbackground: none;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tcolor: var(--notectl-fg);\n\tline-height: 1.4;\n\tfont-family: inherit;\n\twhite-space: nowrap;\n}\n\n.notectl-dropdown__item:hover,\n.notectl-dropdown__item:focus-visible {\n\tbackground: var(--notectl-hover-bg);\n}\n\n.notectl-dropdown__item:focus-visible {\n\toutline: none;\n}\n\n.notectl-dropdown__item-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\tfont-weight: 600;\n\tcolor: var(--notectl-fg-muted);\n\tflex-shrink: 0;\n}\n\n.notectl-dropdown__item-label {\n\tflex: 1;\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/* List Wrappers — suppress native markers, we use ::before pseudo-elements */\n.notectl-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Ordered List — each <ol> wrapper resets the counter */\n.notectl-list--ordered {\n\tcounter-reset: notectl-ordered;\n}\n\n/* List Items */\n.notectl-list-item {\n\tmargin: 0;\n\tpadding: 2px 0 2px 24px;\n\tmin-height: 1.6em;\n\tposition: relative;\n}\n\n.notectl-list-item::before {\n\tposition: absolute;\n\tleft: 0;\n\tdisplay: inline-block;\n\twidth: 24px;\n\ttext-align: center;\n}\n\n/* Bullet List */\n.notectl-list-item--bullet::before {\n\tcontent: '\\\\2022';\n\tcolor: var(--notectl-fg);\n}\n\n/* Ordered List — counter increment per item */\n.notectl-list-item--ordered {\n\tcounter-increment: notectl-ordered;\n}\n\n.notectl-list-item--ordered::before {\n\tcontent: counter(notectl-ordered) '.';\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n}\n\n/* Checklist */\n.notectl-list-item--checklist::before {\n\tcontent: '\\\\2610';\n\tfont-size: 16px;\n\tcolor: var(--notectl-fg-muted);\n\tcursor: pointer;\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"]::before {\n\tcontent: '\\\\2611';\n\tcolor: var(--notectl-success);\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"] {\n\tcolor: var(--notectl-fg-muted);\n\ttext-decoration: line-through;\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/* Image */\n.notectl-image {\n\tmargin: 8px 0;\n\tuser-select: none;\n\tline-height: 0;\n}\n\n.notectl-image--center {\n\ttext-align: center;\n}\n\n.notectl-image--left {\n\ttext-align: left;\n}\n\n.notectl-image--right {\n\ttext-align: right;\n}\n\n.notectl-image__container {\n\tdisplay: inline-block;\n\tposition: relative;\n\tline-height: 0;\n}\n\n.notectl-image__img {\n\tdisplay: block;\n\tmax-width: 100%;\n\tborder-radius: 4px;\n}\n\n.notectl-image--selected .notectl-image__container {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n\tborder-radius: 6px;\n}\n\n/* Alignment toolbar (appears on image selection) */\n.notectl-image__align-toolbar {\n\tdisplay: flex;\n\tgap: 2px;\n\tposition: absolute;\n\ttop: -36px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tbackground: var(--notectl-surface-overlay);\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\tpadding: 2px;\n\tbox-shadow: 0 2px 8px var(--notectl-shadow);\n\tz-index: 10;\n}\n\n.notectl-image__align-btn {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\theight: 28px;\n\tborder: none;\n\tbackground: transparent;\n\tborder-radius: 4px;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n}\n\n.notectl-image__align-btn:hover {\n\tbackground: var(--notectl-hover-bg);\n}\n\n.notectl-image__align-btn--active {\n\tbackground: var(--notectl-active-bg);\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-image__align-btn svg {\n\twidth: 16px;\n\theight: 16px;\n\tfill: currentColor;\n}\n\n/* Upload overlay */\n.notectl-image__overlay {\n\tposition: absolute;\n\tinset: 0;\n\tdisplay: none;\n\talign-items: center;\n\tjustify-content: center;\n\tbackground: rgba(255, 255, 255, 0.8);\n\tborder-radius: 4px;\n\tfont-size: 13px;\n\tcolor: var(--notectl-fg-muted);\n}\n\n.notectl-image__overlay--uploading {\n\tdisplay: flex;\n}\n\n.notectl-image__overlay--error {\n\tdisplay: flex;\n\tbackground: var(--notectl-danger-muted);\n\tcolor: var(--notectl-danger);\n}\n\n/* Resize overlay + handles */\n.notectl-image__resize-overlay {\n\tposition: absolute;\n\tinset: 0;\n\tpointer-events: none;\n}\n\n.notectl-image__resize-handle {\n\tposition: absolute;\n\twidth: 10px;\n\theight: 10px;\n\tbackground: var(--notectl-bg);\n\tborder: 2px solid var(--notectl-primary);\n\tborder-radius: 50%;\n\tpointer-events: all;\n\tz-index: 2;\n\ttransition: transform 0.1s, background 0.1s;\n}\n\n.notectl-image__resize-handle:hover {\n\tbackground: var(--notectl-primary);\n\ttransform: scale(1.3);\n}\n\n.notectl-image--resizing .notectl-image__resize-handle {\n\tbackground: var(--notectl-primary);\n}\n\n.notectl-image__resize-handle--nw {\n\ttop: -5px;\n\tleft: -5px;\n\tcursor: nwse-resize;\n}\n\n.notectl-image__resize-handle--ne {\n\ttop: -5px;\n\tright: -5px;\n\tcursor: nesw-resize;\n}\n\n.notectl-image__resize-handle--sw {\n\tbottom: -5px;\n\tleft: -5px;\n\tcursor: nesw-resize;\n}\n\n.notectl-image__resize-handle--se {\n\tbottom: -5px;\n\tright: -5px;\n\tcursor: nwse-resize;\n}\n\n/* Size indicator tooltip */\n.notectl-image__size-indicator {\n\tposition: absolute;\n\tbottom: -28px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tpadding: 2px 8px;\n\tbackground: var(--notectl-tooltip-bg);\n\tcolor: var(--notectl-tooltip-fg);\n\tfont-size: 11px;\n\tfont-weight: 500;\n\tborder-radius: 4px;\n\twhite-space: nowrap;\n\tpointer-events: none;\n\topacity: 0;\n\ttransition: opacity 0.15s;\n\tz-index: 3;\n}\n\n.notectl-image__size-indicator--visible {\n\topacity: 1;\n}\n\n/* Resizing feedback */\n.notectl-image--resizing .notectl-image__img {\n\topacity: 0.85;\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/* Color Picker Popup */\n.notectl-color-picker {\n\tpadding: 8px;\n\tmin-width: 240px;\n}\n\n.notectl-color-picker__default {\n\tdisplay: block;\n\twidth: 100%;\n\tpadding: 6px 12px;\n\tmargin-bottom: 8px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n\tcursor: pointer;\n\tfont-size: 13px;\n\tcolor: var(--notectl-fg);\n\ttext-align: center;\n}\n\n.notectl-color-picker__default:hover {\n\tbackground: var(--notectl-hover-bg);\n}\n\n.notectl-color-picker__grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(10, 1fr);\n\tgap: 3px;\n}\n\n.notectl-color-picker__swatch {\n\twidth: 22px;\n\theight: 22px;\n\tborder: 1px solid transparent;\n\tborder-radius: 3px;\n\tpadding: 0;\n\tcursor: pointer;\n\ttransition: transform 0.1s;\n}\n\n.notectl-color-picker__swatch:hover,\n.notectl-color-picker__swatch:focus-visible {\n\ttransform: scale(1.25);\n\tz-index: 1;\n}\n\n.notectl-color-picker__swatch:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: 1px;\n}\n\n.notectl-color-picker__swatch--active {\n\tborder: 2px solid var(--notectl-primary-fg);\n\tborder-radius: 3px;\n}\n\n.notectl-toolbar-btn--textColor .notectl-toolbar-btn__color-indicator {\n\tdisplay: block;\n\twidth: 16px;\n\theight: 3px;\n\tmargin-top: 1px;\n\tborder-radius: 1px;\n}\n\n/* Font Select — Combobox-style toolbar button */\n.notectl-toolbar-btn--font {\n\twidth: auto;\n\tmin-width: 100px;\n\tmax-width: 160px;\n\tpadding: 0 8px;\n\tgap: 4px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n}\n\n.notectl-toolbar-btn--font:hover {\n\tbackground: var(--notectl-hover-bg);\n\tborder-color: var(--notectl-fg-muted);\n}\n\n.notectl-toolbar-btn--font.notectl-toolbar-btn--active {\n\tbackground: var(--notectl-bg);\n\tborder-color: var(--notectl-primary-muted);\n}\n\n.notectl-toolbar-btn--font .notectl-toolbar-btn__icon {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\twidth: 100%;\n\toverflow: hidden;\n}\n\n.notectl-toolbar-btn--font .notectl-toolbar-btn__icon svg {\n\tdisplay: none;\n}\n\n.notectl-font-select__label {\n\tflex: 1;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcolor: var(--notectl-fg);\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\ttext-align: left;\n\tline-height: 30px;\n}\n\n.notectl-font-select__arrow {\n\tflex-shrink: 0;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n\tline-height: 30px;\n}\n\n/* Font Picker Popup */\n.notectl-font-picker {\n\tmin-width: 200px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.notectl-font-picker__list {\n\tpadding: 4px 0;\n}\n\n.notectl-font-picker__item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\twidth: 100%;\n\tpadding: 7px 12px;\n\tborder: none;\n\tbackground: none;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tcolor: var(--notectl-fg);\n\tline-height: 1.4;\n\ttext-align: left;\n\twhite-space: nowrap;\n\tfont-family: inherit;\n\ttransition: background 0.1s;\n}\n\n.notectl-font-picker__item:hover {\n\tbackground: var(--notectl-hover-bg);\n}\n\n.notectl-font-picker__item--active {\n\tbackground: var(--notectl-active-bg);\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-font-picker__item--active:hover {\n\tbackground: var(--notectl-active-bg);\n}\n\n.notectl-font-picker__check {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\tflex-shrink: 0;\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-font-picker__label {\n\tflex: 1;\n}\n\n.notectl-font-picker__separator {\n\theight: 1px;\n\tbackground: var(--notectl-border);\n\tmargin: 4px 8px;\n}\n\n/* Heading Select — Combobox-style toolbar button */\n.notectl-toolbar-btn--heading {\n\twidth: auto;\n\tmin-width: 100px;\n\tmax-width: 160px;\n\tpadding: 0 8px;\n\tgap: 4px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n}\n\n.notectl-toolbar-btn--heading:hover {\n\tbackground: var(--notectl-hover-bg);\n\tborder-color: var(--notectl-fg-muted);\n}\n\n.notectl-toolbar-btn--heading.notectl-toolbar-btn--active {\n\tbackground: var(--notectl-bg);\n\tborder-color: var(--notectl-primary-muted);\n}\n\n.notectl-toolbar-btn--heading .notectl-toolbar-btn__icon {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\twidth: 100%;\n\toverflow: hidden;\n}\n\n.notectl-toolbar-btn--heading .notectl-toolbar-btn__icon svg {\n\tdisplay: none;\n}\n\n.notectl-heading-select__label {\n\tflex: 1;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcolor: var(--notectl-fg);\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\ttext-align: left;\n\tline-height: 30px;\n}\n\n.notectl-heading-select__arrow {\n\tflex-shrink: 0;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n\tline-height: 30px;\n}\n\n/* Heading Picker Popup */\n.notectl-heading-picker {\n\tmin-width: 200px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.notectl-heading-picker__list {\n\tpadding: 4px 0;\n}\n\n.notectl-heading-picker__item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\twidth: 100%;\n\tpadding: 7px 12px;\n\tborder: none;\n\tbackground: none;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tcolor: var(--notectl-fg);\n\ttext-align: left;\n\twhite-space: nowrap;\n\tfont-family: inherit;\n\ttransition: background 0.1s;\n}\n\n.notectl-heading-picker__item:hover {\n\tbackground: var(--notectl-hover-bg);\n}\n\n.notectl-heading-picker__item--active {\n\tbackground: var(--notectl-active-bg);\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-heading-picker__item--active:hover {\n\tbackground: var(--notectl-active-bg);\n}\n\n.notectl-heading-picker__check {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\tflex-shrink: 0;\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-heading-picker__label {\n\tflex: 1;\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/* Table */\n.notectl-table-wrapper {\n\tmargin: 8px 0;\n\toverflow-x: auto;\n\tposition: relative;\n}\n\n.notectl-table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n\ttable-layout: fixed;\n}\n\n.notectl-table td {\n\tborder: 1px solid var(--notectl-border);\n\tpadding: 8px 12px;\n\tmin-width: 60px;\n\tvertical-align: top;\n\tmin-height: 1.6em;\n}\n\n.notectl-table td:focus-within {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: -2px;\n}\n\n.notectl-table-cell--selected {\n\tbackground: var(--notectl-primary-muted);\n}\n\n/* Table Context Menu */\n.notectl-table-context-menu {\n\tposition: fixed;\n\tbackground: var(--notectl-surface-overlay);\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\tbox-shadow: 0 4px 12px var(--notectl-shadow);\n\tpadding: 4px 0;\n\tmin-width: 180px;\n\tz-index: 10000;\n}\n\n.notectl-table-context-menu button {\n\tdisplay: block;\n\twidth: 100%;\n\tpadding: 8px 12px;\n\ttext-align: left;\n\tborder: none;\n\tbackground: none;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tcolor: var(--notectl-fg);\n\tfont-family: inherit;\n}\n\n.notectl-table-context-menu button:hover {\n\tbackground: var(--notectl-hover-bg);\n}\n\n.notectl-table-context-menu hr {\n\tborder: none;\n\tborder-top: 1px solid var(--notectl-border);\n\tmargin: 4px 0;\n}\n\n/* === Table Controls === */\n\n/* Outer container for table + controls */\n.ntbl-container {\n\tposition: relative;\n\tmargin: 8px 0;\n\tpadding: 24px 0 0 24px;\n}\n\n.ntbl-container .notectl-table-wrapper {\n\tmargin: 0;\n}\n\n.ntbl-container.notectl-table--selected .notectl-table-wrapper {\n\toutline: 2px solid var(--notectl-primary-fg);\n\toutline-offset: 2px;\n\tborder-radius: 6px;\n}\n\n/* --- Column Handle Bar --- */\n.ntbl-col-bar {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 24px;\n\theight: 20px;\n\tdisplay: flex;\n\topacity: 0;\n\ttransition: opacity 0.2s ease;\n\tz-index: 3;\n\tpointer-events: none;\n}\n\n.ntbl-container:hover .ntbl-col-bar,\n.ntbl-container:focus-within .ntbl-col-bar {\n\topacity: 1;\n\tpointer-events: auto;\n}\n\n.ntbl-container.notectl-table--selected .ntbl-col-bar {\n\topacity: 1;\n\tpointer-events: auto;\n}\n\n/* --- Row Handle Bar --- */\n.ntbl-row-bar {\n\tposition: absolute;\n\ttop: 24px;\n\tleft: 0;\n\twidth: 20px;\n\tdisplay: flex;\n\tflex-direction: column;\n\topacity: 0;\n\ttransition: opacity 0.2s ease;\n\tz-index: 3;\n\tpointer-events: none;\n}\n\n.ntbl-container:hover .ntbl-row-bar,\n.ntbl-container:focus-within .ntbl-row-bar {\n\topacity: 1;\n\tpointer-events: auto;\n}\n\n.ntbl-container.notectl-table--selected .ntbl-row-bar {\n\topacity: 1;\n\tpointer-events: auto;\n}\n\n/* --- Handle (shared base) --- */\n.ntbl-handle {\n\tposition: absolute;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tcursor: pointer;\n\ttransition: background 0.15s ease;\n\tborder-radius: 3px;\n}\n\n.ntbl-col-handle {\n\theight: 100%;\n\tbackground: var(--notectl-hover-bg);\n\tborder-radius: 4px 4px 0 0;\n}\n\n.ntbl-col-handle:hover {\n\tbackground: var(--notectl-border);\n}\n\n.ntbl-row-handle {\n\twidth: 100%;\n\tbackground: var(--notectl-hover-bg);\n\tborder-radius: 4px 0 0 4px;\n}\n\n.ntbl-row-handle:hover {\n\tbackground: var(--notectl-border);\n}\n\n/* --- Handle Delete Button --- */\n.ntbl-handle-delete {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tborder: none;\n\tbackground: transparent;\n\tcolor: var(--notectl-fg-muted);\n\tcursor: pointer;\n\tborder-radius: 3px;\n\tpadding: 0;\n\topacity: 0;\n\ttransform: scale(0.7);\n\ttransition: opacity 0.15s, transform 0.15s,\n\t\tbackground 0.15s, color 0.15s;\n}\n\n.ntbl-handle:hover .ntbl-handle-delete,\n.ntbl-handle:focus-within .ntbl-handle-delete {\n\topacity: 1;\n\ttransform: scale(1);\n}\n\n.ntbl-handle-delete:hover,\n.ntbl-handle-delete:focus-visible {\n\tbackground: var(--notectl-danger-muted);\n\tcolor: var(--notectl-danger);\n}\n\n.ntbl-handle-delete:focus-visible {\n\toutline: none;\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n}\n\n/* --- Insert Lines --- */\n.ntbl-insert-line {\n\tposition: absolute;\n\tpointer-events: none;\n\topacity: 0;\n\ttransition: opacity 0.15s ease;\n\tz-index: 6;\n}\n\n.ntbl-insert-line--visible {\n\topacity: 1;\n\tpointer-events: auto;\n}\n\n.ntbl-insert-line--horizontal {\n\theight: 2px;\n\tbackground: linear-gradient(\n\t\t90deg,\n\t\ttransparent,\n\t\tvar(--notectl-primary) 8%,\n\t\tvar(--notectl-primary) 92%,\n\t\ttransparent\n\t);\n\tbox-shadow: 0 0 6px var(--notectl-focus-ring);\n}\n\n.ntbl-insert-line--vertical {\n\twidth: 2px;\n\tbackground: linear-gradient(\n\t\t180deg,\n\t\ttransparent,\n\t\tvar(--notectl-primary) 8%,\n\t\tvar(--notectl-primary) 92%,\n\t\ttransparent\n\t);\n\tbox-shadow: 0 0 6px var(--notectl-focus-ring);\n}\n\n/* --- Insert Button on Line --- */\n.ntbl-insert-btn {\n\tposition: absolute;\n\twidth: 20px;\n\theight: 20px;\n\tborder-radius: 50%;\n\tbackground: var(--notectl-bg);\n\tborder: 2px solid var(--notectl-primary);\n\tcolor: var(--notectl-primary);\n\tcursor: pointer;\n\tpointer-events: all;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 0;\n\tbox-shadow: 0 2px 8px var(--notectl-focus-ring);\n\ttransition: background 0.15s, color 0.15s,\n\t\ttransform 0.15s, box-shadow 0.15s;\n}\n\n.ntbl-insert-line--horizontal .ntbl-insert-btn {\n\tleft: 50%;\n\ttop: -9px;\n\ttransform: translateX(-50%);\n}\n\n.ntbl-insert-line--vertical .ntbl-insert-btn {\n\ttop: 50%;\n\tleft: -9px;\n\ttransform: translateY(-50%);\n}\n\n.ntbl-insert-btn:hover,\n.ntbl-insert-btn:focus-visible {\n\tbackground: var(--notectl-primary);\n\tcolor: var(--notectl-bg);\n\tbox-shadow: 0 2px 12px var(--notectl-focus-ring);\n}\n\n.ntbl-insert-btn:focus-visible {\n\toutline: none;\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n}\n\n.ntbl-insert-line--horizontal .ntbl-insert-btn:hover {\n\ttransform: translateX(-50%) scale(1.2);\n}\n\n.ntbl-insert-line--vertical .ntbl-insert-btn:hover {\n\ttransform: translateY(-50%) scale(1.2);\n}\n\n/* --- Add Row / Add Column Zones --- */\n.ntbl-add-zone {\n\tposition: absolute;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tcursor: pointer;\n\tuser-select: none;\n\topacity: 0;\n\ttransition: opacity 0.2s ease, background 0.2s ease,\n\t\tborder-color 0.2s ease;\n}\n\n.ntbl-container:hover .ntbl-add-zone,\n.ntbl-container:focus-within .ntbl-add-zone {\n\topacity: 1;\n}\n\n.ntbl-container.notectl-table--selected .ntbl-add-zone {\n\topacity: 1;\n}\n\n.ntbl-delete-table-btn {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 20px;\n\theight: 20px;\n\tborder: 1px solid var(--notectl-danger);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n\tcolor: var(--notectl-danger);\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\topacity: 0;\n\ttransition: opacity 0.2s ease, background 0.15s, border-color 0.15s;\n\tz-index: 7;\n}\n\n.ntbl-container:hover .ntbl-delete-table-btn,\n.ntbl-container:focus-within .ntbl-delete-table-btn,\n.ntbl-container.notectl-table--selected .ntbl-delete-table-btn {\n\topacity: 1;\n}\n\n.ntbl-delete-table-btn:hover,\n.ntbl-delete-table-btn:focus-visible {\n\tbackground: var(--notectl-danger-muted);\n\tborder-color: var(--notectl-danger);\n}\n\n.ntbl-delete-table-btn:focus-visible {\n\toutline: none;\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n}\n\n.ntbl-add-row {\n\tbottom: 0;\n\theight: 24px;\n\tborder: 1px dashed var(--notectl-border);\n\tborder-radius: 0 0 6px 6px;\n\tborder-top: none;\n\tcolor: var(--notectl-fg-muted);\n\ttransform: translateY(100%);\n}\n\n.ntbl-add-row:hover,\n.ntbl-add-row:focus-visible {\n\tbackground: var(--notectl-primary-muted);\n\tborder-color: var(--notectl-primary);\n\tcolor: var(--notectl-primary);\n}\n\n.ntbl-add-row:focus-visible {\n\toutline: none;\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n}\n\n.ntbl-add-col {\n\tright: 0;\n\ttop: 24px;\n\twidth: 24px;\n\tborder: 1px dashed var(--notectl-border);\n\tborder-radius: 0 6px 6px 0;\n\tborder-left: none;\n\tcolor: var(--notectl-fg-muted);\n\ttransform: translateX(100%);\n}\n\n.ntbl-add-col:hover,\n.ntbl-add-col:focus-visible {\n\tbackground: var(--notectl-primary-muted);\n\tborder-color: var(--notectl-primary);\n\tcolor: var(--notectl-primary);\n}\n\n.ntbl-add-col:focus-visible {\n\toutline: none;\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n}\n\n.ntbl-add-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\ttransition: transform 0.2s ease;\n}\n\n.ntbl-add-zone:hover .ntbl-add-icon {\n\ttransform: scale(1.15);\n}\n\n/* Font Size Select — Combobox-style toolbar button */\n.notectl-toolbar-btn--fontSize {\n\twidth: auto;\n\tmin-width: 60px;\n\tmax-width: 80px;\n\tpadding: 0 8px;\n\tgap: 4px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-bg);\n}\n\n.notectl-toolbar-btn--fontSize:hover {\n\tbackground: var(--notectl-hover-bg);\n\tborder-color: var(--notectl-fg-muted);\n}\n\n.notectl-toolbar-btn--fontSize.notectl-toolbar-btn--active {\n\tbackground: var(--notectl-bg);\n\tborder-color: var(--notectl-primary-muted);\n}\n\n.notectl-toolbar-btn--fontSize .notectl-toolbar-btn__icon {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\twidth: 100%;\n\toverflow: hidden;\n}\n\n.notectl-toolbar-btn--fontSize .notectl-toolbar-btn__icon svg {\n\tdisplay: none;\n}\n\n.notectl-font-size-select__label {\n\tflex: 1;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcolor: var(--notectl-fg);\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\ttext-align: left;\n\tline-height: 30px;\n}\n\n.notectl-font-size-select__arrow {\n\tflex-shrink: 0;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n\tline-height: 30px;\n}\n\n/* Font Size Picker Popup */\n.notectl-font-size-picker {\n\tmin-width: 140px;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.notectl-font-size-picker__input-wrapper {\n\tpadding: 8px 8px 4px;\n}\n\n.notectl-font-size-picker__input {\n\twidth: 100%;\n\tpadding: 6px 8px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tfont-size: 13px;\n\tfont-family: inherit;\n\tcolor: var(--notectl-fg);\n\tbackground: var(--notectl-bg);\n\toutline: none;\n\tbox-sizing: border-box;\n\t-moz-appearance: textfield;\n}\n\n.notectl-font-size-picker__input::-webkit-inner-spin-button,\n.notectl-font-size-picker__input::-webkit-outer-spin-button {\n\t-webkit-appearance: none;\n\tmargin: 0;\n}\n\n.notectl-font-size-picker__input:focus {\n\tborder-color: var(--notectl-border-focus);\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n}\n\n.notectl-font-size-picker__list {\n\tmax-height: 280px;\n\toverflow-y: auto;\n\tpadding: 4px 0;\n}\n\n.notectl-font-size-picker__item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\twidth: 100%;\n\tpadding: 7px 12px;\n\tborder: none;\n\tbackground: none;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tcolor: var(--notectl-fg);\n\tline-height: 1.4;\n\ttext-align: left;\n\twhite-space: nowrap;\n\tfont-family: inherit;\n\ttransition: background 0.1s;\n\toutline: none;\n}\n\n.notectl-font-size-picker__item:hover {\n\tbackground: var(--notectl-hover-bg);\n}\n\n.notectl-font-size-picker__item--active {\n\tbackground: var(--notectl-active-bg);\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-font-size-picker__item--active:hover {\n\tbackground: var(--notectl-active-bg);\n}\n\n.notectl-font-size-picker__item--focused {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: -2px;\n}\n\n.notectl-font-size-picker__check {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\tflex-shrink: 0;\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-font-size-picker__label {\n\tflex: 1;\n}\n\n/* Code Block — uses theme custom properties */\n.notectl-code-block {\n\tposition: relative;\n\tmargin: 8px 0;\n\tborder-radius: 6px;\n\tbackground: var(--notectl-code-block-bg);\n\tcolor: var(--notectl-code-block-color);\n\tfont-family: 'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, Consolas, monospace;\n\tfont-size: 14px;\n\tline-height: 1.5;\n\toverflow: hidden;\n}\n\n.notectl-code-block__header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 6px 12px;\n\tbackground: var(--notectl-code-block-header-bg);\n\tborder-bottom: 1px solid var(--notectl-code-block-header-border);\n\tfont-size: 12px;\n\tcolor: var(--notectl-code-block-header-color);\n\tuser-select: none;\n}\n\n.notectl-code-block__language {\n\tfont-weight: 500;\n\tletter-spacing: 0.02em;\n}\n\n.notectl-code-block__copy {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 24px;\n\theight: 24px;\n\tborder: none;\n\tborder-radius: 4px;\n\tbackground: transparent;\n\tcolor: var(--notectl-code-block-header-color);\n\tcursor: pointer;\n\tpadding: 0;\n\ttransition: background 0.15s, color 0.15s;\n}\n\n.notectl-code-block__copy:hover {\n\tbackground: rgba(128, 128, 128, 0.15);\n\tcolor: var(--notectl-code-block-color);\n}\n\n.notectl-code-block__copy svg {\n\tfill: currentColor;\n}\n\n.notectl-code-block__content {\n\tdisplay: block;\n\tpadding: 12px 16px;\n\twhite-space: pre-wrap;\n\tword-wrap: break-word;\n\ttab-size: 4;\n\t-moz-tab-size: 4;\n\toutline: none;\n\tmin-height: 1.5em;\n}\n\n.notectl-code-block--selected {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n}\n\n.notectl-code-block__esc-hint {\n\tdisplay: none;\n\tposition: absolute;\n\tbottom: 4px;\n\tright: 8px;\n\tfont-size: 11px;\n\tcolor: var(--notectl-code-block-header-color);\n\topacity: 0.5;\n\tpointer-events: none;\n\tuser-select: none;\n\tfont-family: system-ui, sans-serif;\n}\n\n.notectl-code-block--focused .notectl-code-block__esc-hint {\n\tdisplay: block;\n}\n\n/* Node selection */\n.notectl-node-selected {\n\toutline: 2px solid var(--notectl-primary);\n\toutline-offset: 2px;\n}\n\n/* Reduced motion preference (WCAG 2.3.3) */\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\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","/**\n * NotectlEditor Web Component — the public-facing editor element.\n */\n\nimport DOMPurify from 'dompurify';\nimport { isMarkActive, selectAll } from '../commands/Commands.js';\nimport { DecorationSet } from '../decorations/Decoration.js';\nimport { isNodeOfType } from '../model/AttrRegistry.js';\nimport { registerBuiltinSpecs } from '../model/BuiltinSpecs.js';\nimport {\n\ttype BlockNode,\n\ttype Document,\n\ttype InlineNode,\n\ttype Mark,\n\ttype TextNode,\n\tcreateBlockNode,\n\tcreateDocument,\n\tcreateTextNode,\n\tgetBlockText,\n\tgetInlineChildren,\n\tisInlineNode,\n} from '../model/Document.js';\nimport { escapeHTML } from '../model/HTMLUtils.js';\nimport type { ParseRule } from '../model/ParseRule.js';\nimport { schemaFromRegistry } from '../model/Schema.js';\nimport { isMarkAllowed } from '../model/Schema.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { createCollapsedSelection, selectionsEqual } from '../model/Selection.js';\nimport { blockId, nodeType, markType as toMarkType } from '../model/TypeBrands.js';\nimport type { Plugin, PluginConfig } from '../plugins/Plugin.js';\nimport { PluginManager } from '../plugins/PluginManager.js';\nimport { TextFormattingPlugin } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport type { TextFormattingConfig } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport { ToolbarPlugin } from '../plugins/toolbar/ToolbarPlugin.js';\nimport type { ToolbarLayoutConfig } from '../plugins/toolbar/ToolbarPlugin.js';\nimport { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { EditorView } from '../view/EditorView.js';\nimport { getEditorStyleSheet } from './styles.js';\nimport { generateThemeCSS } from './theme/ThemeEngine.js';\nimport { type Theme, ThemePreset, resolveTheme } from './theme/ThemeTokens.js';\n\n// --- Config Types ---\n\nexport interface NotectlEditorConfig {\n\t/** Controls which inline marks are enabled. Used to auto-configure TextFormattingPlugin. */\n\tfeatures?: Partial<TextFormattingConfig>;\n\tplugins?: Plugin[];\n\t/**\n\t * Declarative toolbar layout. Each inner array is a visual group;\n\t * separators are rendered between groups. Order = array order.\n\t * When set, a ToolbarPlugin is created internally — do not add one to `plugins`.\n\t */\n\ttoolbar?: ReadonlyArray<ReadonlyArray<Plugin>>;\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}\n\n// --- Event Types ---\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\n// --- Web Component ---\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 themeStyleSheet: CSSStyleSheet | null = null;\n\tprivate systemThemeQuery: MediaQueryList | null = null;\n\tprivate systemThemeHandler: ((e: MediaQueryListEvent) => void) | 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'];\n\t}\n\n\tconnectedCallback(): void {\n\t\tif (this.initialized) return;\n\t\tthis.init();\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tthis.destroy();\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}\n\t\tif (name === 'theme' && this.initialized) {\n\t\t\tthis.applyTheme((newValue as ThemePreset) ?? ThemePreset.Light);\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.applyTheme(this.config.theme ?? ThemePreset.Light);\n\n\t\t// 1. Build DOM structure\n\t\tthis.editorWrapper = document.createElement('div');\n\t\tthis.editorWrapper.className = 'notectl-editor';\n\n\t\tthis.topPluginContainer = document.createElement('div');\n\t\tthis.topPluginContainer.className = 'notectl-plugin-container--top';\n\n\t\tthis.contentElement = document.createElement('div');\n\t\tthis.contentElement.className = 'notectl-content';\n\t\tthis.contentElement.contentEditable = this.config.readonly ? 'false' : 'true';\n\t\tthis.contentElement.setAttribute('role', 'textbox');\n\t\tthis.contentElement.setAttribute('aria-multiline', 'true');\n\t\tthis.contentElement.setAttribute('aria-label', 'Rich text editor');\n\t\tif (this.config.readonly) {\n\t\t\tthis.contentElement.setAttribute('aria-readonly', 'true');\n\t\t}\n\t\tthis.contentElement.setAttribute('aria-description', 'Press Escape to exit the editor');\n\t\tthis.contentElement.setAttribute(\n\t\t\t'data-placeholder',\n\t\t\tthis.config.placeholder ?? 'Start typing...',\n\t\t);\n\n\t\tthis.bottomPluginContainer = document.createElement('div');\n\t\tthis.bottomPluginContainer.className = 'notectl-plugin-container--bottom';\n\n\t\t// Screen reader announcer\n\t\tthis.announcer = document.createElement('div');\n\t\tthis.announcer.className = 'notectl-sr-only';\n\t\tthis.announcer.setAttribute('aria-live', 'polite');\n\t\tthis.announcer.setAttribute('aria-atomic', 'true');\n\n\t\tthis.editorWrapper.appendChild(this.topPluginContainer);\n\t\tthis.editorWrapper.appendChild(this.contentElement);\n\t\tthis.editorWrapper.appendChild(this.bottomPluginContainer);\n\t\tthis.editorWrapper.appendChild(this.announcer);\n\n\t\tshadow.appendChild(this.editorWrapper);\n\n\t\t// 2. Create PluginManager (SchemaRegistry is available)\n\t\tthis.pluginManager = new PluginManager();\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 TextFormattingPlugin if none was explicitly provided\n\t\tthis.ensureTextFormattingPlugin();\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\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\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});\n\t\t\t\tthis.updateEmptyState();\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// --- 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\tgetHTML(): string {\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\t\tconst parts: string[] = [];\n\t\tlet currentListTag: string | null = null;\n\n\t\tfor (const block of doc.children) {\n\t\t\tif (isNodeOfType(block, 'list_item')) {\n\t\t\t\tconst listType = block.attrs.listType;\n\t\t\t\tconst tag = listType === 'ordered' ? 'ol' : 'ul';\n\n\t\t\t\tif (currentListTag !== tag) {\n\t\t\t\t\tif (currentListTag) parts.push(`</${currentListTag}>`);\n\t\t\t\t\tparts.push(`<${tag}>`);\n\t\t\t\t\tcurrentListTag = tag;\n\t\t\t\t}\n\n\t\t\t\tparts.push(this.serializeBlock(block, registry));\n\t\t\t} else {\n\t\t\t\tif (currentListTag) {\n\t\t\t\t\tparts.push(`</${currentListTag}>`);\n\t\t\t\t\tcurrentListTag = null;\n\t\t\t\t}\n\t\t\t\tparts.push(this.serializeBlock(block, registry));\n\t\t\t}\n\t\t}\n\n\t\tif (currentListTag) parts.push(`</${currentListTag}>`);\n\n\t\tconst allowedTags: string[] = registry ? registry.getAllowedTags() : ['p', 'br', 'div', 'span'];\n\t\tconst allowedAttrs: string[] = registry ? registry.getAllowedAttrs() : ['style'];\n\n\t\treturn DOMPurify.sanitize(parts.join(''), {\n\t\t\tALLOWED_TAGS: allowedTags,\n\t\t\tALLOWED_ATTR: allowedAttrs,\n\t\t});\n\t}\n\n\t/** Sets content from HTML (sanitized). */\n\tsetHTML(html: string): void {\n\t\tconst registry = this.pluginManager?.schemaRegistry;\n\t\tconst allowedTags: string[] = registry ? registry.getAllowedTags() : ['p', 'br', 'div', 'span'];\n\t\tconst allowedAttrs: string[] = registry ? registry.getAllowedAttrs() : ['style'];\n\n\t\tconst sanitized = DOMPurify.sanitize(html, {\n\t\t\tALLOWED_TAGS: allowedTags,\n\t\t\tALLOWED_ATTR: allowedAttrs,\n\t\t});\n\n\t\tconst doc = this.parseHTMLToDocument(sanitized);\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: () => this.view?.undo(),\n\t\tredo: () => this.view?.redo(),\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} {\n\t\tconst schema = this.view?.getState().schema;\n\t\treturn {\n\t\t\ttoggleBold: () => (schema ? isMarkAllowed(schema, 'bold') : false),\n\t\t\ttoggleItalic: () => (schema ? isMarkAllowed(schema, 'italic') : false),\n\t\t\ttoggleUnderline: () => (schema ? isMarkAllowed(schema, 'underline') : false),\n\t\t\tundo: () => this.view?.history.canUndo() ?? false,\n\t\t\tredo: () => this.view?.history.canRedo() ?? false,\n\t\t};\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// --- 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\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}\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.applyTheme(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/** Cleans up the editor. Awaiting ensures async plugin teardown completes. */\n\tdestroy(): Promise<void> {\n\t\tthis.cleanupSystemThemeListener();\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\treturn pluginTeardown;\n\t}\n\n\t// --- Private ---\n\n\t/** Applies a theme. Called during init() and on runtime changes. */\n\tprivate applyTheme(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\tprivate setThemeStyleSheet(theme: Theme): void {\n\t\tif (!this.themeStyleSheet) {\n\t\t\tthis.themeStyleSheet = new CSSStyleSheet();\n\t\t}\n\t\tthis.themeStyleSheet.replaceSync(generateThemeCSS(theme));\n\n\t\tconst shadow: ShadowRoot | null = this.shadowRoot;\n\t\tif (shadow) {\n\t\t\tshadow.adoptedStyleSheets = [this.themeStyleSheet, getEditorStyleSheet()];\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\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 */\n\tprivate processToolbarConfig(): void {\n\t\tif (!this.pluginManager || !this.config.toolbar) return;\n\n\t\tconst groups: string[][] = [];\n\t\tfor (const group of this.config.toolbar) {\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 };\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\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\tthis.announceStateChange(oldState, newState, tr);\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 announceStateChange(oldState: EditorState, newState: EditorState, tr: Transaction): void {\n\t\tif (!this.announcer) return;\n\n\t\t// Priority 1: Undo/Redo\n\t\tif (tr.metadata.historyDirection === 'undo') {\n\t\t\tthis.announcer.textContent = 'Undo';\n\t\t\treturn;\n\t\t}\n\t\tif (tr.metadata.historyDirection === 'redo') {\n\t\t\tthis.announcer.textContent = 'Redo';\n\t\t\treturn;\n\t\t}\n\n\t\t// Priority 2: Block type changes\n\t\tfor (const step of tr.steps) {\n\t\t\tif (step.type === 'setBlockType') {\n\t\t\t\tconst label = getBlockTypeLabel(step.nodeType, step.attrs);\n\t\t\t\tthis.announcer.textContent = label;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Priority 3: Mark changes\n\t\tconst markTypes = newState.schema.markTypes;\n\t\tfor (const mt of markTypes) {\n\t\t\tconst branded = toMarkType(mt);\n\t\t\tconst wasActive = isMarkActive(oldState, branded);\n\t\t\tconst nowActive = isMarkActive(newState, branded);\n\t\t\tif (wasActive !== nowActive) {\n\t\t\t\tthis.announcer.textContent = `${mt} ${nowActive ? 'on' : 'off'}`;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\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\t// --- Spec-based HTML Serialization ---\n\n\tprivate serializeBlock(block: BlockNode, registry?: SchemaRegistry): string {\n\t\tconst inlineContent: string = this.serializeInlineContent(block, registry);\n\t\tconst spec = registry?.getNodeSpec(block.type);\n\n\t\tlet html: string;\n\t\tif (spec?.toHTML) {\n\t\t\thtml = spec.toHTML(block, inlineContent);\n\t\t} else {\n\t\t\thtml = `<p>${inlineContent || '<br>'}</p>`;\n\t\t}\n\n\t\t// Inject align style into the first opening tag\n\t\tconst align: string | undefined = (block.attrs as Record<string, unknown>)?.align as\n\t\t\t| string\n\t\t\t| undefined;\n\t\tif (align && align !== 'left') {\n\t\t\thtml = html.replace(/>/, ` style=\"text-align: ${align}\">`);\n\t\t}\n\n\t\treturn html;\n\t}\n\n\tprivate serializeInlineContent(block: BlockNode, registry?: SchemaRegistry): string {\n\t\tconst children: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\t\tconst parts: string[] = [];\n\n\t\tfor (const child of children) {\n\t\t\tif (isInlineNode(child)) {\n\t\t\t\tconst inlineSpec = registry?.getInlineNodeSpec(child.inlineType);\n\t\t\t\tif (inlineSpec?.toHTMLString) {\n\t\t\t\t\tparts.push(inlineSpec.toHTMLString(child));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tparts.push(this.serializeTextNode(child, registry));\n\t\t\t}\n\t\t}\n\n\t\treturn parts.join('');\n\t}\n\n\tprivate serializeTextNode(node: TextNode, registry?: SchemaRegistry): string {\n\t\tif (node.text === '') return '';\n\n\t\tlet html: string = escapeHTML(node.text);\n\n\t\t// Sort marks by MarkSpec.rank from the schema registry (lower = closer to text)\n\t\tconst markOrder: Map<string, number> = this.getMarkOrder();\n\t\tconst sortedMarks: Mark[] = [...node.marks].sort(\n\t\t\t(a, b) => (markOrder.get(a.type) ?? 99) - (markOrder.get(b.type) ?? 99),\n\t\t);\n\n\t\tfor (const mark of sortedMarks) {\n\t\t\tconst markSpec = registry?.getMarkSpec(mark.type);\n\t\t\tif (markSpec?.toHTMLString) {\n\t\t\t\thtml = markSpec.toHTMLString(mark, html);\n\t\t\t}\n\t\t}\n\n\t\treturn html;\n\t}\n\n\tprivate getMarkOrder(): Map<string, number> {\n\t\tconst registry = this.pluginManager?.schemaRegistry;\n\t\tif (!registry) return new Map();\n\t\tconst types = registry.getMarkTypes();\n\t\tconst order = new Map<string, number>();\n\t\tfor (const t of types) {\n\t\t\tconst spec = registry.getMarkSpec(t);\n\t\t\tif (spec) order.set(t, spec.rank ?? 99);\n\t\t}\n\t\treturn order;\n\t}\n\n\t// --- Spec-based HTML Parsing ---\n\n\tprivate parseHTMLToDocument(html: string): Document {\n\t\tconst registry = this.pluginManager?.schemaRegistry;\n\t\tconst allowedTags: string[] = registry ? registry.getAllowedTags() : ['p', 'br', 'div', 'span'];\n\t\tconst allowedAttrs: string[] = registry ? registry.getAllowedAttrs() : ['style'];\n\n\t\tconst template = document.createElement('template');\n\t\ttemplate.innerHTML = DOMPurify.sanitize(html, {\n\t\t\tALLOWED_TAGS: allowedTags,\n\t\t\tALLOWED_ATTR: allowedAttrs,\n\t\t});\n\t\tconst root = template.content;\n\n\t\tconst blockRules = registry?.getBlockParseRules() ?? [];\n\t\tconst blocks: BlockNode[] = [];\n\n\t\tfor (const child of Array.from(root.childNodes)) {\n\t\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tconst el = child as HTMLElement;\n\t\t\t\tconst tag = el.tagName.toLowerCase();\n\n\t\t\t\t// Lists need cross-element logic — handle before parse rules\n\t\t\t\tif (tag === 'ul' || tag === 'ol') {\n\t\t\t\t\tconst listType = tag === 'ol' ? 'ordered' : 'bullet';\n\t\t\t\t\tfor (const li of Array.from(el.querySelectorAll('li'))) {\n\t\t\t\t\t\tconst textNodes = this.parseElementToTextNodes(li as HTMLElement, registry);\n\t\t\t\t\t\tblocks.push(\n\t\t\t\t\t\t\tcreateBlockNode(nodeType('list_item'), textNodes, undefined, {\n\t\t\t\t\t\t\t\tlistType,\n\t\t\t\t\t\t\t\tindent: 0,\n\t\t\t\t\t\t\t\tchecked: false,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Try block parse rules\n\t\t\t\tconst match = matchBlockParseRule(el, blockRules);\n\t\t\t\tif (match) {\n\t\t\t\t\tconst textNodes = this.parseElementToTextNodes(el, registry);\n\t\t\t\t\tblocks.push(\n\t\t\t\t\t\tcreateBlockNode(\n\t\t\t\t\t\t\tnodeType(match.type),\n\t\t\t\t\t\t\ttextNodes,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tmatch.attrs as Record<string, string | number | boolean> | undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Fallback to paragraph\n\t\t\t\tconst textNodes = this.parseElementToTextNodes(el, registry);\n\t\t\t\tblocks.push(createBlockNode(nodeType('paragraph'), textNodes));\n\t\t\t} else if (child.nodeType === Node.TEXT_NODE && child.textContent?.trim()) {\n\t\t\t\tblocks.push(\n\t\t\t\t\tcreateBlockNode(nodeType('paragraph'), [createTextNode(child.textContent.trim())]),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (blocks.length === 0) {\n\t\t\treturn createDocument();\n\t\t}\n\n\t\treturn createDocument(blocks);\n\t}\n\n\tprivate parseElementToTextNodes(el: HTMLElement, registry?: SchemaRegistry): TextNode[] {\n\t\tconst result: TextNode[] = [];\n\t\tconst markRules = registry?.getMarkParseRules() ?? [];\n\t\tthis.walkElement(el, [], result, markRules);\n\t\treturn result.length > 0 ? result : [createTextNode('')];\n\t}\n\n\tprivate walkElement(\n\t\tnode: Node,\n\t\tcurrentMarks: Mark[],\n\t\tresult: TextNode[],\n\t\tmarkRules: readonly { readonly rule: ParseRule; readonly type: string }[],\n\t): void {\n\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\tconst text = node.textContent ?? '';\n\t\t\tif (text) {\n\t\t\t\tresult.push(createTextNode(text, [...currentMarks]));\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 = node as HTMLElement;\n\t\tconst tag = el.tagName.toLowerCase();\n\t\tconst marks = [...currentMarks];\n\n\t\t// Try mark parse rules — collect all matching marks for this element\n\t\tconst matchedTypes = new Set<string>();\n\t\tfor (const entry of markRules) {\n\t\t\tif (entry.rule.tag !== tag) continue;\n\t\t\tif (matchedTypes.has(entry.type)) continue;\n\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\tif (!marks.some((m) => m.type === entry.type)) {\n\t\t\t\t\tmarks.push({\n\t\t\t\t\t\ttype: toMarkType(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}\n\t\t\t} else {\n\t\t\t\tif (!marks.some((m) => m.type === entry.type)) {\n\t\t\t\t\tmarks.push({ type: toMarkType(entry.type) });\n\t\t\t\t\tmatchedTypes.add(entry.type);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const child of Array.from(el.childNodes)) {\n\t\t\tthis.walkElement(child, marks, result, markRules);\n\t\t}\n\t}\n}\n\n// --- Helpers ---\n\nconst BLOCK_TYPE_LABELS: Record<string, string> = {\n\tparagraph: 'Paragraph',\n\theading: 'Heading',\n\tcode_block: 'Code Block',\n\tblockquote: 'Block Quote',\n\tlist_item: 'List Item',\n\thorizontal_rule: 'Horizontal Rule',\n\timage: 'Image',\n\ttable: 'Table',\n};\n\n/** Returns a human-readable label for a block type (used in screen reader announcements). */\nfunction getBlockTypeLabel(typeName: string, attrs?: Record<string, unknown>): string {\n\tif (typeName === 'heading' && attrs?.level) {\n\t\treturn `Heading ${attrs.level}`;\n\t}\n\treturn BLOCK_TYPE_LABELS[typeName] ?? typeName;\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// 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"],"names":["getBlockSegmentsInRange","block","from","to","inlineChildren","getInlineChildren","segments","pos","child","childWidth","isInlineNode","childEnd","sliceFrom","sliceTo","text","isTextNode","node","isBlockNode","isLeafBlock","c","getTextChildren","getBlockChildren","generateBlockId","createDocument","children","createBlockNode","type","id","attrs","createTextNode","marks","createInlineNode","inlineType","getBlockText","getBlockLength","len","getBlockMarksAtOffset","offset","end","i","marksEqual","a","b","aAttrs","bAttrs","aKeys","bKeys","key","markSetsEqual","markA","markB","hasMark","markType","m","addMarkToSet","mark","removeMarkFromSet","normalizeTextNodes","nodes","result","prev","normalizeInlineContent","cleaned","next","walkInlineContent","width","getContentAtOffset","localOffset","createNodeSelection","nodeId","path","isNodeSelection","sel","isTextSelection","selectionsEqual","createPosition","blockId","createSelection","anchor","head","createCollapsedSelection","isCollapsed","isForward","blockOrder","anchorIdx","headIdx","selectionRange","defaultSchema","schemaFromRegistry","registry","isMarkAllowed","schema","isNodeTypeAllowed","nodeType","name","pluginId","commandName","isNodeOfType","isMarkOfType","isInlineNodeOfType","inlineNodeType","createBlockElement","tag","el","escapeHTML","SchemaRegistry","__publicField","spec","factory","keymap","existing","idx","rule","item","ids","items","pattern","handler","mimeType","handlers","entry","matchMimePattern","e","results","tags","_a","_b","_c","attr","prefix","resolveNodeByPath","doc","current","childId","resolveParentByPath","index","parentPath","parent","findNodePath","subPath","findNodePathInBlock","walkNodes","callback","walkNodeRecursive","findNode","found","findNodeInBlock","findNodeWithPath","canContain","parentType","childType","parentSpec","childSpec","childGroup","allowed","validateContent","childTypes","min","max","blockChildTypes","t","registerBuiltinSpecs","_node","content","applyStep","step","applyInsertText","applyDeleteText","applySplitBlock","applyMergeBlocks","applyAddMark","applyRemoveMark","applySetBlockType","applyInsertNode","applyRemoveNode","applySetNodeAttr","applyInsertInlineNode","applyRemoveInlineNode","applySetInlineNodeAttr","mapBlock","newChildren","insertSegmentsIntoInlineContent","insertTextIntoInlineContent","replaceInlineChildren","deleteFromInlineContent","blockIndex","nodesBeforeSplit","sliceInlineContent","nodesAfterSplit","updatedBlock","newBlock","splitBlockRecursive","changed","mapped","targetIndex","sourceIndex","target","source","targetInline","sourceInline","mergedChildren","mergedBlock","mergeBlocksRecursive","targetIdx","sourceIdx","applyMarkToInlineContent","insertInlineNodeAtOffset","removeInlineNodeAtOffset","setInlineNodeAttrsAtOffset","fn","mapBlockInChildren","mappedChildren","original","newInlineChildren","blockChildren","inserted","nodeEnd","before","after","seg","deleteFrom","deleteTo","remaining","add","newMarks","overlapStart","overlapEnd","beforeText","insideText","afterText","inlineNode","mapNodeByPath","rootId","mapNodeByPathRecursive","depth","targetId","invertStep","invertTransaction","tr","TransactionBuilder","currentSelection","currentStoredMarks","origin","deletedText","deletedMarks","deletedSegments","newBlockId","targetBlockId","sourceBlockId","targetLengthBefore","targetBlock","removedNode","resolveRemovedNode","selection","previousMarks","EditorState","storedMarks","options","firstBlock","validateSelection","buildBlockMap","buildBlockOrder","parentId","json","validatePosition","length","map","walk","blocks","order","DEFAULT_GROUP_TIMEOUT_MS","DEFAULT_MAX_DEPTH","HistoryManager","now","lastGroup","state","group","currentState","allSteps","inverted","transaction","incoming","lastTr","lastStepType","incomingStepType","defaultFeatures","isVoidBlock","bid","getNodeSpec","deleteNodeSelection","siblings","builder","newId","prevSibling","prevLeafId","findLastLeafBlockId","prevLeaf","prevLen","nextSibling","nextLeafId","findFirstLeafBlockId","firstBlockChild","lastBlockChild","toggleMark","features","isFeatureGated","anchorBlock","currentMarks","range","fromIdx","toIdx","shouldRemove","isMarkActiveInRange","blockLen","isMarkActiveInBlock","toggleBold","toggleItalic","toggleUnderline","insertTextCommand","insertTextAfterNodeSelection","resolveActiveMarks","addDeleteSelectionSteps","insertBlockId","insertOffset","deleteSelectionCommand","deleteBackward","mergeBlockBackward","deleteForward","mergeBlockForward","deleteWordBackward","wordStart","findWordBoundaryBackward","deleteWordForward","wordEnd","findWordBoundaryForward","deleteSoftLineBackward","deleteSoftLineForward","splitBlockCommand","insertParagraphAfterNodeSelection","insertHardBreakCommand","hardBreak","sharesParent","blockIdA","blockIdB","pathA","pathB","isInsideIsolating","ancestorId","ancestor","isIsolatingBlock","blockIdx","prevBlockId","prevBlock","nextBlockId","selectAll","lastBlock","lastBlockLen","isMarkActive","firstLen","midBlockId","midBlock","midLen","insertIdx","navigateArrowIntoVoid","direction","nodeIdx","prevId","nextId","KeyboardHandler","element","descriptor","normalizeKeyDescriptor","keymaps","parts","setRichClipboard","plainText","consumeRichClipboard","BLOCK_MIME","ClipboardHandler","clipboardData","blockData","altText","lines","richBlocks","start","sliced","htmlParts","sorted","specA","specB","html","EventKey","ServiceKey","EventBus","payload","set","listener","err","mapDecorationThroughStep","deco","mapInline","mapWidget","mapNode","mapInlineInsert","mapInlineDelete","mapInlineSplit","mapInlineMerge","removeIfBlockDeleted","mapWidgetInsert","mapWidgetDelete","mapWidgetSplit","mapWidgetMerge","mapNodeMerge","newFrom","newTo","delLen","clampAndShift","left","right","delFrom","delTo","inline","widget","toDOM","_DecorationSet","byBlock","decorations","decos","d","predicate","filtered","other","otherDecos","decorationArraysEqual","r","DecorationSet","ai","bi","decorationsEqual","attrsEqual","bn","bw","DEFAULT_PRIORITY","PluginManager","plugin","context","oldState","newState","finalDispatch","dispatched","currentTr","called","guardedNext","config","reversed","reg","serviceId","unsub","itemId","pluginEventBus","middleware","priority","service","dep","inDegree","dependents","deps","depList","queue","deg","pa","pb","newDeg","missing","findNextEnabled","buttons","findFirstEnabled","findLastEnabled","applyRovingTabindex","focusedIndex","btn","findNextDropdownItem","navigateGrid","row","col","maxRows","maxCols","HIGHLIGHTED_CLASS","renderGridPicker","container","onClose","grid","label","cell","highlightCells","targetRow","targetCol","cells","renderDropdown","executeCommand","iconSpan","labelSpan","createSeparator","sep","ToolbarPopupController","getActiveElement","button","popup","cmd","triggerBtn","rect","root","firstItem","menuItems","itemArr","focused","lastCell","newRow","newCol","active","currentIdx","TOOLTIP_DELAY_MS","_ToolbarTooltip","isPopupActive","ToolbarTooltip","ToolbarServiceKey","ToolbarPlugin","layoutConfig","_oldState","_tr","value","elements","first","last","firstGroup","groupPluginIds","groupItems","pId","groups","list","span","enabled","_d","formatShortcut","binding","DEFAULT_CONFIG","BOLD_ICON","ITALIC_ICON","UNDERLINE_ICON","MARK_DEFINITIONS","TextFormattingPlugin","enabledMarks","def","lastVisibleMark","isSeparatorTarget","separatorAfter","toCommandName","toolbarVisible","_mark","featureEnabled","configKey","HEADING_TAGS","HEADING_LABELS","TITLE_LABEL","SUBTITLE_LABEL","PARAGRAPH_LABEL","_HeadingPlugin","level","hashes","_match","_end","icon","ctx","entries","toolbar","isActive","style","check","blockLength","excludeMarks","excludeSet","HeadingPlugin","LinkPlugin","openInNewTab","href","sum","textChildren","cursorIdx","cursorEntry","startIdx","endIdx","startEntry","endEntry","linkStart","linkEnd","removeBtn","input","applyBtn","BULLET_LIST_ICON","NUMBERED_LIST_ICON","CHECKLIST_ICON","LIST_TYPE_DEFINITIONS","ListPlugin","listType","indent","checked","li","enabledTypes","match","matchStr","matchLen","lastType","BlockquotePlugin","StrikethroughPlugin","HEX_COLOR_PATTERN","isValidHexColor","resolveColors","colors","COLOR_PALETTE","invalid","seen","unique","color","normalized","TextColorPlugin","activeColor","defaultBtn","swatch","HorizontalRulePlugin","_start","newParagraph","hrBlock","ALIGNMENT_LABELS","ALIGNMENT_ICONS","AlignmentPlugin","originalToDOM","defaultAlign","applyAlignment","alignment","capitalize","bindings","dropdownItems","_state","patched","patchedSteps","prevAlign","newAttrs","align","s","FontPlugin","family","f","activeFamily","displayName","fontMark","rules","font","face","declarations","activeFont","defaultFamily","isDefault","DEFAULT_FONT_SIZES","DEFAULT_FONT_SIZE","MIN_CUSTOM_SIZE","MAX_CUSTOM_SIZE","FontSizePlugin","resolveSizes","resolveDefaultSize","size","activeSize","raw","parsed","currentSize","inputWrapper","activeIdx","activeItem","setFocusedIndex","val","selectedSize","sizes","n","FIRA_CODE_WOFF2_DATA","FIRA_SANS_WOFF2_DATA","FIRA_CODE","FIRA_SANS","STARTER_FONTS","createTable","rows","cols","tableId","rowNodes","cellNodes","createTableCell","createTableRow","paragraph","findTableContext","tableNode","tableIndex","cellId","rowId","rowIndex","rowNode","colIndex","totalCols","totalRows","getCellAt","table","getFirstLeafInCell","getLastLeafInCell","isInsideTable","insertTable","currentBlockId","rootIndex","rootBlock","paragraphAfter","insertIndex","firstRow","firstCell","firstParagraph","addRowAbove","tableCtx","firstLeaf","addRowBelow","addColumnLeft","addColumn","addColumnRight","side","insertColIndex","newCell","deleteRow","deleteTable","targetRowIndex","targetCellId","leafId","deleteColumn","targetColIndex","resolveTableDeletionTarget","createDeleteTableTransaction","selectTable","selectedNode","registerTableCommands","nextRoot","prevRoot","registerTableKeymaps","handleTab","handleShiftTab","handleEnter","handleBackspace","handleDelete","handleArrowDown","handleArrowUp","handleArrowRight","handleArrowLeft","handleEscape","moveToCellAndSelect","selectTableNode","lastLeaf","moveToCellAtEnd","nextIndex","nextBlock","leaf","leafLen","PLUS_SVG","DELETE_SVG","TABLE_DELETE_SVG","BORDER_THRESHOLD","insertRowAtIndex","getState","dispatch","numCols","insertColumnAtIndex","deleteRowAtIndex","deleteTableAtRoot","deleteColumnAtIndex","createButton","className","innerHTML","title","buildInsertLine","orientation","line","buildAddButton","buildHandleBar","bar","buildHandle","onDelete","handle","deleteBtn","createTableControls","tableEl","initialNode","numRows","countRows","countCols","colBar","rowBar","insertLineH","insertLineV","addRowZone","addColZone","deleteTableBtn","activeRowIndex","activeColIndex","rebuildColHandles","rebuildRowHandles","insertBtnH","insertBtnV","onMouseMove","onMouseLeave","observer","positionControls","getTableOffset","top","measureRowBorders","trs","tableTop","borders","measureColBorders","colWidth","positionColHandles","positionRowHandles","positionAddButtons","handles","tableWidth","h","totalHeight","height","tableHeight","tableRect","x","y","hideInsertLines","rowBorders","nearestRowDist","nearestRowBorder","border","dist","colBorders","nearestColDist","nearestColBorder","showHorizontalLine","hideVerticalLine","showVerticalLine","hideHorizontalLine","newRows","newCols","createTableNodeViewFactory","_registry","wrapper","tbody","liveRegion","controls","updatedNode","updatedRows","newTotalRows","newTotalCols","createTableRowNodeViewFactory","_getState","_dispatch","createTableCellNodeViewFactory","td","colspan","rowspan","newColspan","newRowspan","TableSelectionServiceKey","createTableSelectionService","selectedRange","cachedCellIds","cachedCellIdSet","updateCache","minRow","maxRow","minCol","maxCol","updateCellHighlights","selectedIds","installMouseSelection","anchorCell","isDragging","handleMouseDown","cellEl","handleMouseMove","handleMouseUp","TABLE_ICON","TablePlugin","HIGHLIGHT_PALETTE","HighlightPlugin","SUPERSCRIPT_ICON","SUBSCRIPT_ICON","SuperSubPlugin","markName","removeStep","storedMarksAfter","hasSup","hasSub","lastSupIdx","lastSubIdx","removeType","insertImage","imageAttrs","anchorBlockId","findTableCellAncestor","insertImageIntoCell","insertImageAtRoot","imageBlock","cellPath","rawIndex","removeImage","nodePath","imageIndex","selectionTarget","findSelectionTargetAfterRemoval","removedId","rootChildren","adjacent","registerImageCommands","ALIGNMENT_CLASSES","MIN_IMAGE_WIDTH","HANDLE_CURSORS","HANDLE_X_SIGN","HANDLE_LABELS","activeCursorStyle","setGlobalResizeCursor","cursor","clearGlobalResizeCursor","createImageNodeViewFactory","uploadStates","figure","img","overlay","currentNodeId","resizeOverlay","applyAttrs","src","alt","_e","cls","alignClass","uploadState","isUploading","clampWidth","commitResize","prevWidth","prevHeight","merged","attachHandleListeners","position","sizeIndicator","startX","startWidth","aspectRatio","onPointerMove","deltaX","newWidth","newHeight","onPointerUp","finalWidth","finalHeight","imgHeight","createResizeOverlay","positions","removeResizeOverlay","IMAGE_UPLOAD_SERVICE","DEFAULT_IMAGE_CONFIG","ImagePlugin","url","imgContainer","sizeAttrs","files","_position","imageFiles","file","blobUrl","imageBlockId","uploadService","fileInput","uploadLabel","separator","line1","orText","line2","urlInput","insertBtn","applyUrl","accepted","HardBreakPlugin","COPY_ICON","createCodeBlockNodeViewFactory","pre","header","langLabel","showCopy","copyBtn","copyAnnouncer","code","escHint","lang","langName","bg","DEFAULT_KEYMAP","CODE_BLOCK_SERVICE_KEY","CODE_BLOCK_ICON","CodeBlockPlugin","oldBlockId","oldBlock","wasInCode","nowInCode","DecorationSetClass","highlighter","tokens","token","inlineDecoration","langAttr","langClass","insertAfter","toggle","language","cellSpec","currentAllow","lineStart","spaceCount","firstNewline","trimmedLen","ThemePreset","LIGHT_THEME","DARK_THEME","createTheme","base","overrides","resolveTheme","theme","VARIABLE_MAP","COMPONENT_FALLBACKS","resolvePath","part","generateThemeCSS","cssVar","fallback","createThemeStyleSheet","sheet","InputHandler","composedText","textBefore","segmentsToText","acc","segmentsLength","pasteSlice","slice","pasteInline","pasteSingleBlock","pasteMultiBlock","totalLength","firstSlice","lastSlice","middleSlices","splitOffset","tailBlockId","insertAt","mid","textNodes","lastLen","BLOCK_ELEMENTS","INLINE_ELEMENTS","HTMLParser","pendingSegments","headingMatch","blockType","blockMatch","isChecklist","resolvedListType","inlineSegments","nestedLists","nested","nestedType","parentMarks","childMarks","matchedTypes","upperTag","additional","rawMarks","segment","PasteHandler","blockJson","richJson","allowedTags","allowedAttrs","sanitized","DOMPurify","parser","template","typeName","anchorIndex","isAnchorEmpty","lastBlockId","lastTextLen","richEl","reconcile","oldBlocks","newBlocks","nodeViews","unwrapBlocks","oldBlockMap","newBlockIds","nv","oldBlockById","previousSibling","selectedNodeId","previousSelectedNodeId","existingEl","oldDecos","newDecos","blockChanged","existingNv","updatedInlineDecos","renderBlockContent","_f","newEl","renderBlock","_g","_h","_i","_j","wrapBlocks","oldAttrs","oldKeys","newKeys","oldChild","newChild","inlineAttrsEqual","oldArr","newArr","inlineDecos","nvSpec","contentDOMChildren","contentDOM","childEl","arr","dom","applyNodeDecorations","renderParagraphFallback","renderTextNode","renderInlineNode","renderDecoratedContent","lastChild","p","preserveSpaces","textNode","sortedMarks","markOrder","createMarkElement","globalOffset","textFrom","textTo","splitSet","dFrom","dTo","splits","localFrom","localTo","activeDecos","j","createDecorationElement","tagName","nodeDecos","wrappers","currentSpec","currentIds","nodeSpec","wSpec","firstEl","getSelection","syncSelectionToDOM","domSel","blockEl","childIdx","childIndexOf","anchorPos","statePositionToDOM","headPos","readSelectionFromDOM","anchorNode","focusNode","domPositionToState","contentEl","resolveContentRoot","walker","createInlineContentWalker","childIndex","domOffset","findBlockElement","rawBlockId","buildBlockPath","targetEl","childOffset","inlineContentWidth","walkerNode","leafBlockEl","isInsideInlineElement","EditorView","contentElement","oldDecorations","newDecorations","cb","nearestBlockEl","lastBlockEl","lastRect","domNode","cp","shadowRoot","activeEl","oldSelection","EDITOR_CSS","cachedStyleSheet","getEditorStyleSheet","NotectlEditor","resolve","_oldValue","newValue","isReadonly","shadow","pluginMgr","topContainer","bottomContainer","announcer","currentListTag","finalTr","event","pluginTeardown","resolved","pluginIds","listeners","getBlockTypeLabel","markTypes","mt","branded","wasActive","nowActive","inlineContent","inlineSpec","markSpec","types","blockRules","matchBlockParseRule","markRules","BLOCK_TYPE_LABELS","createEditor","editor"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAy6CnB,IAAIC,KAAyC;AAGtC,SAASC,KAAqC;AACpD,SAAKD,OACJA,KAAmB,IAAI,cAAA,GACvBA,GAAiB,YAAYD,EAAU,IAEjCC;AACR;ACv2CO,MAAME,WAAsB,YAAY;AAAA,EAkB9C,cAAc;AACb,UAAA;AAlBO,IAAAtlC,EAAA,cAA0B;AAC1B,IAAAA,EAAA,uBAAsC;AACtC,IAAAA,EAAA,wBAAqC;AACrC,IAAAA,EAAA,uBAAoC;AACpC,IAAAA,EAAA,4BAAyC;AACzC,IAAAA,EAAA,+BAA4C;AAC5C,IAAAA,EAAA,mBAAgC;AAChC,IAAAA,EAAA,gBAA8B,CAAA;AAC9B,IAAAA,EAAA,4CAA+D,IAAA;AAC/D,IAAAA,EAAA,6BAA2C;AAClC,IAAAA,EAAA;AACT,IAAAA,EAAA,qBAAc;AACd,IAAAA,EAAA,wBAA2B,CAAA;AAC3B,IAAAA,EAAA,yBAAwC;AACxC,IAAAA,EAAA,0BAA0C;AAC1C,IAAAA,EAAA,4BAAgE;AA+Q/D;AAAA,IAAAA,EAAA,kBAAW;AAAA,MACnB,YAAY,MAAM,KAAK,eAAe,YAAY;AAAA,MAClD,cAAc,MAAM,KAAK,eAAe,cAAc;AAAA,MACtD,iBAAiB,MAAM,KAAK,eAAe,iBAAiB;AAAA,MAC5D,MAAM,MAAA;;AAAM,gBAAAmB,IAAA,KAAK,SAAL,gBAAAA,EAAW;AAAA;AAAA,MACvB,MAAM,MAAA;;AAAM,gBAAAA,IAAA,KAAK,SAAL,gBAAAA,EAAW;AAAA;AAAA,MACvB,WAAW,MAAM;AAChB,YAAI,CAAC,KAAK,KAAM;AAChB,cAAMiH,IAAKoH,GAAU,KAAK,KAAK,UAAU;AACzC,aAAK,SAASpH,CAAE;AAAA,MACjB;AAAA,IAAA;AArRA,SAAK,eAAe,IAAI,QAAQ,CAACm9B,MAAY;AAC5C,WAAK,sBAAsBA;AAAA,IAC5B,CAAC,GACD,KAAK,aAAa,EAAE,MAAM,OAAA,CAAQ;AAAA,EACnC;AAAA,EAEA,WAAW,qBAA+B;AACzC,WAAO,CAAC,eAAe,YAAY,OAAO;AAAA,EAC3C;AAAA,EAEA,oBAA0B;AACzB,IAAI,KAAK,eACT,KAAK,KAAA;AAAA,EACN;AAAA,EAEA,uBAA6B;AAC5B,SAAK,QAAA;AAAA,EACN;AAAA,EAEA,yBAAyBnmC,GAAcomC,GAA0BC,GAA+B;AAI/F,QAHIrmC,MAAS,iBAAiB,KAAK,kBAClC,KAAK,eAAe,aAAa,oBAAoBqmC,KAAY,EAAE,GAEhErmC,MAAS,cAAc,KAAK,gBAAgB;AAC/C,YAAMsmC,IAAsBD,MAAa;AACzC,WAAK,eAAe,kBAAkBC,IAAa,UAAU,QACzDA,IACH,KAAK,eAAe,aAAa,iBAAiB,MAAM,IAExD,KAAK,eAAe,gBAAgB,eAAe;AAAA,IAErD;AACA,IAAItmC,MAAS,WAAW,KAAK,eAC5B,KAAK,WAAYqmC,KAA4BlM,GAAY,KAAK;AAAA,EAEhE;AAAA;AAAA,EAGA,eAAerkB,GAAsB;AACpC,QAAI,KAAK;AACR,YAAM,IAAI;AAAA,QACT;AAAA,MAAA;AAGF,SAAK,eAAe,KAAKA,CAAM;AAAA,EAChC;AAAA;AAAA,EAGA,MAAM,KAAKS,GAA6C;;AACvD,QAAI,KAAK,YAAa;AACtB,SAAK,cAAc,IAEfA,WAAa,SAASA;AAE1B,UAAMgwB,IAAS,KAAK;AACpB,QAAI,CAACA,EAAQ;AAGb,SAAK,WAAW,KAAK,OAAO,SAASpM,GAAY,KAAK,GAGtD,KAAK,gBAAgB,SAAS,cAAc,KAAK,GACjD,KAAK,cAAc,YAAY,kBAE/B,KAAK,qBAAqB,SAAS,cAAc,KAAK,GACtD,KAAK,mBAAmB,YAAY,iCAEpC,KAAK,iBAAiB,SAAS,cAAc,KAAK,GAClD,KAAK,eAAe,YAAY,mBAChC,KAAK,eAAe,kBAAkB,KAAK,OAAO,WAAW,UAAU,QACvE,KAAK,eAAe,aAAa,QAAQ,SAAS,GAClD,KAAK,eAAe,aAAa,kBAAkB,MAAM,GACzD,KAAK,eAAe,aAAa,cAAc,kBAAkB,GAC7D,KAAK,OAAO,YACf,KAAK,eAAe,aAAa,iBAAiB,MAAM,GAEzD,KAAK,eAAe,aAAa,oBAAoB,iCAAiC,GACtF,KAAK,eAAe;AAAA,MACnB;AAAA,MACA,KAAK,OAAO,eAAe;AAAA,IAAA,GAG5B,KAAK,wBAAwB,SAAS,cAAc,KAAK,GACzD,KAAK,sBAAsB,YAAY,oCAGvC,KAAK,YAAY,SAAS,cAAc,KAAK,GAC7C,KAAK,UAAU,YAAY,mBAC3B,KAAK,UAAU,aAAa,aAAa,QAAQ,GACjD,KAAK,UAAU,aAAa,eAAe,MAAM,GAEjD,KAAK,cAAc,YAAY,KAAK,kBAAkB,GACtD,KAAK,cAAc,YAAY,KAAK,cAAc,GAClD,KAAK,cAAc,YAAY,KAAK,qBAAqB,GACzD,KAAK,cAAc,YAAY,KAAK,SAAS,GAE7CoM,EAAO,YAAY,KAAK,aAAa,GAGrC,KAAK,gBAAgB,IAAI1wB,GAAA,GAGzB1R,GAAqB,KAAK,cAAc,cAAc,GAGtD,KAAK,qBAAA;AAGL,eAAW2R,KAAU,KAAK,OAAO,WAAW,CAAA;AAC3C,WAAK,cAAc,SAASA,CAAM;AAInC,eAAWA,KAAU,KAAK;AACzB,WAAK,cAAc,SAASA,CAAM;AAEnC,SAAK,iBAAiB,CAAA,GAGtB,KAAK,2BAAA,GAGL,KAAK,eAAe,iBAAiB,SAAS,MAAM,KAAK,KAAK,SAAS,MAAS,CAAC,GACjF,KAAK,eAAe,iBAAiB,QAAQ,MAAM,KAAK,KAAK,QAAQ,MAAS,CAAC;AAK/E,UAAMquB,IAAY,KAAK,gBACjBqC,IAAY,KAAK,eACjBC,IAAe,KAAK,oBACpBC,IAAkB,KAAK;AAC7B,QAAI,CAACvC,KAAa,CAACqC,KAAa,CAACC,KAAgB,CAACC,EAAiB;AAEnE,UAAMC,IAAY,KAAK;AACvB,UAAMH,EAAU,KAAK;AAAA,MACpB,UAAU,MAAM;AACf,YAAI,CAAC,KAAK,KAAM,OAAM,IAAI,MAAM,sBAAsB;AACtD,eAAO,KAAK,KAAK,SAAA;AAAA,MAClB;AAAA,MACA,UAAU,CAACx9B,MAAO,KAAK,SAASA,CAAE;AAAA,MAClC,cAAc,MAAMm7B;AAAA,MACpB,oBAAoB,CAAC7O,MAAcA,MAAa,QAAQmR,IAAeC;AAAA,MACvE,UAAU,CAAC1rC,MAAiB;AAC3B,QAAI2rC,QAAqB,cAAc3rC;AAAA,MACxC;AAAA,MACA,eAAe,MAAM;AACpB,cAAM6E,IAASH,GAAmB8mC,EAAU,cAAc,GACpDn7B,IAAQpB,GAAY,OAAO,EAAE,QAAApK,GAAQ;AAC3C,aAAK,OAAO,IAAIqlC,GAAWf,GAAW;AAAA,UACrC,OAAA94B;AAAA,UACA,gBAAgBm7B,EAAU;AAAA,UAC1B,iBAAiB,KAAK,OAAO;AAAA,UAC7B,gBAAgB,CAAC9jB,GAAG1Z,MAAA;;AACnB,qBAAAjH,IAAA,KAAK,kBAAL,gBAAAA,EAAoB,mBAAmB2gB,GAAG1Z,OAAOqM,GAAc;AAAA;AAAA,UAChE,eAAe,CAACW,GAAUC,GAAUjN,MAAO;AAC1C,iBAAK,cAAcgN,GAAUC,GAAUjN,CAAE;AAAA,UAC1C;AAAA,QAAA,CACA,GACD,KAAK,iBAAA;AAAA,MACN;AAAA,IAAA,CACA,GAEG,KAAK,OAAO,aACf,sBAAsB,MAAA;;AAAM,cAAAjH,IAAA,KAAK,mBAAL,gBAAAA,EAAqB;AAAA,KAAO,IAGzDA,IAAA,KAAK,wBAAL,QAAAA,EAAA,YACA,KAAK,KAAK,SAAS,MAAS;AAAA,EAC7B;AAAA;AAAA;AAAA,EAKA,UAAoB;AACnB,QAAI,CAAC,KAAK,KAAM,OAAM,IAAI,MAAM,wBAAwB;AACxD,WAAO,KAAK,KAAK,SAAA,EAAW;AAAA,EAC7B;AAAA;AAAA,EAGA,QAAQM,GAAqB;;AAC5B,UAAMxC,IAAS,KAAK,gBACjBH,GAAmB,KAAK,cAAc,cAAc,IACpD,QACG2L,IAAQpB,GAAY,OAAO;AAAA,MAChC,KAAA5H;AAAA,MACA,QAAAxC;AAAA,MACA,WAAWX,IAAyB6C,IAAAM,EAAI,SAAS,CAAC,MAAd,gBAAAN,EAAiB,OAAc,IAAK,CAAC;AAAA,IAAA,CACzE;AACD,SAAK,aAAasJ,CAAK;AAAA,EACxB;AAAA;AAAA,EAGA,UAAkB;;AACjB,QAAI,CAAC,KAAK,KAAM,OAAM,IAAI,MAAM,wBAAwB;AACxD,UAAMhJ,IAAM,KAAK,KAAK,SAAA,EAAW,KAC3B1C,KAAWoC,IAAA,KAAK,kBAAL,gBAAAA,EAAoB,gBAC/BwP,IAAkB,CAAA;AACxB,QAAIq1B,IAAgC;AAEpC,eAAWzsC,KAASkI,EAAI;AACvB,UAAIlC,GAAahG,GAAO,WAAW,GAAG;AAErC,cAAMqG,IADWrG,EAAM,MAAM,aACJ,YAAY,OAAO;AAE5C,QAAIysC,MAAmBpmC,MAClBomC,KAAgBr1B,EAAM,KAAK,KAAKq1B,CAAc,GAAG,GACrDr1B,EAAM,KAAK,IAAI/Q,CAAG,GAAG,GACrBomC,IAAiBpmC,IAGlB+Q,EAAM,KAAK,KAAK,eAAepX,GAAOwF,CAAQ,CAAC;AAAA,MAChD;AACC,QAAIinC,MACHr1B,EAAM,KAAK,KAAKq1B,CAAc,GAAG,GACjCA,IAAiB,OAElBr1B,EAAM,KAAK,KAAK,eAAepX,GAAOwF,CAAQ,CAAC;AAIjD,IAAIinC,KAAgBr1B,EAAM,KAAK,KAAKq1B,CAAc,GAAG;AAErD,UAAM5I,IAAwBr+B,IAAWA,EAAS,eAAA,IAAmB,CAAC,KAAK,MAAM,OAAO,MAAM,GACxFs+B,IAAyBt+B,IAAWA,EAAS,gBAAA,IAAoB,CAAC,OAAO;AAE/E,WAAOw+B,GAAU,SAAS5sB,EAAM,KAAK,EAAE,GAAG;AAAA,MACzC,cAAcysB;AAAA,MACd,cAAcC;AAAA,IAAA,CACd;AAAA,EACF;AAAA;AAAA,EAGA,QAAQzrB,GAAoB;;AAC3B,UAAM7S,KAAWoC,IAAA,KAAK,kBAAL,gBAAAA,EAAoB,gBAC/Bi8B,IAAwBr+B,IAAWA,EAAS,eAAA,IAAmB,CAAC,KAAK,MAAM,OAAO,MAAM,GACxFs+B,IAAyBt+B,IAAWA,EAAS,gBAAA,IAAoB,CAAC,OAAO,GAEzEu+B,IAAYC,GAAU,SAAS3rB,GAAM;AAAA,MAC1C,cAAcwrB;AAAA,MACd,cAAcC;AAAA,IAAA,CACd,GAEK57B,IAAM,KAAK,oBAAoB67B,CAAS;AAC9C,SAAK,QAAQ77B,CAAG;AAAA,EACjB;AAAA;AAAA,EAGA,UAAkB;AACjB,QAAI,CAAC,KAAK,KAAM,OAAM,IAAI,MAAM,wBAAwB;AAExD,WADY,KAAK,KAAK,SAAA,EAAW,IACtB,SAAS,IAAI,CAACzF,MAAMT,EAAaS,CAAC,CAAC,EAAE,KAAK;AAAA,CAAI;AAAA,EAC1D;AAAA;AAAA,EAGA,UAAmB;AAClB,QAAI,CAAC,KAAK,KAAM,QAAO;AACvB,UAAMyF,IAAM,KAAK,KAAK,SAAA,EAAW;AACjC,QAAIA,EAAI,SAAS,WAAW,EAAG,QAAO;AACtC,QAAIA,EAAI,SAAS,SAAS,EAAG,QAAO;AACpC,UAAMlI,IAAQkI,EAAI,SAAS,CAAC;AAC5B,WAAKlI,IACEA,EAAM,SAAS,eAAegC,EAAahC,CAAK,MAAM,KAD1C;AAAA,EAEpB;AAAA;AAAA,EAkBA,MAME;;AACD,UAAM0F,KAASkC,IAAA,KAAK,SAAL,gBAAAA,EAAW,WAAW;AACrC,WAAO;AAAA,MACN,YAAY,MAAOlC,IAASD,GAAcC,GAAQ,MAAM,IAAI;AAAA,MAC5D,cAAc,MAAOA,IAASD,GAAcC,GAAQ,QAAQ,IAAI;AAAA,MAChE,iBAAiB,MAAOA,IAASD,GAAcC,GAAQ,WAAW,IAAI;AAAA,MACtE,MAAM,MAAA;;AAAM,iBAAAkC,IAAA,KAAK,SAAL,gBAAAA,EAAW,QAAQ,cAAa;AAAA;AAAA,MAC5C,MAAM,MAAA;;AAAM,iBAAAA,IAAA,KAAK,SAAL,gBAAAA,EAAW,QAAQ,cAAa;AAAA;AAAA,IAAA;AAAA,EAE9C;AAAA;AAAA,EAGA,eAAe/B,GAAuB;;AACrC,aAAO+B,IAAA,KAAK,kBAAL,gBAAAA,EAAoB,eAAe/B,OAAS;AAAA,EACpD;AAAA;AAAA,EAGA,gBAAgBC,GAAkBsW,GAA4B;;AAC7D,KAAAxU,IAAA,KAAK,kBAAL,QAAAA,EAAoB,gBAAgB9B,GAAUsW;AAAA,EAC/C;AAAA;AAAA;AAAA,EAKA,WAAwB;AACvB,QAAI,CAAC,KAAK,KAAM,OAAM,IAAI,MAAM,wBAAwB;AACxD,WAAO,KAAK,KAAK,SAAA;AAAA,EAClB;AAAA;AAAA,EAGA,SAASvN,GAAuB;AAC/B,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,iBACxB,KAAK,cAAc;AAAA,MAAuBA;AAAA,MAAI,KAAK,KAAK,SAAA;AAAA,MAAY,CAAC69B,MAAA;;AACpE,gBAAA9kC,IAAA,KAAK,SAAL,gBAAAA,EAAW,SAAS8kC;AAAA;AAAA,IAAO;AAAA,EAE7B;AAAA;AAAA;AAAA,EAKA,GAA6BC,GAAU9jC,GAA4C;;AAClF,IAAK,KAAK,eAAe,IAAI8jC,CAAK,KACjC,KAAK,eAAe,IAAIA,GAAO,oBAAI,KAAK,IAEzC/kC,IAAA,KAAK,eAAe,IAAI+kC,CAAK,MAA7B,QAAA/kC,EAAgC,IAAIiB;AAAA,EACrC;AAAA;AAAA,EAGA,IAA8B8jC,GAAU9jC,GAA4C;;AACnF,KAAAjB,IAAA,KAAK,eAAe,IAAI+kC,CAAK,MAA7B,QAAA/kC,EAAgC,OAAOiB;AAAA,EACxC;AAAA;AAAA;AAAA,EAKA,YAA2B;AAC1B,WAAO,KAAK;AAAA,EACb;AAAA;AAAA,EAGA,UAAUuT,GAA4C;AACrD,IAAIA,EAAO,gBAAgB,UAAa,KAAK,kBAC5C,KAAK,eAAe,aAAa,oBAAoBA,EAAO,WAAW,GAGpEA,EAAO,aAAa,UAAa,KAAK,mBACzC,KAAK,eAAe,kBAAkBA,EAAO,WAAW,UAAU,QAC9DA,EAAO,WACV,KAAK,eAAe,aAAa,iBAAiB,MAAM,IAExD,KAAK,eAAe,gBAAgB,eAAe,IAIrD,KAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAGA,EAAA;AAAA,EACpC;AAAA;AAAA;AAAA,EAKA,SAASmkB,GAAkC;AAC1C,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,OAAAA,EAAA,GAChC,KAAK,WAAWA,CAAK;AAAA,EACtB;AAAA;AAAA,EAGA,WAAgC;AAC/B,WAAO,KAAK,OAAO,SAASP,GAAY;AAAA,EACzC;AAAA;AAAA,EAGA,UAAyB;;AACxB,SAAK,2BAAA,IACLp4B,IAAA,KAAK,SAAL,QAAAA,EAAW;AACX,UAAMglC,MAAiB/kC,IAAA,KAAK,kBAAL,gBAAAA,EAAoB,cAAa,QAAQ,QAAA;AAChE,gBAAK,OAAO,MACZ,KAAK,gBAAgB,MACrB,KAAK,cAAc,IACZ+kC;AAAA,EACR;AAAA;AAAA;AAAA,EAKQ,WAAWrM,GAAkC;AAGpD,QAFA,KAAK,2BAAA,GAEDA,MAAUP,GAAY,QAAQ;AACjC,WAAK,yBAAA;AACL,YAAM6M,IAAkBvM,GAAa,KAAK,eAAA,CAAgB;AAC1D,WAAK,mBAAmBuM,CAAQ;AAAA,IACjC;AACC,WAAK,mBAAmBvM,GAAaC,CAAK,CAAC;AAAA,EAE7C;AAAA,EAEQ,mBAAmBA,GAAoB;AAC9C,IAAK,KAAK,oBACT,KAAK,kBAAkB,IAAI,cAAA,IAE5B,KAAK,gBAAgB,YAAYK,GAAiBL,CAAK,CAAC;AAExD,UAAM6L,IAA4B,KAAK;AACvC,IAAIA,MACHA,EAAO,qBAAqB,CAAC,KAAK,iBAAiBN,IAAqB;AAAA,EAE1E;AAAA,EAEQ,2BAAiC;AACxC,SAAK,mBAAmB,OAAO,WAAW,8BAA8B,GACxE,KAAK,qBAAqB,CAACtR,MAAkC;AAC5D,YAAMqS,IAAkBvM,GAAa,KAAK,eAAA,CAAgB;AAC1D,WAAK,mBAAmBuM,CAAQ;AAAA,IACjC,GACA,KAAK,iBAAiB,iBAAiB,UAAU,KAAK,kBAAkB;AAAA,EACzE;AAAA,EAEQ,6BAAmC;AAC1C,IAAI,KAAK,oBAAoB,KAAK,sBACjC,KAAK,iBAAiB,oBAAoB,UAAU,KAAK,kBAAkB,GAE5E,KAAK,mBAAmB,MACxB,KAAK,qBAAqB;AAAA,EAC3B;AAAA,EAEQ,iBAA8B;AAErC,WAD6B,OAAO,WAAW,8BAA8B,EAAE,UAC1D7M,GAAY,OAAOA,GAAY;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAA6B;AACpC,QAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,OAAO,QAAS;AAEjD,UAAMve,IAAqB,CAAA;AAC3B,eAAWtQ,KAAS,KAAK,OAAO,SAAS;AACxC,YAAM27B,IAAsB,CAAA;AAC5B,iBAAWnxB,KAAUxK;AACpB,QAAA27B,EAAU,KAAKnxB,EAAO,EAAE,GACxB,KAAK,cAAc,SAASA,CAAM;AAEnC,MAAA8F,EAAO,KAAKqrB,CAAS;AAAA,IACtB;AAEA,UAAMhsB,IAAoC,EAAE,QAAAW,EAAA;AAC5C,SAAK,cAAc,SAAS,IAAIZ,GAAcC,CAAY,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,6BAAmC;;AAI1C,QAHI,CAAC,KAAK,iBAEgB,KAAK,cAAc,IAAI,iBAAiB,MAAM,OACjD;AAEvB,UAAM/N,IAAiC;AAAA,MACtC,QAAMnL,IAAA,KAAK,OAAO,aAAZ,gBAAAA,EAAsB,SAAQ;AAAA,MACpC,UAAQC,IAAA,KAAK,OAAO,aAAZ,gBAAAA,EAAsB,WAAU;AAAA,MACxC,aAAWC,IAAA,KAAK,OAAO,aAAZ,gBAAAA,EAAsB,cAAa;AAAA,IAAA;AAG/C,SAAK,cAAc,SAAS,IAAIua,GAAqBtP,CAAQ,CAAC;AAAA,EAC/D;AAAA,EAEQ,KAA+B45B,GAAUl0B,GAA4B;AAC5E,UAAMs0B,IAAY,KAAK,eAAe,IAAIJ,CAAK;AAC/C,QAAII;AACH,iBAAW5B,KAAM4B;AACf,QAAA5B,EAAkC1yB,CAAO;AAAA,EAG7C;AAAA,EAEQ,cAAcoD,GAAuBC,GAAuBjN,GAAuB;;AAE1F,IAAI,KAAK,cAAW,KAAK,UAAU,cAAc,MAGjDjH,IAAA,KAAK,kBAAL,QAAAA,EAAoB,kBAAkBiU,GAAUC,GAAUjN,IAG1D,KAAK,iBAAA,GAGL,KAAK,KAAK,eAAe,EAAE,UAAAgN,GAAU,UAAAC,GAAU,aAAajN,GAAI,GAE3DpK,GAAgBoX,EAAS,WAAWC,EAAS,SAAS,KAC1D,KAAK,KAAK,mBAAmB,EAAE,WAAWA,EAAS,WAAW,IAI1DjU,IAAA,KAAK,cAAL,QAAAA,EAAgB,eACpB,KAAK,oBAAoBgU,GAAUC,GAAUjN,CAAE;AAAA,EAEjD;AAAA,EAEQ,mBAAyB;AAChC,IAAK,KAAK,kBACV,KAAK,eAAe,UAAU,OAAO,0BAA0B,KAAK,SAAS;AAAA,EAC9E;AAAA,EAEQ,oBAAoBgN,GAAuBC,GAAuBjN,GAAuB;AAChG,QAAI,CAAC,KAAK,UAAW;AAGrB,QAAIA,EAAG,SAAS,qBAAqB,QAAQ;AAC5C,WAAK,UAAU,cAAc;AAC7B;AAAA,IACD;AACA,QAAIA,EAAG,SAAS,qBAAqB,QAAQ;AAC5C,WAAK,UAAU,cAAc;AAC7B;AAAA,IACD;AAGA,eAAWzE,KAAQyE,EAAG;AACrB,UAAIzE,EAAK,SAAS,gBAAgB;AACjC,cAAMuU,IAAQquB,GAAkB5iC,EAAK,UAAUA,EAAK,KAAK;AACzD,aAAK,UAAU,cAAcuU;AAC7B;AAAA,MACD;AAID,UAAMsuB,IAAYnxB,EAAS,OAAO;AAClC,eAAWoxB,KAAMD,GAAW;AAC3B,YAAME,IAAqBD,GACrBE,IAAYh3B,GAAayF,GAAUsxB,CAAO,GAC1CE,IAAYj3B,GAAa0F,GAAUqxB,CAAO;AAChD,UAAIC,MAAcC,GAAW;AAC5B,aAAK,UAAU,cAAc,GAAGH,CAAE,IAAIG,IAAY,OAAO,KAAK;AAC9D;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEQ,aAAavxB,GAA6B;AACjD,IAAK,KAAK,SAEV,KAAK,KAAK,aAAaA,CAAQ,GAC/B,KAAK,iBAAA;AAAA,EACN;AAAA;AAAA,EAIQ,eAAe9b,GAAkBwF,GAAmC;;AAC3E,UAAM8nC,IAAwB,KAAK,uBAAuBttC,GAAOwF,CAAQ,GACnEkB,IAAOlB,KAAA,gBAAAA,EAAU,YAAYxF,EAAM;AAEzC,QAAIqY;AACJ,IAAI3R,KAAA,QAAAA,EAAM,SACT2R,IAAO3R,EAAK,OAAO1G,GAAOstC,CAAa,IAEvCj1B,IAAO,MAAMi1B,KAAiB,MAAM;AAIrC,UAAMhlB,KAA6B1gB,IAAA5H,EAAM,UAAN,gBAAA4H,EAAyC;AAG5E,WAAI0gB,KAASA,MAAU,WACtBjQ,IAAOA,EAAK,QAAQ,KAAK,uBAAuBiQ,CAAK,IAAI,IAGnDjQ;AAAA,EACR;AAAA,EAEQ,uBAAuBrY,GAAkBwF,GAAmC;AACnF,UAAMjE,IAA+CnB,EAAkBJ,CAAK,GACtEoX,IAAkB,CAAA;AAExB,eAAW7W,KAASgB;AACnB,UAAId,EAAaF,CAAK,GAAG;AACxB,cAAMgtC,IAAa/nC,KAAA,gBAAAA,EAAU,kBAAkBjF,EAAM;AACrD,QAAIgtC,KAAA,QAAAA,EAAY,gBACfn2B,EAAM,KAAKm2B,EAAW,aAAahtC,CAAK,CAAC;AAAA,MAE3C;AACC,QAAA6W,EAAM,KAAK,KAAK,kBAAkB7W,GAAOiF,CAAQ,CAAC;AAIpD,WAAO4R,EAAM,KAAK,EAAE;AAAA,EACrB;AAAA,EAEQ,kBAAkBrW,GAAgByE,GAAmC;AAC5E,QAAIzE,EAAK,SAAS,GAAI,QAAO;AAE7B,QAAIsX,IAAe9R,GAAWxF,EAAK,IAAI;AAGvC,UAAM8mC,IAAiC,KAAK,aAAA,GACtCD,IAAsB,CAAC,GAAG7mC,EAAK,KAAK,EAAE;AAAA,MAC3C,CAACyB,GAAGC,OAAOolC,EAAU,IAAIrlC,EAAE,IAAI,KAAK,OAAOqlC,EAAU,IAAIplC,EAAE,IAAI,KAAK;AAAA,IAAA;AAGrE,eAAWa,KAAQskC,GAAa;AAC/B,YAAM4F,IAAWhoC,KAAA,gBAAAA,EAAU,YAAYlC,EAAK;AAC5C,MAAIkqC,KAAA,QAAAA,EAAU,iBACbn1B,IAAOm1B,EAAS,aAAalqC,GAAM+U,CAAI;AAAA,IAEzC;AAEA,WAAOA;AAAA,EACR;AAAA,EAEQ,eAAoC;;AAC3C,UAAM7S,KAAWoC,IAAA,KAAK,kBAAL,gBAAAA,EAAoB;AACrC,QAAI,CAACpC,EAAU,QAAO,oBAAI,IAAA;AAC1B,UAAMioC,IAAQjoC,EAAS,aAAA,GACjBoL,wBAAY,IAAA;AAClB,eAAW7G,KAAK0jC,GAAO;AACtB,YAAM/mC,IAAOlB,EAAS,YAAYuE,CAAC;AACnC,MAAIrD,KAAMkK,EAAM,IAAI7G,GAAGrD,EAAK,QAAQ,EAAE;AAAA,IACvC;AACA,WAAOkK;AAAA,EACR;AAAA;AAAA,EAIQ,oBAAoByH,GAAwB;;AACnD,UAAM7S,KAAWoC,IAAA,KAAK,kBAAL,gBAAAA,EAAoB,gBAC/Bi8B,IAAwBr+B,IAAWA,EAAS,eAAA,IAAmB,CAAC,KAAK,MAAM,OAAO,MAAM,GACxFs+B,IAAyBt+B,IAAWA,EAAS,gBAAA,IAAoB,CAAC,OAAO,GAEzE0+B,IAAW,SAAS,cAAc,UAAU;AAClD,IAAAA,EAAS,YAAYF,GAAU,SAAS3rB,GAAM;AAAA,MAC7C,cAAcwrB;AAAA,MACd,cAAcC;AAAA,IAAA,CACd;AACD,UAAMhkB,IAAOokB,EAAS,SAEhBwJ,KAAaloC,KAAA,gBAAAA,EAAU,yBAAwB,CAAA,GAC/CmL,IAAsB,CAAA;AAE5B,eAAWpQ,KAAS,MAAM,KAAKuf,EAAK,UAAU;AAC7C,UAAIvf,EAAM,aAAa,KAAK,cAAc;AACzC,cAAM+F,IAAK/F,GACL8F,IAAMC,EAAG,QAAQ,YAAA;AAGvB,YAAID,MAAQ,QAAQA,MAAQ,MAAM;AACjC,gBAAMqf,IAAWrf,MAAQ,OAAO,YAAY;AAC5C,qBAAWwf,KAAM,MAAM,KAAKvf,EAAG,iBAAiB,IAAI,CAAC,GAAG;AACvD,kBAAM87B,IAAY,KAAK,wBAAwBvc,GAAmBrgB,CAAQ;AAC1E,YAAAmL,EAAO;AAAA,cACNnP,EAAyB,aAAc4gC,GAAW,QAAW;AAAA,gBAC5D,UAAA1c;AAAA,gBACA,QAAQ;AAAA,gBACR,SAAS;AAAA,cAAA,CACT;AAAA,YAAA;AAAA,UAEH;AACA;AAAA,QACD;AAGA,cAAMK,IAAQ4nB,GAAoBrnC,GAAIonC,CAAU;AAChD,YAAI3nB,GAAO;AACV,gBAAMqc,IAAY,KAAK,wBAAwB97B,GAAId,CAAQ;AAC3D,UAAAmL,EAAO;AAAA,YACNnP;AAAA,cACUukB,EAAM;AAAA,cACfqc;AAAAA,cACA;AAAA,cACArc,EAAM;AAAA,YAAA;AAAA,UACP;AAED;AAAA,QACD;AAGA,cAAMqc,IAAY,KAAK,wBAAwB97B,GAAId,CAAQ;AAC3D,QAAAmL,EAAO,KAAKnP,EAAyB,aAAc4gC,CAAS,CAAC;AAAA,MAC9D,MAAA,CAAW7hC,EAAM,aAAa,KAAK,eAAasH,IAAAtH,EAAM,gBAAN,QAAAsH,EAAmB,WAClE8I,EAAO;AAAA,QACNnP,EAAyB,aAAc,CAACI,EAAerB,EAAM,YAAY,KAAA,CAAM,CAAC,CAAC;AAAA,MAAA;AAKpF,WAAIoQ,EAAO,WAAW,IACdrP,GAAA,IAGDA,GAAeqP,CAAM;AAAA,EAC7B;AAAA,EAEQ,wBAAwBrK,GAAiBd,GAAuC;AACvF,UAAM9B,IAAqB,CAAA,GACrBkqC,KAAYpoC,KAAA,gBAAAA,EAAU,wBAAuB,CAAA;AACnD,gBAAK,YAAYc,GAAI,CAAA,GAAI5C,GAAQkqC,CAAS,GACnClqC,EAAO,SAAS,IAAIA,IAAS,CAAC9B,EAAe,EAAE,CAAC;AAAA,EACxD;AAAA,EAEQ,YACPb,GACAmS,GACAxP,GACAkqC,GACO;AACP,QAAI7sC,EAAK,aAAa,KAAK,WAAW;AACrC,YAAMF,IAAOE,EAAK,eAAe;AACjC,MAAIF,KACH6C,EAAO,KAAK9B,EAAef,GAAM,CAAC,GAAGqS,CAAY,CAAC,CAAC;AAEpD;AAAA,IACD;AAEA,QAAInS,EAAK,aAAa,KAAK,aAAc;AAEzC,UAAMuF,IAAKvF,GACLsF,IAAMC,EAAG,QAAQ,YAAA,GACjBzE,IAAQ,CAAC,GAAGqR,CAAY,GAGxBmwB,wBAAmB,IAAA;AACzB,eAAW97B,KAASqmC;AACnB,UAAIrmC,EAAM,KAAK,QAAQlB,KACnB,CAAAg9B,EAAa,IAAI97B,EAAM,IAAI;AAE/B,YAAIA,EAAM,KAAK,UAAU;AACxB,gBAAM5F,IAAQ4F,EAAM,KAAK,SAASjB,CAAE;AACpC,cAAI3E,MAAU,GAAO;AACrB,UAAKE,EAAM,KAAK,CAACuB,MAAMA,EAAE,SAASmE,EAAM,IAAI,MAC3C1F,EAAM,KAAK;AAAA,YACV,MAAiB0F,EAAM;AAAA,YACvB,GAAI,OAAO,KAAK5F,CAAK,EAAE,SAAS,IAAI,EAAE,OAAAA,MAAU,CAAA;AAAA,UAAC,CACzC,GACT0hC,EAAa,IAAI97B,EAAM,IAAI;AAAA,QAE7B;AACC,UAAK1F,EAAM,KAAK,CAACuB,MAAMA,EAAE,SAASmE,EAAM,IAAI,MAC3C1F,EAAM,KAAK,EAAE,MAAiB0F,EAAM,MAAO,GAC3C87B,EAAa,IAAI97B,EAAM,IAAI;AAK9B,eAAWhH,KAAS,MAAM,KAAK+F,EAAG,UAAU;AAC3C,WAAK,YAAY/F,GAAOsB,GAAO6B,GAAQkqC,CAAS;AAAA,EAElD;AACD;AAIA,MAAMC,KAA4C;AAAA,EACjD,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,OAAO;AAAA,EACP,OAAO;AACR;AAGA,SAASb,GAAkB7I,GAAkBxiC,GAAyC;AACrF,SAAIwiC,MAAa,cAAaxiC,KAAA,QAAAA,EAAO,SAC7B,WAAWA,EAAM,KAAK,KAEvBksC,GAAkB1J,CAAQ,KAAKA;AACvC;AAGA,SAASwJ,GACRrnC,GACAwiB,GAC6E;AAC7E,QAAMziB,IAAcC,EAAG,QAAQ,YAAA;AAC/B,aAAWiB,KAASuhB;AACnB,QAAIvhB,EAAM,KAAK,QAAQlB,GACvB;AAAA,UAAIkB,EAAM,KAAK,UAAU;AACxB,cAAM5F,IAAQ4F,EAAM,KAAK,SAASjB,CAAE;AACpC,YAAI3E,MAAU,GAAO;AACrB,eAAO,EAAE,MAAM4F,EAAM,MAAM,OAAA5F,EAAA;AAAA,MAC5B;AACA,aAAO,EAAE,MAAM4F,EAAM,KAAA;AAAA;AAEtB,SAAO;AACR;AAGI,OAAO,iBAAmB,OAAe,CAAC,eAAe,IAAI,gBAAgB,KAChF,eAAe,OAAO,kBAAkBwkC,EAAa;AAItD,eAAsB+B,GAAa1xB,GAAsD;AACxF,QAAM2xB,IAAS,SAAS,cAAc,gBAAgB;AACtD,eAAMA,EAAO,KAAK3xB,CAAM,GACjB2xB;AACR;"}
|
|
1
|
+
{"version":3,"file":"notectl-core.mjs","sources":["../src/model/SchemaRegistry.ts","../src/model/ContentModel.ts","../src/model/BuiltinSpecs.ts","../src/state/StepApplication.ts","../src/state/Transaction.ts","../src/state/EditorState.ts","../src/state/History.ts","../src/input/KeyboardHandler.ts","../src/input/InternalClipboard.ts","../src/input/ClipboardHandler.ts","../src/plugins/EventBus.ts","../src/plugins/PluginManager.ts","../src/editor/theme/ThemeTokens.ts","../src/editor/theme/ThemeEngine.ts","../src/input/InputHandler.ts","../src/model/ContentSlice.ts","../src/model/HTMLParser.ts","../src/input/PasteHandler.ts","../src/commands/PasteCommand.ts","../src/view/Reconciler.ts","../src/view/SelectionSync.ts","../src/view/EditorView.ts","../src/editor/Announcer.ts","../src/editor/DocumentParser.ts","../src/editor/DocumentSerializer.ts","../src/editor/styles/base.ts","../src/editor/styles.ts","../src/editor/styles/reduced-motion.ts","../src/editor/EditorThemeController.ts","../src/editor/NotectlEditor.ts","../src/editor/EditorDOM.ts"],"sourcesContent":["/**\n * SchemaRegistry: central registry for node specs, mark specs, node views,\n * keymaps, input rules, and toolbar items registered by plugins.\n */\n\nimport type { InputRule } from '../input/InputRule.js';\nimport type { Keymap } from '../input/Keymap.js';\nimport type { BlockTypePickerEntry } from '../plugins/heading/BlockTypePickerEntry.js';\nimport type { ToolbarItem } from '../plugins/toolbar/ToolbarItem.js';\nimport type { NodeViewFactory } from '../view/NodeView.js';\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\n/** Handler for files pasted or dropped into the editor. */\nexport type FileHandler = (\n\tfiles: readonly File[],\n\tposition: import('./Selection.js').Position | null,\n) => boolean | Promise<boolean>;\n\nexport interface FileHandlerEntry {\n\treadonly pattern: string;\n\treadonly handler: FileHandler;\n}\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\tprivate readonly _nodeViews = new Map<string, NodeViewFactory>();\n\tprivate readonly _keymaps: Keymap[] = [];\n\tprivate readonly _inputRules: InputRule[] = [];\n\tprivate readonly _toolbarItems = new Map<string, ToolbarItem>();\n\tprivate readonly _toolbarItemPluginMap = new Map<string, string[]>();\n\tprivate readonly _fileHandlers: FileHandlerEntry[] = [];\n\tprivate readonly _blockTypePickerEntries = new Map<string, BlockTypePickerEntry>();\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// --- NodeView ---\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\t// --- Keymap ---\n\n\tregisterKeymap(keymap: Keymap): void {\n\t\tfor (const key of Object.keys(keymap)) {\n\t\t\tfor (const existing of this._keymaps) {\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._keymaps.push(keymap);\n\t}\n\n\tgetKeymaps(): readonly Keymap[] {\n\t\treturn this._keymaps;\n\t}\n\n\tremoveKeymap(keymap: Keymap): void {\n\t\tconst idx = this._keymaps.indexOf(keymap);\n\t\tif (idx !== -1) this._keymaps.splice(idx, 1);\n\t}\n\n\t// --- 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\t// --- ToolbarItem ---\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\t// --- FileHandler ---\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\t// --- BlockTypePickerEntry ---\n\n\tregisterBlockTypePickerEntry(entry: BlockTypePickerEntry): void {\n\t\tif (this._blockTypePickerEntries.has(entry.id)) {\n\t\t\tthrow new Error(`BlockTypePickerEntry with id \"${entry.id}\" is already registered.`);\n\t\t}\n\t\tthis._blockTypePickerEntries.set(entry.id, entry);\n\t}\n\n\tgetBlockTypePickerEntries(): readonly BlockTypePickerEntry[] {\n\t\treturn [...this._blockTypePickerEntries.values()].sort((a, b) => a.priority - b.priority);\n\t}\n\n\tremoveBlockTypePickerEntry(id: string): void {\n\t\tthis._blockTypePickerEntries.delete(id);\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\tthis._nodeViews.clear();\n\t\tthis._keymaps.length = 0;\n\t\tthis._inputRules.length = 0;\n\t\tthis._toolbarItems.clear();\n\t\tthis._toolbarItemPluginMap.clear();\n\t\tthis._fileHandlers.length = 0;\n\t\tthis._blockTypePickerEntries.clear();\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 * 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 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 Mark,\n\ttype TextNode,\n\ttype TextSegment,\n\taddMarkToSet,\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgetBlockLength,\n\tgetInlineChildren,\n\tisBlockNode,\n\tisInlineNode,\n\tisTextNode,\n\tnormalizeInlineContent,\n\tremoveMarkFromSet,\n} from '../model/Document.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\t// Try at top level first\n\tconst blockIndex: number = doc.children.findIndex((b) => b.id === step.blockId);\n\n\tif (blockIndex !== -1) {\n\t\tconst block: BlockNode | undefined = doc.children[blockIndex];\n\t\tif (!block) return doc;\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 newChildren: BlockNode[] = [...doc.children];\n\t\tnewChildren.splice(blockIndex, 1, updatedBlock, newBlock);\n\t\treturn { children: newChildren };\n\t}\n\n\t// Recurse into block children\n\treturn {\n\t\tchildren: doc.children.map((child) => {\n\t\t\tconst mapped: BlockNode | null = splitBlockRecursive(child, step);\n\t\t\treturn mapped ?? child;\n\t\t}),\n\t};\n}\n\nfunction splitBlockRecursive(node: BlockNode, step: SplitBlockStep): BlockNode | null {\n\tconst idx: number = node.children.findIndex((c) => isBlockNode(c) && c.id === step.blockId);\n\tif (idx !== -1) {\n\t\tconst block: BlockNode = node.children[idx] 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 newChildren: ChildNode[] = [...node.children] as ChildNode[];\n\t\tnewChildren.splice(idx, 1, updatedBlock, newBlock);\n\t\treturn { ...node, children: newChildren };\n\t}\n\n\t// Recurse deeper\n\tlet changed = false;\n\tconst newChildren: ChildNode[] = node.children.map((child) => {\n\t\tif (!isBlockNode(child)) return child;\n\t\tconst mapped: BlockNode | null = splitBlockRecursive(child, step);\n\t\tif (mapped) {\n\t\t\tchanged = true;\n\t\t\treturn mapped;\n\t\t}\n\t\treturn child;\n\t});\n\n\treturn changed ? { ...node, children: newChildren } : null;\n}\n\nfunction applyMergeBlocks(doc: Document, step: MergeBlocksStep): Document {\n\t// Try at top level first\n\tconst targetIndex: number = doc.children.findIndex((b) => b.id === step.targetBlockId);\n\tconst sourceIndex: number = doc.children.findIndex((b) => b.id === step.sourceBlockId);\n\n\tif (targetIndex !== -1 && sourceIndex !== -1) {\n\t\tconst target: BlockNode | undefined = doc.children[targetIndex];\n\t\tconst source: BlockNode | undefined = doc.children[sourceIndex];\n\t\tif (!target || !source) return doc;\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 newChildren: readonly BlockNode[] = doc.children.filter(\n\t\t\t(b) => b.id !== step.sourceBlockId,\n\t\t);\n\t\treturn {\n\t\t\tchildren: newChildren.map((b) => (b.id === step.targetBlockId ? mergedBlock : b)),\n\t\t};\n\t}\n\n\t// Recurse into block children\n\treturn {\n\t\tchildren: doc.children.map((child) => {\n\t\t\tconst mapped: BlockNode | null = mergeBlocksRecursive(child, step);\n\t\t\treturn mapped ?? child;\n\t\t}),\n\t};\n}\n\nfunction mergeBlocksRecursive(node: BlockNode, step: MergeBlocksStep): BlockNode | null {\n\tconst targetIdx: number = node.children.findIndex(\n\t\t(c) => isBlockNode(c) && c.id === step.targetBlockId,\n\t);\n\tconst sourceIdx: number = node.children.findIndex(\n\t\t(c) => isBlockNode(c) && c.id === step.sourceBlockId,\n\t);\n\n\tif (targetIdx !== -1 && sourceIdx !== -1) {\n\t\tconst target: BlockNode = node.children[targetIdx] as BlockNode;\n\t\tconst source: BlockNode = node.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[] = node.children.filter(\n\t\t\t(c) => !isBlockNode(c) || c.id !== step.sourceBlockId,\n\t\t);\n\t\tconst result: ChildNode[] = filtered.map((c) =>\n\t\t\tisBlockNode(c) && c.id === step.targetBlockId ? mergedBlock : c,\n\t\t);\n\t\treturn { ...node, children: result };\n\t}\n\n\t// Recurse deeper\n\tlet changed = false;\n\tconst newChildren: ChildNode[] = node.children.map((child) => {\n\t\tif (!isBlockNode(child)) return child;\n\t\tconst mapped: BlockNode | null = mergeBlocksRecursive(child, step);\n\t\tif (mapped) {\n\t\t\tchanged = true;\n\t\t\treturn mapped;\n\t\t}\n\t\treturn child;\n\t});\n\n\treturn changed ? { ...node, children: newChildren } : null;\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\n// --- Helpers ---\n\nfunction mapBlock(doc: Document, blockId: string, fn: (block: BlockNode) => BlockNode): Document {\n\treturn {\n\t\tchildren: mapBlockInChildren(doc.children, blockId, fn) as BlockNode[],\n\t};\n}\n\nfunction 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 * Replaces the inline content children of a ChildNode array,\n * preserving any BlockNode children in their original positions.\n */\nfunction 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/**\n * Inserts text into mixed inline content at the given offset.\n * Handles both TextNode and InlineNode children.\n */\nfunction 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 */\nfunction 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 */\nfunction 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 */\nfunction 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 */\nfunction 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. */\nfunction 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. */\nfunction 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. */\nfunction 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\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/**\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 */\nfunction 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\nfunction 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 * 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}\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\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/** 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},\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\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(): object {\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 block\n\t\tconst firstBlock = doc.children[0];\n\t\tif (!firstBlock) return sel;\n\t\treturn createCollapsedSelection(firstBlock.id, 0);\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/** 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 * 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\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 * 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\tdeleteNodeSelection,\n\tinsertTextCommand,\n\tnavigateArrowIntoVoid,\n\tselectAll,\n\tsplitBlockCommand,\n} from '../commands/Commands.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { isNodeSelection } from '../model/Selection.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport type { DispatchFn, GetStateFn, RedoFn, UndoFn } from './InputHandler.js';\n\nexport interface KeyboardHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tundo: UndoFn;\n\tredo: RedoFn;\n\tschemaRegistry?: SchemaRegistry;\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 schemaRegistry?: SchemaRegistry;\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.schemaRegistry = options.schemaRegistry;\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// Handle NodeSelection keys before plugin keymaps\n\t\tif (this.handleNodeSelectionKeys(e)) return;\n\n\t\t// Handle arrow key navigation into void blocks\n\t\tif (this.handleArrowIntoVoid(e)) return;\n\n\t\t// Try plugin keymaps first (last registered has highest precedence)\n\t\tif (this.schemaRegistry) {\n\t\t\tconst descriptor = normalizeKeyDescriptor(e);\n\t\t\tconst keymaps = this.schemaRegistry.getKeymaps();\n\t\t\t// Iterate in reverse so later-registered keymaps take precedence\n\t\t\tfor (let i = keymaps.length - 1; i >= 0; i--) {\n\t\t\t\tconst handler = keymaps[i]?.[descriptor];\n\t\t\t\tif (handler?.()) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\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\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\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 * 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\t/** Handles arrow key navigation from text blocks into adjacent void blocks. */\n\tprivate handleArrowIntoVoid(e: KeyboardEvent): boolean {\n\t\tconst key = e.key;\n\t\tif (key !== 'ArrowLeft' && key !== 'ArrowRight' && key !== 'ArrowUp' && key !== 'ArrowDown') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Don't intercept modified arrows (selection extension, word jump)\n\t\tif (e.shiftKey || e.metaKey || e.ctrlKey || e.altKey) return false;\n\n\t\tconst state = this.getState();\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\n\t\tconst tr = navigateArrowIntoVoid(state, direction);\n\t\tif (tr) {\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\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 * 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 type { BlockNode, Mark } from '../model/Document.js';\nimport {\n\tgetBlockLength,\n\tgetBlockText,\n\tgetInlineChildren,\n\tisInlineNode,\n\tisTextNode,\n} 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 {\n\tisCollapsed,\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}\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 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\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// 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\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// 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 (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 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));\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(block: BlockNode, start: number, end: number): 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) {\n\t\t\t\t\tparts.push(this.serializeTextWithMarks(text, child.marks));\n\t\t\t\t}\n\t\t\t}\n\t\t\t// InlineNodes are skipped for text/html serialization (same as plain text)\n\n\t\t\tpos = childEnd;\n\t\t}\n\n\t\treturn parts.join('');\n\t}\n\n\t/** Wraps escaped text in mark HTML tags using MarkSpec.toHTMLString when available. */\n\tprivate serializeTextWithMarks(text: string, marks: readonly Mark[]): string {\n\t\tif (marks.length === 0 || !this.schemaRegistry) {\n\t\t\treturn escapeHTML(text);\n\t\t}\n\n\t\t// Sort marks by rank (lowest rank = closest to text content = applied first)\n\t\tconst sorted: readonly Mark[] = [...marks].sort((a, b) => {\n\t\t\tconst specA: MarkSpec | undefined = this.schemaRegistry?.getMarkSpec(a.type);\n\t\t\tconst specB: MarkSpec | undefined = this.schemaRegistry?.getMarkSpec(b.type);\n\t\t\treturn (specA?.rank ?? 100) - (specB?.rank ?? 100);\n\t\t});\n\n\t\tlet html: string = escapeHTML(text);\n\t\t// Apply marks from innermost (lowest rank) to outermost (highest rank)\n\t\tfor (const mark of sorted) {\n\t\t\tconst spec: MarkSpec | undefined = this.schemaRegistry?.getMarkSpec(mark.type);\n\t\t\tif (spec?.toHTMLString) {\n\t\t\t\thtml = spec.toHTMLString(mark, html);\n\t\t\t}\n\t\t}\n\t\treturn html;\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 * 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 { InputRule } from '../input/InputRule.js';\nimport type { Keymap } from '../input/Keymap.js';\nimport { type FileHandler, SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { EventBus } from './EventBus.js';\nimport type {\n\tCommandEntry,\n\tCommandHandler,\n\tMiddlewareNext,\n\tPlugin,\n\tPluginConfig,\n\tPluginContext,\n\tPluginEventBus,\n\tServiceKey,\n\tTransactionMiddleware,\n} from './Plugin.js';\n\nconst DEFAULT_PRIORITY = 100;\n\ninterface MiddlewareEntry {\n\tmiddleware: TransactionMiddleware;\n\tpriority: number;\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/** 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\tprivate middlewareSorted: MiddlewareEntry[] | null = null;\n\tprivate initOrder: string[] = [];\n\tprivate initialized = false;\n\tprivate initializing = false;\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 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/** Executes a named command. Returns false if command not found. */\n\texecuteCommand(name: string): boolean {\n\t\tconst entry = this.commands.get(name);\n\t\tif (!entry) return false;\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}\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 all registered plugin IDs. */\n\tgetPluginIds(): string[] {\n\t\treturn [...this.plugins.keys()];\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/** 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.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\t\tfor (const type of reg.nodeViews) this.schemaRegistry.removeNodeView(type);\n\t\tfor (const keymap of reg.keymaps) this.schemaRegistry.removeKeymap(keymap);\n\t\tfor (const rule of reg.inputRules) this.schemaRegistry.removeInputRule(rule);\n\t\tfor (const itemId of reg.toolbarItems) this.schemaRegistry.removeToolbarItem(itemId);\n\t\tfor (const handler of reg.fileHandlers) {\n\t\t\tthis.schemaRegistry.removeFileHandler(handler);\n\t\t}\n\t\tfor (const id of reg.blockTypePickerEntries) {\n\t\t\tthis.schemaRegistry.removeBlockTypePickerEntry(id);\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\n\t\t\tregisterCommand: (name: string, handler: CommandHandler) => {\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\tthis.commands.set(name, { name, handler, pluginId });\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, priority = DEFAULT_PRIORITY) => {\n\t\t\t\tconst entry: MiddlewareEntry = { 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.schemaRegistry.registerNodeView(type, factory);\n\t\t\t\treg.nodeViews.push(type);\n\t\t\t},\n\n\t\t\tregisterKeymap: (keymap) => {\n\t\t\t\tthis.schemaRegistry.registerKeymap(keymap);\n\t\t\t\treg.keymaps.push(keymap);\n\t\t\t},\n\n\t\t\tregisterInputRule: (rule) => {\n\t\t\t\tthis.schemaRegistry.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.schemaRegistry.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.schemaRegistry.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.schemaRegistry.registerBlockTypePickerEntry(entry);\n\t\t\t\treg.blockTypePickerEntries.push(entry.id);\n\t\t\t},\n\n\t\t\tgetSchemaRegistry: () => this.schemaRegistry,\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\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","/**\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\t// biome-ignore lint/suspicious/noExplicitAny: dynamic path resolution\n\tlet current: any = theme;\n\tfor (const part of parts) {\n\t\tif (current === undefined || current === null) return undefined;\n\t\tcurrent = current[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 * 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 type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { isNodeSelection } from '../model/Selection.js';\nimport type { Transaction } from '../state/Transaction.js';\n\nimport type { EditorState } from '../state/EditorState.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\tschemaRegistry?: SchemaRegistry;\n}\n\nexport class InputHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly syncSelection: SyncSelectionFn;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate composing = false;\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.schemaRegistry = options.schemaRegistry;\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\t// During composition, let the browser handle it\n\t\tif (this.composing && 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\tthis.composing = true;\n\t}\n\n\tprivate onCompositionEnd(e: CompositionEvent): void {\n\t\tthis.composing = false;\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.schemaRegistry) return;\n\t\tconst rules = this.schemaRegistry.getInputRules();\n\t\tif (rules.length === 0) return;\n\n\t\tconst state = this.getState();\n\t\tif (isNodeSelection(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 * 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 {\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 [\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\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\tmarks.push({ type: markType('bold') });\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\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 * 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 { schemaFromRegistry } from '../model/Schema.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\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 { DispatchFn, GetStateFn } from './InputHandler.js';\nimport { type RichBlockData, consumeRichClipboard } from './InternalClipboard.js';\n\nexport interface PasteHandlerOptions {\n\tgetState: GetStateFn;\n\tdispatch: DispatchFn;\n\tschemaRegistry?: SchemaRegistry;\n}\n\nexport class PasteHandler {\n\tprivate readonly getState: GetStateFn;\n\tprivate readonly dispatch: DispatchFn;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\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\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\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\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(html, {\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\tif (this.schemaRegistry && !this.schemaRegistry.getNodeSpec(typeName)) 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) ? sel.nodeId : sel.anchor.blockId;\n\n\t\tconst newBlockId: BlockId = generateBlockId();\n\t\tconst attrs: Record<string, string | number | boolean> | undefined = parsed.attrs\n\t\t\t? (parsed.attrs as Record<string, string | number | boolean>)\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 builder = state.transaction('paste');\n\t\tbuilder.insertNode(parentPath, index + 1, 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) ? sel.nodeId : 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 blockData of blocks) {\n\t\t\tif (!blockData.type) 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\tlet insertIndex: number = anchorIndex + 1;\n\t\tconst builder = state.transaction('paste');\n\t\tlet lastBlockId: BlockId | undefined;\n\t\tlet lastTextLen = 0;\n\n\t\tfor (const blockData of blocks) {\n\t\t\tif (!blockData.type) 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\n\t\tif (isAnchorEmpty) {\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/** 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.schemaRegistry) 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\tfor (const file of files) {\n\t\t\tconst handlers = this.schemaRegistry.matchFileHandlers(file.type);\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = handler(files, null);\n\t\t\t\tif (result === true) return true;\n\t\t\t\t// If handler returns a Promise, treat as handled\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t// Fire-and-forget for async handlers\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\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 * 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 { createBlockNode, createTextNode, generateBlockId } from '../model/Document.js';\nimport type { TextSegment } from '../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tisCollapsed,\n\tisNodeSelection,\n\tselectionRange,\n} from '../model/Selection.js';\nimport { nodeType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction, TransactionBuilder } from '../state/Transaction.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\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tconst range = isCollapsed(sel) ? null : selectionRange(sel, state.getBlockOrder());\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst insertBlockId = range ? range.from.blockId : sel.anchor.blockId;\n\tconst insertOffset: number = range ? range.from.offset : sel.anchor.offset;\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\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tconst range = isCollapsed(sel) ? null : selectionRange(sel, state.getBlockOrder());\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst insertBlockId = range ? range.from.blockId : sel.anchor.blockId;\n\tconst insertOffset: number = range ? range.from.offset : sel.anchor.offset;\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\tconst builder: TransactionBuilder = state.transaction('paste');\n\n\tconst range = isCollapsed(sel) ? null : selectionRange(sel, state.getBlockOrder());\n\n\tif (!isCollapsed(sel)) {\n\t\taddDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst blockId = range ? range.from.blockId : sel.anchor.blockId;\n\tconst offset: number = range ? range.from.offset : sel.anchor.offset;\n\tconst blockOrder = state.getBlockOrder();\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 * 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 { MarkAttrsFor, NodeAttrsFor } from '../model/AttrRegistry.js';\nimport type { BlockNode, InlineNode, Mark, 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 type { NodeView } from './NodeView.js';\n\nexport interface ReconcileOptions {\n\tregistry?: SchemaRegistry;\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}\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\tunwrapBlocks(container);\n\n\tconst oldBlockMap = new Map<BlockId, HTMLElement>();\n\tfor (const child of Array.from(container.children)) {\n\t\tconst el = child as HTMLElement;\n\t\tconst bid = el.getAttribute('data-block-id');\n\t\tif (bid) {\n\t\t\toldBlockMap.set(toBlockId(bid), el);\n\t\t}\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\tcontainer.removeChild(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\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\tcontainer.replaceChild(newEl, existingEl);\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\tif (previousSibling?.nextSibling) {\n\t\t\t\tcontainer.insertBefore(newEl, previousSibling.nextSibling);\n\t\t\t} else if (!previousSibling && container.firstChild) {\n\t\t\t\tcontainer.insertBefore(newEl, container.firstChild);\n\t\t\t} else {\n\t\t\t\tcontainer.appendChild(newEl);\n\t\t\t}\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\twrapBlocks(container, newBlocks, registry);\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\tif (registry && nodeViews && options?.getState && options?.dispatch) {\n\t\tconst factory = registry.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\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\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\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\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) => markOrder(a, registry) - markOrder(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\nfunction markOrder(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\t// Fallback order for built-in marks\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\nfunction 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}\n\t// Fallback for built-in marks\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// --- 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) => markOrder(a, registry) - markOrder(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 * Selection synchronization between editor state and DOM.\n */\n\nimport type { EditorSelection, Position, Selection } from '../model/Selection.js';\nimport { createPosition, createSelection, isNodeSelection } from '../model/Selection.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport { blockId as toBlockId } from '../model/TypeBrands.js';\n\ninterface DOMPosition {\n\tnode: Node;\n\toffset: number;\n}\n\n/** Gets the selection object, preferring shadow root's selection for Shadow DOM. */\nfunction getSelection(container: HTMLElement): globalThis.Selection | null {\n\tconst root = container.getRootNode();\n\tif (root instanceof ShadowRoot && 'getSelection' in root) {\n\t\treturn (root as ShadowRoot & { getSelection(): globalThis.Selection | null }).getSelection();\n\t}\n\treturn window.getSelection();\n}\n\n/** Syncs the editor state selection to the DOM. */\nexport function syncSelectionToDOM(container: HTMLElement, selection: EditorSelection): void {\n\tconst domSel = getSelection(container);\n\tif (!domSel) return;\n\n\t// NodeSelection: select the entire block element\n\tif (isNodeSelection(selection)) {\n\t\tconst blockEl = container.querySelector(`[data-block-id=\"${selection.nodeId}\"]`);\n\t\tif (!blockEl) return;\n\t\tconst parent = blockEl.parentNode;\n\t\tif (!parent) return;\n\t\tconst childIdx = childIndexOf(parent, blockEl);\n\t\ttry {\n\t\t\tdomSel.setBaseAndExtent(parent, childIdx, parent, childIdx + 1);\n\t\t} catch {\n\t\t\t// Selection may fail if DOM is not yet rendered\n\t\t}\n\t\treturn;\n\t}\n\n\tconst anchorPos = statePositionToDOM(container, selection.anchor);\n\tconst headPos = statePositionToDOM(container, selection.head);\n\n\tif (!anchorPos || !headPos) return;\n\n\ttry {\n\t\tdomSel.setBaseAndExtent(anchorPos.node, anchorPos.offset, headPos.node, headPos.offset);\n\t} catch {\n\t\t// Selection may fail if DOM is not yet rendered\n\t}\n}\n\n/** Reads the current DOM selection and converts it to a state selection. */\nexport function readSelectionFromDOM(container: HTMLElement): Selection | null {\n\tconst domSel = getSelection(container);\n\tif (!domSel || domSel.rangeCount === 0) return null;\n\n\tconst anchorNode = domSel.anchorNode;\n\tconst focusNode = domSel.focusNode;\n\n\tif (!anchorNode || !focusNode) return null;\n\tif (!container.contains(anchorNode) || !container.contains(focusNode)) return null;\n\n\tconst anchor = domPositionToState(container, anchorNode, domSel.anchorOffset);\n\tconst head = domPositionToState(container, focusNode, domSel.focusOffset);\n\n\tif (!anchor || !head) return null;\n\n\treturn createSelection(anchor, head);\n}\n\n/** Converts a state position (blockId + offset) to a DOM position (node + offset). */\nfunction statePositionToDOM(container: HTMLElement, pos: Position): DOMPosition | null {\n\t// If path is available, navigate directly to the leaf block\n\tlet blockEl: Element | null = null;\n\tif (pos.path && pos.path.length > 0) {\n\t\tlet current: Element = container;\n\t\tfor (const id of pos.path) {\n\t\t\tconst found = current.querySelector(`:scope [data-block-id=\"${id}\"]`);\n\t\t\tif (!found) break;\n\t\t\tcurrent = found;\n\t\t}\n\t\tif (current !== container && current.getAttribute('data-block-id') === pos.blockId) {\n\t\t\tblockEl = current;\n\t\t}\n\t}\n\tblockEl ??= container.querySelector(`[data-block-id=\"${pos.blockId}\"]`);\n\tif (!blockEl) return null;\n\n\t// Use contentDOM if available (NodeView blocks like code_block)\n\tconst contentEl: Element = resolveContentRoot(blockEl);\n\n\t// Handle empty paragraphs with <br>\n\tif (contentEl.childNodes.length === 1 && contentEl.firstChild?.nodeName === 'BR') {\n\t\treturn { node: contentEl, offset: 0 };\n\t}\n\n\t// Walk through text nodes and inline elements to find the correct position\n\tlet remaining = pos.offset;\n\tconst walker = createInlineContentWalker(contentEl);\n\n\tlet current = walker.nextNode();\n\twhile (current) {\n\t\tif (current.nodeType === Node.TEXT_NODE) {\n\t\t\tconst len = current.textContent?.length ?? 0;\n\t\t\tif (remaining <= len) {\n\t\t\t\treturn { node: current, offset: remaining };\n\t\t\t}\n\t\t\tremaining -= len;\n\t\t} else if (\n\t\t\tcurrent instanceof HTMLElement &&\n\t\t\tcurrent.getAttribute('contenteditable') === 'false'\n\t\t) {\n\t\t\t// InlineNode element — width 1 in state offset space\n\t\t\tif (remaining === 0) {\n\t\t\t\t// Position before this inline element\n\t\t\t\tconst parent = current.parentNode;\n\t\t\t\tif (parent) {\n\t\t\t\t\tconst childIndex = childIndexOf(parent, current);\n\t\t\t\t\treturn { node: parent, offset: childIndex };\n\t\t\t\t}\n\t\t\t}\n\t\t\tremaining -= 1;\n\t\t}\n\t\tcurrent = walker.nextNode();\n\t}\n\n\t// Fallback: position at end of block\n\tconst lastChild = contentEl.lastChild;\n\tif (lastChild) {\n\t\tif (lastChild.nodeType === Node.TEXT_NODE) {\n\t\t\treturn { node: lastChild, offset: lastChild.textContent?.length ?? 0 };\n\t\t}\n\t\treturn { node: contentEl, offset: contentEl.childNodes.length };\n\t}\n\n\treturn { node: contentEl, offset: 0 };\n}\n\n/** Converts a DOM position to a state position, including nested path. */\nexport function domPositionToState(\n\tcontainer: HTMLElement,\n\tnode: Node,\n\tdomOffset: number,\n): Position | null {\n\t// Find the innermost block element\n\tconst blockEl = findBlockElement(container, node);\n\tif (!blockEl) return null;\n\n\tconst rawBlockId = blockEl.getAttribute('data-block-id');\n\tif (!rawBlockId) return null;\n\tconst bid = toBlockId(rawBlockId);\n\n\t// Build path by collecting all data-block-id ancestors from leaf to root\n\tconst path = buildBlockPath(container, blockEl);\n\n\t// Use contentDOM if available (NodeView blocks like code_block)\n\tconst contentEl: Element = resolveContentRoot(blockEl);\n\n\t// Handle clicks on the block or content element itself (e.g. empty paragraph with <br>)\n\tif (node === blockEl || node === contentEl) {\n\t\tconst targetEl: Element = node === contentEl ? contentEl : blockEl;\n\t\tlet childOffset = 0;\n\t\tlet childIdx = 0;\n\t\tfor (const child of Array.from(targetEl.childNodes)) {\n\t\t\tif (childIdx >= domOffset) break;\n\t\t\tchildOffset += inlineContentWidth(child);\n\t\t\tchildIdx++;\n\t\t}\n\t\treturn createPosition(bid, childOffset, path.length > 1 ? path : undefined);\n\t}\n\n\t// If node is outside the contentDOM (e.g. in NodeView header), map to offset 0\n\tif (contentEl !== blockEl && !contentEl.contains(node)) {\n\t\treturn createPosition(bid, 0, path.length > 1 ? path : undefined);\n\t}\n\n\t// Calculate offset by walking text nodes and inline elements\n\tlet offset = 0;\n\tconst walker = createInlineContentWalker(contentEl);\n\n\tlet walkerNode = walker.nextNode();\n\twhile (walkerNode) {\n\t\tif (walkerNode === node) {\n\t\t\tif (walkerNode.nodeType === Node.TEXT_NODE) {\n\t\t\t\treturn createPosition(bid, offset + domOffset, path.length > 1 ? path : undefined);\n\t\t\t}\n\t\t\t// Node is an inline element — return offset at its start\n\t\t\treturn createPosition(bid, offset, path.length > 1 ? path : undefined);\n\t\t}\n\t\tif (walkerNode.nodeType === Node.TEXT_NODE) {\n\t\t\toffset += walkerNode.textContent?.length ?? 0;\n\t\t} else if (\n\t\t\twalkerNode instanceof HTMLElement &&\n\t\t\twalkerNode.getAttribute('contenteditable') === 'false'\n\t\t) {\n\t\t\toffset += 1;\n\t\t}\n\t\twalkerNode = walker.nextNode();\n\t}\n\n\t// If the node is not a text node, try to find the offset from element context\n\tif (node.nodeType === Node.ELEMENT_NODE) {\n\t\tlet childOffset = 0;\n\t\tlet childIdx = 0;\n\n\t\tfor (const child of Array.from(node.childNodes)) {\n\t\t\tif (childIdx >= domOffset) break;\n\t\t\tchildOffset += inlineContentWidth(child);\n\t\t\tchildIdx++;\n\t\t}\n\n\t\treturn createPosition(bid, childOffset, path.length > 1 ? path : undefined);\n\t}\n\n\treturn createPosition(bid, 0, path.length > 1 ? path : undefined);\n}\n\n/** Builds an array of block IDs from root to leaf by walking up from a block element. */\nfunction buildBlockPath(container: HTMLElement, leafBlockEl: HTMLElement): BlockId[] {\n\tconst path: BlockId[] = [];\n\tlet current: HTMLElement | null = leafBlockEl;\n\n\twhile (current && current !== container) {\n\t\tif (current.hasAttribute('data-block-id')) {\n\t\t\tpath.unshift(toBlockId(current.getAttribute('data-block-id') ?? ''));\n\t\t}\n\t\tcurrent = current.parentElement;\n\t}\n\n\treturn path;\n}\n\n/** Finds the closest block element ancestor. */\nfunction findBlockElement(container: HTMLElement, node: Node): HTMLElement | null {\n\tlet current: Node | null = node;\n\twhile (current && current !== container) {\n\t\tif (current instanceof HTMLElement && current.hasAttribute('data-block-id')) {\n\t\t\treturn current;\n\t\t}\n\t\tcurrent = current.parentNode;\n\t}\n\treturn null;\n}\n\n/** Checks if a node is inside a contentEditable=\"false\" inline element. */\nfunction isInsideInlineElement(node: Node, root: Element): boolean {\n\tlet parent: Node | null = node.parentNode;\n\twhile (parent && parent !== root) {\n\t\tif (parent instanceof HTMLElement && parent.getAttribute('contenteditable') === 'false') {\n\t\t\treturn true;\n\t\t}\n\t\tparent = parent.parentNode;\n\t}\n\treturn false;\n}\n\n/**\n * Creates a TreeWalker that visits text nodes and contentEditable=\"false\"\n * inline elements within a block, skipping mark wrappers and nested blocks.\n */\nfunction createInlineContentWalker(blockEl: Element): TreeWalker {\n\treturn document.createTreeWalker(blockEl, NodeFilter.SHOW_ALL, {\n\t\tacceptNode: (n: Node) => {\n\t\t\t// Skip anything inside an inline element (contentEditable=\"false\")\n\t\t\tif (isInsideInlineElement(n, blockEl)) return NodeFilter.FILTER_REJECT;\n\t\t\t// Skip nested block elements and their descendants\n\t\t\tif (n instanceof HTMLElement && n.hasAttribute('data-block-id') && n !== blockEl) {\n\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t}\n\t\t\t// Accept text nodes\n\t\t\tif (n.nodeType === Node.TEXT_NODE) return NodeFilter.FILTER_ACCEPT;\n\t\t\t// Accept inline elements (contentEditable=\"false\")\n\t\t\tif (n instanceof HTMLElement && n.getAttribute('contenteditable') === 'false') {\n\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t}\n\t\t\t// Skip other elements (mark wrappers, decoration wrappers) — descend\n\t\t\treturn NodeFilter.FILTER_SKIP;\n\t\t},\n\t});\n}\n\n/** Returns the child index of a node within its parent. */\nfunction childIndexOf(parent: Node, child: Node): number {\n\tlet idx = 0;\n\tfor (const c of Array.from(parent.childNodes)) {\n\t\tif (c === child) return idx;\n\t\tidx++;\n\t}\n\treturn idx;\n}\n\n/**\n * Resolves the content root for inline content walking.\n * If the block element has a contentDOM (marked with data-content-dom),\n * returns it so the walker skips NodeView structural elements (headers, etc.).\n */\nfunction resolveContentRoot(blockEl: Element): Element {\n\tconst contentDOM: Element | null = blockEl.querySelector('[data-content-dom]');\n\treturn contentDOM ?? blockEl;\n}\n\n/** Counts the inline content width of a DOM node (text length + 1 per inline element). */\nfunction inlineContentWidth(node: Node): number {\n\tif (node.nodeType === Node.TEXT_NODE) {\n\t\treturn node.textContent?.length ?? 0;\n\t}\n\tif (node instanceof HTMLElement && node.getAttribute('contenteditable') === 'false') {\n\t\treturn 1;\n\t}\n\t// Mark wrapper or other element — sum children\n\tlet width = 0;\n\tfor (const child of Array.from(node.childNodes)) {\n\t\twidth += inlineContentWidth(child);\n\t}\n\treturn width;\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 { InputHandler } from '../input/InputHandler.js';\nimport { KeyboardHandler } from '../input/KeyboardHandler.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\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 type { NodeView } from './NodeView.js';\nimport { 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\tmaxHistoryDepth?: number;\n\tonStateChange?: StateChangeCallback;\n\tgetDecorations?: (state: EditorState, tr?: Transaction) => DecorationSet;\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 isUpdating = false;\n\tprivate pendingNodeSelectionClear = false;\n\tprivate readonly schemaRegistry?: SchemaRegistry;\n\tprivate readonly nodeViews = new Map<string, NodeView>();\n\tprivate decorations: DecorationSet = DecorationSet.empty;\n\tprivate readonly getDecorations?: (state: EditorState, tr?: Transaction) => DecorationSet;\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.getDecorations = options.getDecorations;\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\tschemaRegistry: this.schemaRegistry,\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\tschemaRegistry: this.schemaRegistry,\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});\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});\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\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\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});\n\t\t\tsyncSelectionToDOM(this.contentElement, newState.selection);\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} 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\t// Guard needed here: history.undo() mutates stacks before applyUpdate runs\n\t\tif (this.isUpdating) 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\t// Guard needed here: history.redo() mutates stacks before applyUpdate runs\n\t\tif (this.isUpdating) 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});\n\t\t\tsyncSelectionToDOM(this.contentElement, newState.selection);\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// If NodeSelection 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\tthis.pendingNodeSelectionClear = 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\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 is active,\n\t\t\t// allow the next syncSelectionFromDOM to override the NodeSelection\n\t\t\tif (isNodeSelection(this.state.selection)) {\n\t\t\t\tthis.pendingNodeSelectionClear = 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\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\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.schemaRegistry) 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.schemaRegistry) 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\tfor (const file of files) {\n\t\t\tconst handlers = this.schemaRegistry.matchFileHandlers(file.type);\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = handler(files, position);\n\t\t\t\tif (result === true) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\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\n\t\tlet domNode: Node | null = null;\n\t\tlet domOffset = 0;\n\n\t\t// Standard API (caretPositionFromPoint)\n\t\tif ('caretPositionFromPoint' in root) {\n\t\t\tconst cp = (root as Document).caretPositionFromPoint(x, y);\n\t\t\tif (cp) {\n\t\t\t\tdomNode = cp.offsetNode;\n\t\t\t\tdomOffset = cp.offset;\n\t\t\t}\n\t\t}\n\n\t\t// Fallback (caretRangeFromPoint)\n\t\tif (!domNode && 'caretRangeFromPoint' in root) {\n\t\t\tconst range = (root as Document).caretRangeFromPoint(x, y);\n\t\t\tif (range) {\n\t\t\t\tdomNode = range.startContainer;\n\t\t\t\tdomOffset = range.startOffset;\n\t\t\t}\n\t\t}\n\n\t\tif (!domNode) return null;\n\t\tif (!this.contentElement.contains(domNode)) return null;\n\n\t\treturn domPositionToState(this.contentElement, domNode, domOffset);\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(oldSelection?: import('../model/Selection.js').EditorSelection) {\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\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/** Cleans up all event listeners and handlers. */\n\tdestroy(): void {\n\t\tthis.inputHandler.destroy();\n\t\tthis.keyboardHandler.destroy();\n\t\tthis.pasteHandler.destroy();\n\t\tthis.clipboardHandler.destroy();\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// 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","/**\n * Announcer: builds screen-reader announcement text for editor state changes.\n * Pure functions — no DOM mutation. The caller applies the result to a live region.\n */\n\nimport { isMarkActive } from '../commands/Commands.js';\nimport { markType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\n\nconst BLOCK_TYPE_LABELS: Record<string, string> = {\n\tparagraph: 'Paragraph',\n\theading: 'Heading',\n\tcode_block: 'Code Block',\n\tblockquote: 'Block Quote',\n\tlist_item: 'List Item',\n\thorizontal_rule: 'Horizontal Rule',\n\timage: 'Image',\n\ttable: 'Table',\n};\n\n/** Returns a human-readable label for a block type (used in screen reader announcements). */\nexport function getBlockTypeLabel(typeName: string, attrs?: Record<string, unknown>): string {\n\tif (typeName === 'heading' && attrs?.level) {\n\t\treturn `Heading ${attrs.level}`;\n\t}\n\treturn BLOCK_TYPE_LABELS[typeName] ?? typeName;\n}\n\n/**\n * Derives an announcement string from a state transition.\n * Returns `null` when no announcement is warranted.\n *\n * Priority order: undo/redo > block-type change > mark toggle.\n */\nexport function buildAnnouncement(\n\toldState: EditorState,\n\tnewState: EditorState,\n\ttr: Transaction,\n): string | null {\n\t// Priority 1: Undo/Redo\n\tif (tr.metadata.historyDirection === 'undo') return 'Undo';\n\tif (tr.metadata.historyDirection === 'redo') return 'Redo';\n\n\t// Priority 2: Block type changes\n\tfor (const step of tr.steps) {\n\t\tif (step.type === 'setBlockType') {\n\t\t\treturn getBlockTypeLabel(step.nodeType, step.attrs);\n\t\t}\n\t}\n\n\t// Priority 3: Mark changes\n\tfor (const mt of newState.schema.markTypes) {\n\t\tconst branded = markType(mt);\n\t\tconst wasActive: boolean = isMarkActive(oldState, branded);\n\t\tconst nowActive: boolean = isMarkActive(newState, branded);\n\t\tif (wasActive !== nowActive) {\n\t\t\treturn `${mt} ${nowActive ? 'on' : 'off'}`;\n\t\t}\n\t}\n\n\treturn null;\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, Mark, TextNode } from '../model/Document.js';\nimport { createBlockNode, createDocument, createTextNode } from '../model/Document.js';\nimport type { ParseRule } from '../model/ParseRule.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport { markType, nodeType } from '../model/TypeBrands.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\tfor (const li of Array.from(el.querySelectorAll('li'))) {\n\t\t\t\t\tconst textNodes: TextNode[] = parseElementToTextNodes(li as HTMLElement, registry);\n\t\t\t\t\tblocks.push(\n\t\t\t\t\t\tcreateBlockNode(nodeType('list_item'), textNodes, undefined, {\n\t\t\t\t\t\t\tlistType,\n\t\t\t\t\t\t\tindent: 0,\n\t\t\t\t\t\t\tchecked: false,\n\t\t\t\t\t\t}),\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// Try block parse rules\n\t\t\tconst match = matchBlockParseRule(el, blockRules);\n\t\t\tif (match) {\n\t\t\t\tconst textNodes: TextNode[] = parseElementToTextNodes(el, registry);\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\ttextNodes,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tmatch.attrs as Record<string, string | number | boolean> | 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 textNodes: TextNode[] = parseElementToTextNodes(el, registry);\n\t\t\tblocks.push(createBlockNode(nodeType('paragraph'), textNodes));\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/** Parses an HTML element's children into TextNode[], applying mark parse rules. */\nfunction parseElementToTextNodes(el: HTMLElement, registry?: SchemaRegistry): TextNode[] {\n\tconst result: TextNode[] = [];\n\tconst markRules = registry?.getMarkParseRules() ?? [];\n\twalkElement(el, [], result, markRules);\n\treturn result.length > 0 ? result : [createTextNode('')];\n}\n\n/** Recursively walks DOM nodes, collecting marks from parse rules and producing TextNodes. */\nfunction walkElement(\n\tnode: Node,\n\tcurrentMarks: Mark[],\n\tresult: TextNode[],\n\tmarkRules: readonly { readonly rule: ParseRule; readonly type: string }[],\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\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);\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 * 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, Mark, TextNode } from '../model/Document.js';\nimport { getInlineChildren, isInlineNode } from '../model/Document.js';\nimport { escapeHTML } from '../model/HTMLUtils.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\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 parts: string[] = [];\n\tlet currentListTag: string | null = null;\n\n\tfor (const block of doc.children) {\n\t\tif (isNodeOfType(block, 'list_item')) {\n\t\t\tconst listType = block.attrs.listType;\n\t\t\tconst tag: string = listType === 'ordered' ? 'ol' : 'ul';\n\n\t\t\tif (currentListTag !== tag) {\n\t\t\t\tif (currentListTag) parts.push(`</${currentListTag}>`);\n\t\t\t\tparts.push(`<${tag}>`);\n\t\t\t\tcurrentListTag = tag;\n\t\t\t}\n\n\t\t\tparts.push(serializeBlock(block, registry));\n\t\t} else {\n\t\t\tif (currentListTag) {\n\t\t\t\tparts.push(`</${currentListTag}>`);\n\t\t\t\tcurrentListTag = null;\n\t\t\t}\n\t\t\tparts.push(serializeBlock(block, registry));\n\t\t}\n\t}\n\n\tif (currentListTag) parts.push(`</${currentListTag}>`);\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(parts.join(''), {\n\t\tALLOWED_TAGS: allowedTags,\n\t\tALLOWED_ATTR: allowedAttrs,\n\t});\n}\n\n/** Serializes a single block to HTML using its NodeSpec. */\nfunction serializeBlock(block: BlockNode, registry?: SchemaRegistry): string {\n\tconst inlineContent: string = serializeInlineContent(block, registry);\n\tconst spec = registry?.getNodeSpec(block.type);\n\n\tlet html: string;\n\tif (spec?.toHTML) {\n\t\thtml = spec.toHTML(block, inlineContent);\n\t} else {\n\t\thtml = `<p>${inlineContent || '<br>'}</p>`;\n\t}\n\n\t// Inject align style into the first opening tag\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') {\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 parts: string[] = [];\n\n\tfor (const child of children) {\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 {\n\t\t\tparts.push(serializeTextNode(child, registry));\n\t\t}\n\t}\n\n\treturn parts.join('');\n}\n\n/** Serializes a text node, wrapping it with mark tags sorted by rank. */\nfunction serializeTextNode(node: TextNode, registry?: SchemaRegistry): string {\n\tif (node.text === '') return '';\n\n\tlet html: string = escapeHTML(node.text);\n\n\tconst markOrder: Map<string, number> = getMarkOrder(registry);\n\tconst sortedMarks: Mark[] = [...node.marks].sort(\n\t\t(a, b) => (markOrder.get(a.type) ?? 99) - (markOrder.get(b.type) ?? 99),\n\t);\n\n\tfor (const mark of sortedMarks) {\n\t\tconst markSpec = 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/** Builds a map of mark type name to rank from the registry. */\nfunction getMarkOrder(registry?: SchemaRegistry): Map<string, number> {\n\tif (!registry) return new Map();\n\tconst types = registry.getMarkTypes();\n\tconst order = new Map<string, number>();\n\tfor (const t of types) {\n\t\tconst spec = registry.getMarkSpec(t);\n\t\tif (spec) order.set(t, spec.rank ?? 99);\n\t}\n\treturn order;\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 { 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].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","/**\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 * NotectlEditor Web Component — the public-facing editor element.\n */\n\nimport { selectAll } from '../commands/Commands.js';\nimport { DecorationSet } from '../decorations/Decoration.js';\nimport { registerBuiltinSpecs } from '../model/BuiltinSpecs.js';\nimport { type Document, getBlockText } from '../model/Document.js';\nimport { isMarkAllowed, schemaFromRegistry } from '../model/Schema.js';\nimport { createCollapsedSelection, selectionsEqual } from '../model/Selection.js';\nimport { blockId } from '../model/TypeBrands.js';\nimport type { Plugin, PluginConfig } from '../plugins/Plugin.js';\nimport { PluginManager } from '../plugins/PluginManager.js';\nimport { TextFormattingPlugin } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport type { TextFormattingConfig } from '../plugins/text-formatting/TextFormattingPlugin.js';\nimport { ToolbarPlugin } from '../plugins/toolbar/ToolbarPlugin.js';\nimport type { ToolbarLayoutConfig } from '../plugins/toolbar/ToolbarPlugin.js';\nimport { EditorState } from '../state/EditorState.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 { type Theme, ThemePreset } from './theme/ThemeTokens.js';\n\nexport interface NotectlEditorConfig {\n\t/** Controls which inline marks are enabled. Used to auto-configure TextFormattingPlugin. */\n\tfeatures?: Partial<TextFormattingConfig>;\n\tplugins?: Plugin[];\n\t/**\n\t * Declarative toolbar layout. Each inner array is a visual group;\n\t * separators are rendered between groups. Order = array order.\n\t * When set, a ToolbarPlugin is created internally — do not add one to `plugins`.\n\t */\n\ttoolbar?: ReadonlyArray<ReadonlyArray<Plugin>>;\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}\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\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'];\n\t}\n\n\tconnectedCallback(): void {\n\t\tif (this.initialized) return;\n\t\tthis.init();\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tthis.destroy();\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}\n\t\tif (name === 'theme' && this.themeController) {\n\t\t\tthis.themeController.apply((newValue as ThemePreset) ?? ThemePreset.Light);\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// 2. Create PluginManager (SchemaRegistry is available)\n\t\tthis.pluginManager = new PluginManager();\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 TextFormattingPlugin if none was explicitly provided\n\t\tthis.ensureTextFormattingPlugin();\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\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\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});\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\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// --- 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\tgetHTML(): string {\n\t\tif (!this.view) throw new Error('Editor not initialized');\n\t\treturn serializeDocumentToHTML(this.view.getState().doc, this.pluginManager?.schemaRegistry);\n\t}\n\n\t/** Sets content from HTML (sanitized). */\n\tsetHTML(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: () => this.view?.undo(),\n\t\tredo: () => this.view?.redo(),\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} {\n\t\tconst schema = this.view?.getState().schema;\n\t\treturn {\n\t\t\ttoggleBold: () => (schema ? isMarkAllowed(schema, 'bold') : false),\n\t\t\ttoggleItalic: () => (schema ? isMarkAllowed(schema, 'italic') : false),\n\t\t\ttoggleUnderline: () => (schema ? isMarkAllowed(schema, 'underline') : false),\n\t\t\tundo: () => this.view?.history.canUndo() ?? false,\n\t\t\tredo: () => this.view?.history.canRedo() ?? false,\n\t\t};\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// --- 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\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}\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/** Cleans up the editor. Awaiting ensures async plugin teardown completes. */\n\tdestroy(): Promise<void> {\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\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 */\n\tprivate processToolbarConfig(): void {\n\t\tif (!this.pluginManager || !this.config.toolbar) return;\n\n\t\tconst groups: string[][] = [];\n\t\tfor (const group of this.config.toolbar) {\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 };\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\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\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\n\t// Screen reader announcer\n\tconst announcer: HTMLElement = document.createElement('div');\n\tannouncer.className = 'notectl-sr-only';\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"],"names":["SchemaRegistry","_nodeSpecs","Map","_markSpecs","_inlineNodeSpecs","_nodeViews","_keymaps","_inputRules","_toolbarItems","_toolbarItemPluginMap","_fileHandlers","_blockTypePickerEntries","spec","this","has","type","Error","set","get","delete","getNodeTypes","keys","getMarkTypes","getInlineNodeTypes","factory","keymap","key","Object","existing","console","debug","push","getKeymaps","idx","indexOf","splice","rule","getInputRules","item","pluginId","id","ids","items","getToolbarItems","values","length","pattern","handler","getFileHandlers","mimeType","handlers","entry","matchMimePattern","findIndex","e","getBlockTypePickerEntries","sort","a","b","priority","getBlockParseRules","results","parseHTML","getInlineParseRules","getMarkParseRules","getAllowedTags","tags","Set","sanitize","tag","add","getAllowedAttrs","attrs","attr","clear","endsWith","prefix","slice","startsWith","canContain","registry","parentType","childType","parentSpec","getNodeSpec","content","childSpec","childGroup","group","allowed","allow","validateContent","childTypes","min","max","Number","POSITIVE_INFINITY","blockChildTypes","filter","t","registerBuiltinSpecs","registerNodeSpec","toDOM","node","createBlockElement","toHTML","_node","applyStep","doc","step","mapBlock","blockId","block","inlineChildren","getInlineChildren","newChildren","segments","nodes","offset","result","pos","inserted","isInlineNode","seg","createTextNode","text","marks","nodeEnd","localOffset","before","after","children","replaceInlineChildren","normalizeInlineContent","from","to","deleteFrom","Math","deleteTo","remaining","blockIndex","len","getBlockLength","nodesBeforeSplit","sliceInlineContent","nodesAfterSplit","updatedBlock","newBlock","createBlockNode","newBlockId","map","child","splitBlockRecursive","targetIndex","targetBlockId","sourceIndex","sourceBlockId","target","source","targetInline","sourceInline","mergedChildren","mergedBlock","mergeBlocksRecursive","applyMarkToInlineContent","mark","nodeType","parentPath","index","mapNodeByPath","parent","nodeId","path","inlineNode","c","isBlockNode","changed","mapped","targetIdx","sourceIdx","fn","mapBlockInChildren","mappedChildren","original","newInlineChildren","every","isTextNode","blockChildren","sliceFrom","sliceTo","newMarks","addMarkToSet","removeMarkFromSet","overlapStart","overlapEnd","beforeText","insideText","afterText","rootId","mapNodeByPathRecursive","depth","targetId","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","currentSelection","currentStoredMarks","advanceDoc","findNode","getBlockSegmentsInRange","getBlockText","getBlockMarksAtOffset","deleteText","targetBlock","mergeBlocks","resolveNodeByPath","join","getContentAtOffset","kind","createNodeSelection","build","EditorState","schema","_blockMap","_blockOrder","options","defaultSchema","createDocument","firstBlock","createCollapsedSelection","sel","isNodeSelection","anchor","validatePosition","head","createSelection","walk","blocks","getBlockOrder","order","isLeafBlock","findNodePath","parentId","toJSON","json","createPosition","HistoryManager","undoStack","redoStack","groupTimeoutMs","maxDepth","lastOrigin","lastGroup","isSameInputType","transactions","shift","state","pop","currentState","allSteps","i","inverted","apply","transaction","historyDirection","canUndo","canRedo","incoming","lastTr","lastStepType","incomingStepType","KeyboardHandler","element","getState","dispatch","undo","redo","schemaRegistry","handleKeydown","onKeydown","bind","addEventListener","handleNodeSelectionKeys","handleArrowIntoVoid","descriptor","normalizeKeyDescriptor","keymaps","preventDefault","handleTab","handleEscape","metaKey","ctrlKey","toLowerCase","shiftKey","selectAll","altKey","navigateArrowIntoVoid","deleteNodeSelection","splitBlockCommand","insertTextCommand","blur","destroy","removeEventListener","parts","toUpperCase","current","ClipboardHandler","syncSelection","handleCopy","onCopy","handleCut","onCut","isTextSelection","isCollapsed","clipboardData","writeNodeSelectionToClipboard","writeTextSelectionToClipboard","deleteSelectionCommand","getBlock","blockData","setData","JSON","stringify","altText","alt","blockOrder","range","selectionRange","fromIdx","toIdx","lines","richBlocks","bid","blockLen","start","end","sliced","plainText","htmlParts","serializeBlockRangeToHTML","childEnd","serializeTextWithMarks","escapeHTML","sorted","specA","getMarkSpec","specB","rank","html","toHTMLString","EventBus","listeners","payload","listener","err","error","callback","size","PluginManager","plugins","commands","services","middlewares","registrations","eventBus","pluginStyleSheets","middlewareSorted","initOrder","initialized","initializing","plugin","resolveOrder","context","createContext","init","onBeforeReady","onReady","oldState","newState","onStateChange","DecorationSet","empty","decorations","decos","isEmpty","merge","finalDispatch","getSortedMiddleware","dispatched","next","currentTr","called","guardedNext","middleware","name","config","onConfigure","getPluginIds","getPluginStyleSheets","reversed","destroyPlugin","cleanupRegistrations","reg","serviceId","unsub","unsubscribers","nodeSpecs","removeNodeSpec","markSpecs","removeMarkSpec","inlineNodeSpecs","removeInlineNodeSpec","nodeViews","removeNodeView","removeKeymap","inputRules","removeInputRule","itemId","toolbarItems","removeToolbarItem","fileHandlers","removeFileHandler","blockTypePickerEntries","removeBlockTypePickerEntry","sheet","stylesheets","pluginEventBus","emit","on","off","getContainer","getPluginContainer","registerCommand","executeCommand","getEventBus","registerMiddleware","registerService","service","getService","updateConfig","registerMarkSpec","registerNodeView","registerKeymap","registerInputRule","registerToolbarItem","registerInlineNodeSpec","registerFileHandler","registerBlockTypePickerEntry","getSchemaRegistry","registerStyleSheet","css","CSSStyleSheet","replaceSync","announce","dep","dependencies","inDegree","dependents","deps","depList","queue","deg","newDeg","missing","includes","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","tooltip","DARK_THEME","createTheme","base","overrides","toolbar","resolveTheme","theme","VARIABLE_MAP","COMPONENT_FALLBACKS","resolvePath","split","part","generateThemeCSS","cssVar","value","fallback","createThemeStyleSheet","InputHandler","handleBeforeInput","onBeforeInput","handleCompositionStart","onCompositionStart","handleCompositionEnd","onCompositionEnd","composing","inputType","data","insertHardBreakCommand","deleteBackward","deleteForward","deleteWordBackward","deleteWordForward","deleteSoftLineBackward","deleteSoftLineForward","checkInputRules","_e","composedText","rules","textBefore","match","exec","segmentsToText","reduce","acc","s","segmentsLength","BLOCK_ELEMENTS","INLINE_ELEMENTS","HTMLParser","blockParseRules","markParseRules","container","parseContainer","resolveBlockType","pendingSegments","Array","childNodes","Node","ELEMENT_NODE","el","isBlockElement","flushPendingSegments","parseBlockElement","parseInlineNode","TEXT_NODE","textContent","tagName","headingMatch","level","blockType","ensureSegments","parseInlineChildren","parseBlockquote","parseList","parseListItem","parsePreContent","parseTableAsParagraphs","blockMatch","matchBlockRule","some","listType","isChecklist","hasCheckbox","resolvedListType","checked","isCheckboxChecked","inlineSegments","nestedLists","getAttribute","indent","normalizeSegments","nested","nestedType","parentMarks","resolveMarks","childMarks","mergeMarks","marksFromElement","cells","querySelectorAll","cell","matchedTypes","getAttrs","markType","upperTag","href","additional","m","rawMarks","isMarkAllowed","isNodeTypeAllowed","segment","prev","markSetsEqual","querySelector","input","hasAttribute","normalized","trim","PasteHandler","handlePaste","onPaste","blockJson","getData","handleBlockPaste","handleFilePaste","handleRichPaste","richJson","extractRichData","handleRichPasteFromJson","allowedTags","allowedAttrs","sanitized","DOMPurify","ALLOWED_TAGS","ALLOWED_ATTR","schemaFromRegistry","parser","template","document","createElement","innerHTML","setSelection","builder","addDeleteSelectionSteps","insertBlockId","insertOffset","totalLength","insertText","setBlockType","blockIdx","firstSlice","lastSlice","middleSlices","firstLen","splitOffset","tailBlockId","generateBlockId","splitBlock","insertAt","mid","textNodes","insertNode","lastLen","parse","extractTextFromHTML","parsed","typeName","anchorBlockId","cellId","findTableCellAncestor","cellPath","isArray","insertRichBlocksIntoCell","insertRichBlocksAtRoot","anchorBlock","anchorIndex","isAnchorEmpty","insertIndex","lastBlockId","lastTextLen","newId","removeNode","files","file","getAsFile","matchFileHandlers","Promise","richEl","reconcile","oldBlocks","newBlocks","wrappers","wrapper","firstChild","insertBefore","remove","oldBlockMap","toBlockId","newBlockIds","removeChild","nv","oldBlockById","previousSibling","selectedNodeId","previousSelectedNodeId","existingEl","oldBlock","oldDecos","oldDecorations","find","newDecos","blockChanged","existingNv","update","contentDOM","updatedInlineDecos","findInline","renderBlockContent","dom","newEl","renderBlock","replaceChild","nextSibling","appendChild","selectNode","HTMLElement","classList","deselectNode","wrapBlocks","oldAttrs","newAttrs","oldKeys","newKeys","oldChild","newChild","inlineType","inlineAttrsEqual","oldArr","newArr","decorationArraysEqual","inlineDecos","getNodeViewFactory","nvSpec","isVoid","setAttribute","selectable","getBlockChildren","contentDOMChildren","getContentDOM","childEl","arr","applyNodeDecorations","p","globalOffset","renderInlineNode","textFrom","textTo","splitSet","deco","dFrom","dTo","splits","localFrom","localTo","activeDecos","preserveSpaces","sortedMarks","markOrder","j","createMarkElement","createDecorationElement","renderTextNode","lastChild","replace","textNode","getInlineNodeSpec","aKeys","bKeys","nodeName","class","cls","style","cssText","entries","nodeDecos","groups","currentSpec","currentIds","nodeSpec","wSpec","blockIds","firstEl","className","getSelection","root","getRootNode","ShadowRoot","window","syncSelectionToDOM","domSel","blockEl","parentNode","childIdx","childIndexOf","setBaseAndExtent","anchorPos","statePositionToDOM","headPos","found","contentEl","resolveContentRoot","walker","createInlineContentWalker","nextNode","domPositionToState","domOffset","rawBlockId","leafBlockEl","unshift","parentElement","targetEl","childOffset","inlineContentWidth","contains","walkerNode","createTreeWalker","NodeFilter","SHOW_ALL","acceptNode","n","FILTER_REJECT","FILTER_ACCEPT","FILTER_SKIP","width","EditorView","contentElement","inputHandler","keyboardHandler","pasteHandler","clipboardHandler","history","stateChangeCallbacks","handleSelectionChange","handleMousedown","handleDragover","handleDrop","isUpdating","pendingNodeSelectionClear","getDecorations","maxHistoryDepth","syncSelectionFromDOM","onSelectionChange","onMousedown","onDragover","onDrop","reconcileOptions","pushHistory","newDecorations","cb","applyUpdate","rangeCount","anchorNode","focusNode","anchorOffset","focusOffset","selectionsEqual","setStoredMarks","nearestBlockEl","closest","handleClickBelowContent","focus","buildBlockPath","lastBlockEl","lastRect","getBoundingClientRect","clientY","bottom","lastBlock","dataTransfer","types","position","getPositionFromPoint","clientX","x","y","domNode","cp","caretPositionFromPoint","offsetNode","caretRangeFromPoint","startContainer","startOffset","shadowRoot","activeEl","activeElement","oldSelection","BLOCK_TYPE_LABELS","paragraph","heading","code_block","blockquote","list_item","horizontal_rule","image","table","getBlockTypeLabel","parseElementToTextNodes","walkElement","currentMarks","markRules","matchBlockParseRule","serializeBlock","inlineContent","inlineSpec","serializeTextNode","align","markSpec","EDITOR_CSS","cachedStyleSheet","EditorThemeController","themeStyleSheet","systemThemeQuery","systemThemeHandler","pluginSheets","cleanupSystemThemeListener","setupSystemThemeListener","resolved","getSystemTheme","setThemeStyleSheet","sheets","refreshAdoptedStyleSheets","adoptedStyleSheets","matchMedia","matches","NotectlEditor","view","pluginManager","editorWrapper","topPluginContainer","bottomPluginContainer","announcer","eventListeners","readyPromiseResolve","readyPromise","preInitPlugins","themeController","constructor","super","resolve","attachShadow","mode","observedAttributes","connectedCallback","disconnectedCallback","_oldValue","newValue","isReadonly","contentEditable","removeAttribute","readonly","placeholder","processToolbarConfig","register","ensureTextFormattingPlugin","pluginMgr","topContainer","bottomContainer","create","collectDecorations","updateEmptyState","setPluginStyleSheets","autofocus","requestAnimationFrame","getJSON","replaceState","getHTML","currentListTag","isNodeOfType","blockRules","li","setJSON","getText","toggleBold","toggleItalic","toggleUnderline","can","configurePlugin","dispatchWithMiddleware","finalTr","event","whenReady","getTheme","pluginTeardown","pluginIds","layoutConfig","ToolbarPlugin","features","bold","italic","underline","TextFormattingPlugin","notifyStateChange","announcement","mt","markTypes","branded","wasActive","isMarkActive","nowActive","toggle","async","createEditor","editor","customElements","define"],"mappings":"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"}
|