@notectl/core 1.7.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/README.md +2 -2
  2. package/dist/chunks/{AttrRegistry-I-VdmRnN.mjs → AttrRegistry-D9Jx_RVb.mjs} +2 -2
  3. package/dist/chunks/{AttrRegistry-I-VdmRnN.mjs.map → AttrRegistry-D9Jx_RVb.mjs.map} +1 -1
  4. package/dist/chunks/AttributedMarkCommands-BtLea72z.mjs +80 -0
  5. package/dist/chunks/AttributedMarkCommands-BtLea72z.mjs.map +1 -0
  6. package/dist/chunks/{CaretNavigation-CAJXoaae.mjs → CaretNavigation-7JYpIKbs.mjs} +56 -56
  7. package/dist/chunks/{CaretNavigation-CAJXoaae.mjs.map → CaretNavigation-7JYpIKbs.mjs.map} +1 -1
  8. package/dist/chunks/ColorGrid-Dneqb8if.mjs +81 -0
  9. package/dist/chunks/ColorGrid-Dneqb8if.mjs.map +1 -0
  10. package/dist/chunks/ColorPickerPopup-CiCLBbe9.mjs +37 -0
  11. package/dist/chunks/ColorPickerPopup-CiCLBbe9.mjs.map +1 -0
  12. package/dist/chunks/ColorValidation-CV4f1wu6.mjs +39 -0
  13. package/dist/chunks/ColorValidation-CV4f1wu6.mjs.map +1 -0
  14. package/dist/chunks/{Document-CuwE73FF.mjs → Document-Brtw2jL1.mjs} +18 -18
  15. package/dist/chunks/{Document-CuwE73FF.mjs.map → Document-Brtw2jL1.mjs.map} +1 -1
  16. package/dist/chunks/MarkCommands-6RUJ4L3r.mjs +94 -0
  17. package/dist/chunks/MarkCommands-6RUJ4L3r.mjs.map +1 -0
  18. package/dist/chunks/{NavigationUtils-CyW0Vo8A.mjs → NavigationUtils-Cspt2ZrK.mjs} +3 -3
  19. package/dist/chunks/{NavigationUtils-CyW0Vo8A.mjs.map → NavigationUtils-Cspt2ZrK.mjs.map} +1 -1
  20. package/dist/chunks/{NodeResolver-B-wzthAQ.mjs → NodeResolver-C2XYkeOi.mjs} +2 -2
  21. package/dist/chunks/{NodeResolver-B-wzthAQ.mjs.map → NodeResolver-C2XYkeOi.mjs.map} +1 -1
  22. package/dist/chunks/PopupPositioning-BTT-_pQ3.mjs +32 -0
  23. package/dist/chunks/PopupPositioning-BTT-_pQ3.mjs.map +1 -0
  24. package/dist/chunks/RangeIterator-Bh4Vl_6D.mjs +16 -0
  25. package/dist/chunks/RangeIterator-Bh4Vl_6D.mjs.map +1 -0
  26. package/dist/chunks/{Selection-DmFDwiPJ.mjs → Selection-BRTab5hO.mjs} +7 -7
  27. package/dist/chunks/{Selection-DmFDwiPJ.mjs.map → Selection-BRTab5hO.mjs.map} +1 -1
  28. package/dist/chunks/StyleRuntime-ChRjVQwL.mjs +239 -0
  29. package/dist/chunks/StyleRuntime-ChRjVQwL.mjs.map +1 -0
  30. package/dist/chunks/ToolbarItem-BpZggUGo.mjs.map +1 -1
  31. package/dist/chunks/{ToolbarKeyboardNav-B32OMv8r.mjs → ToolbarKeyboardNav-DhpL8zNV.mjs} +3 -3
  32. package/dist/chunks/{ToolbarKeyboardNav-B32OMv8r.mjs.map → ToolbarKeyboardNav-DhpL8zNV.mjs.map} +1 -1
  33. package/dist/chunks/{ToolbarPlugin-B6JETWaw.mjs → ToolbarPlugin-DpLVJ71w.mjs} +348 -135
  34. package/dist/chunks/ToolbarPlugin-DpLVJ71w.mjs.map +1 -0
  35. package/dist/chunks/index--n1RGpq-.mjs +171 -0
  36. package/dist/chunks/index--n1RGpq-.mjs.map +1 -0
  37. package/dist/chunks/index-4or5UzNO.mjs +168 -0
  38. package/dist/chunks/index-4or5UzNO.mjs.map +1 -0
  39. package/dist/chunks/{index-pxbbDHVH.mjs → index-ABlTDvEX.mjs} +20 -19
  40. package/dist/chunks/index-ABlTDvEX.mjs.map +1 -0
  41. package/dist/chunks/{index--z_Txzej.mjs → index-BAke7kNL.mjs} +45 -45
  42. package/dist/chunks/{index--z_Txzej.mjs.map → index-BAke7kNL.mjs.map} +1 -1
  43. package/dist/chunks/{index-DMt3ojrY.mjs → index-BXtw5PNN.mjs} +2 -2
  44. package/dist/chunks/{index-DMt3ojrY.mjs.map → index-BXtw5PNN.mjs.map} +1 -1
  45. package/dist/chunks/{index-FlTg80Pk.mjs → index-BhDXjueu.mjs} +285 -325
  46. package/dist/chunks/index-BhDXjueu.mjs.map +1 -0
  47. package/dist/chunks/{index-D0s0Q8Wc.mjs → index-BqNUfq-y.mjs} +43 -35
  48. package/dist/chunks/index-BqNUfq-y.mjs.map +1 -0
  49. package/dist/chunks/{index-CflvcXSd.mjs → index-BvqkuEY1.mjs} +21 -17
  50. package/dist/chunks/index-BvqkuEY1.mjs.map +1 -0
  51. package/dist/chunks/{index-C9gc3Bws.mjs → index-C1opJocO.mjs} +32 -32
  52. package/dist/chunks/{index-C9gc3Bws.mjs.map → index-C1opJocO.mjs.map} +1 -1
  53. package/dist/chunks/index-CWltg1wK.mjs +124 -0
  54. package/dist/chunks/index-CWltg1wK.mjs.map +1 -0
  55. package/dist/chunks/{index-D8tbbW97.mjs → index-Cd3uJLP3.mjs} +2 -2
  56. package/dist/chunks/{index-D8tbbW97.mjs.map → index-Cd3uJLP3.mjs.map} +1 -1
  57. package/dist/chunks/{index-C0cEs7Jc.mjs → index-CluzpB2b.mjs} +10 -10
  58. package/dist/chunks/{index-C0cEs7Jc.mjs.map → index-CluzpB2b.mjs.map} +1 -1
  59. package/dist/chunks/{index-CoeD4T9-.mjs → index-D3NlpmT1.mjs} +15 -11
  60. package/dist/chunks/index-D3NlpmT1.mjs.map +1 -0
  61. package/dist/chunks/{index-CAV2N-fF.mjs → index-D515iymW.mjs} +75 -74
  62. package/dist/chunks/{index-CAV2N-fF.mjs.map → index-D515iymW.mjs.map} +1 -1
  63. package/dist/chunks/{index-B-NSeaM4.mjs → index-Dk49P9N4.mjs} +2 -2
  64. package/dist/chunks/{index-B-NSeaM4.mjs.map → index-Dk49P9N4.mjs.map} +1 -1
  65. package/dist/chunks/index-DyzigvbZ.mjs +410 -0
  66. package/dist/chunks/index-DyzigvbZ.mjs.map +1 -0
  67. package/dist/chunks/index-ErZ5_a1o.mjs +296 -0
  68. package/dist/chunks/index-ErZ5_a1o.mjs.map +1 -0
  69. package/dist/chunks/{index-CNs4QQ8l.mjs → index-fsVJLutn.mjs} +52 -64
  70. package/dist/chunks/index-fsVJLutn.mjs.map +1 -0
  71. package/dist/commands/AttributedMarkCommands.d.ts +46 -0
  72. package/dist/commands/AttributedMarkCommands.d.ts.map +1 -0
  73. package/dist/commands/CommandHelpers.d.ts +21 -0
  74. package/dist/commands/CommandHelpers.d.ts.map +1 -0
  75. package/dist/commands/Commands.d.ts +2 -8
  76. package/dist/commands/Commands.d.ts.map +1 -1
  77. package/dist/commands/DeleteCommands.d.ts.map +1 -1
  78. package/dist/commands/GapCursorCommands.d.ts.map +1 -1
  79. package/dist/commands/NodeSelectionCommands.d.ts.map +1 -1
  80. package/dist/commands/PasteCommand.d.ts.map +1 -1
  81. package/dist/commands/RangeIterator.d.ts +10 -0
  82. package/dist/commands/RangeIterator.d.ts.map +1 -0
  83. package/dist/editor/DocumentParser.d.ts.map +1 -1
  84. package/dist/editor/DocumentSerializer.d.ts +2 -0
  85. package/dist/editor/DocumentSerializer.d.ts.map +1 -1
  86. package/dist/editor/EditorThemeController.d.ts +3 -0
  87. package/dist/editor/EditorThemeController.d.ts.map +1 -1
  88. package/dist/editor/MarkSerializer.d.ts +11 -0
  89. package/dist/editor/MarkSerializer.d.ts.map +1 -0
  90. package/dist/editor/NotectlEditor.d.ts +19 -3
  91. package/dist/editor/NotectlEditor.d.ts.map +1 -1
  92. package/dist/editor/PaperLayoutController.d.ts +2 -0
  93. package/dist/editor/PaperLayoutController.d.ts.map +1 -1
  94. package/dist/editor/styles/font-select.d.ts +1 -1
  95. package/dist/editor/styles/font-select.d.ts.map +1 -1
  96. package/dist/editor/styles/font-size-select.d.ts +1 -1
  97. package/dist/editor/styles/font-size-select.d.ts.map +1 -1
  98. package/dist/editor/styles/heading-select.d.ts +1 -1
  99. package/dist/editor/styles/heading-select.d.ts.map +1 -1
  100. package/dist/editor/styles/toolbar.d.ts +1 -1
  101. package/dist/editor/styles/toolbar.d.ts.map +1 -1
  102. package/dist/index.d.ts +9 -2
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/input/ClipboardHandler.d.ts +0 -2
  105. package/dist/input/ClipboardHandler.d.ts.map +1 -1
  106. package/dist/input/LegacyHTMLNormalizer.d.ts.map +1 -1
  107. package/dist/model/MarkSpec.d.ts +6 -0
  108. package/dist/model/MarkSpec.d.ts.map +1 -1
  109. package/dist/notectl-core.mjs +2244 -2095
  110. package/dist/notectl-core.mjs.map +1 -1
  111. package/dist/notectl-core.umd.js +2862 -2415
  112. package/dist/notectl-core.umd.js.map +1 -1
  113. package/dist/plugins/PluginManager.d.ts +2 -0
  114. package/dist/plugins/PluginManager.d.ts.map +1 -1
  115. package/dist/plugins/alignment/AlignmentPlugin.d.ts.map +1 -1
  116. package/dist/plugins/alignment.mjs +1 -1
  117. package/dist/plugins/blockquote.mjs +1 -1
  118. package/dist/plugins/caret-navigation.mjs +1 -1
  119. package/dist/plugins/code-block/CodeBlockNodeView.d.ts.map +1 -1
  120. package/dist/plugins/code-block.mjs +1 -1
  121. package/dist/plugins/font/FontPlugin.d.ts +0 -6
  122. package/dist/plugins/font/FontPlugin.d.ts.map +1 -1
  123. package/dist/plugins/font-size/FontSizeOperations.d.ts.map +1 -1
  124. package/dist/plugins/font-size/FontSizePlugin.d.ts +0 -5
  125. package/dist/plugins/font-size/FontSizePlugin.d.ts.map +1 -1
  126. package/dist/plugins/font-size.mjs +1 -1
  127. package/dist/plugins/font.mjs +1 -1
  128. package/dist/plugins/gap-cursor.mjs +2 -2
  129. package/dist/plugins/hard-break.mjs +2 -25
  130. package/dist/plugins/hard-break.mjs.map +1 -1
  131. package/dist/plugins/heading/HeadingBlockTypePicker.d.ts +1 -7
  132. package/dist/plugins/heading/HeadingBlockTypePicker.d.ts.map +1 -1
  133. package/dist/plugins/heading/HeadingPlugin.d.ts +0 -6
  134. package/dist/plugins/heading/HeadingPlugin.d.ts.map +1 -1
  135. package/dist/plugins/heading.mjs +1 -1
  136. package/dist/plugins/highlight/HighlightPlugin.d.ts.map +1 -1
  137. package/dist/plugins/highlight.mjs +1 -1
  138. package/dist/plugins/horizontal-rule.mjs +1 -1
  139. package/dist/plugins/image/ImageNodeView.d.ts.map +1 -1
  140. package/dist/plugins/image/ImagePlugin.d.ts.map +1 -1
  141. package/dist/plugins/image.mjs +1 -1
  142. package/dist/plugins/link/LinkPlugin.d.ts.map +1 -1
  143. package/dist/plugins/link.mjs +1 -1
  144. package/dist/plugins/list/ListPlugin.d.ts.map +1 -1
  145. package/dist/plugins/list.mjs +1 -1
  146. package/dist/plugins/print/PrintContentPreparer.d.ts.map +1 -1
  147. package/dist/plugins/shared/ColorGrid.d.ts +25 -0
  148. package/dist/plugins/shared/ColorGrid.d.ts.map +1 -0
  149. package/dist/plugins/shared/ColorMarkOperations.d.ts.map +1 -1
  150. package/dist/plugins/shared/ColorPickerPopup.d.ts.map +1 -1
  151. package/dist/plugins/shared/ColorValidation.d.ts +13 -2
  152. package/dist/plugins/shared/ColorValidation.d.ts.map +1 -1
  153. package/dist/plugins/shared/PopupKeyboardPatterns.d.ts +43 -0
  154. package/dist/plugins/shared/PopupKeyboardPatterns.d.ts.map +1 -0
  155. package/dist/plugins/shared/PopupManager.d.ts +45 -0
  156. package/dist/plugins/shared/PopupManager.d.ts.map +1 -0
  157. package/dist/plugins/shared/PopupPositioning.d.ts +21 -0
  158. package/dist/plugins/shared/PopupPositioning.d.ts.map +1 -0
  159. package/dist/plugins/strikethrough.mjs +1 -1
  160. package/dist/plugins/super-sub.mjs +1 -1
  161. package/dist/plugins/table/TableBorderColor.d.ts.map +1 -1
  162. package/dist/plugins/table/TableContextMenu.d.ts +2 -1
  163. package/dist/plugins/table/TableContextMenu.d.ts.map +1 -1
  164. package/dist/plugins/table/TableControls.d.ts.map +1 -1
  165. package/dist/plugins/table/TableControlsDOM.d.ts.map +1 -1
  166. package/dist/plugins/table/TableControlsLayout.d.ts.map +1 -1
  167. package/dist/plugins/table/TableNodeViews.d.ts.map +1 -1
  168. package/dist/plugins/table.mjs +1 -1
  169. package/dist/plugins/text-color/TextColorPlugin.d.ts.map +1 -1
  170. package/dist/plugins/text-color.mjs +1 -1
  171. package/dist/plugins/text-formatting.mjs +1 -1
  172. package/dist/plugins/toolbar/ToolbarItem.d.ts +11 -2
  173. package/dist/plugins/toolbar/ToolbarItem.d.ts.map +1 -1
  174. package/dist/plugins/toolbar/ToolbarOverflowController.d.ts +5 -1
  175. package/dist/plugins/toolbar/ToolbarOverflowController.d.ts.map +1 -1
  176. package/dist/plugins/toolbar/ToolbarPlugin.d.ts +1 -0
  177. package/dist/plugins/toolbar/ToolbarPlugin.d.ts.map +1 -1
  178. package/dist/plugins/toolbar/ToolbarPopupController.d.ts +9 -1
  179. package/dist/plugins/toolbar/ToolbarPopupController.d.ts.map +1 -1
  180. package/dist/plugins/toolbar/ToolbarRenderers.d.ts.map +1 -1
  181. package/dist/plugins/toolbar/ToolbarTooltip.d.ts.map +1 -1
  182. package/dist/plugins/toolbar/index.d.ts +1 -1
  183. package/dist/plugins/toolbar/index.d.ts.map +1 -1
  184. package/dist/plugins/toolbar.mjs +1 -1
  185. package/dist/state/BlockTreeOps.d.ts +21 -0
  186. package/dist/state/BlockTreeOps.d.ts.map +1 -0
  187. package/dist/state/InlineContentOps.d.ts +37 -0
  188. package/dist/state/InlineContentOps.d.ts.map +1 -0
  189. package/dist/state/StepApplication.d.ts.map +1 -1
  190. package/dist/style/StyleRuntime.d.ts +38 -0
  191. package/dist/style/StyleRuntime.d.ts.map +1 -0
  192. package/dist/test/PluginTestUtils.d.ts +4 -0
  193. package/dist/test/PluginTestUtils.d.ts.map +1 -1
  194. package/dist/view/Reconciler.d.ts.map +1 -1
  195. package/package.json +2 -2
  196. package/dist/chunks/ColorNames-BdsHwA2f.mjs +0 -59
  197. package/dist/chunks/ColorNames-BdsHwA2f.mjs.map +0 -1
  198. package/dist/chunks/ColorPickerPopup-xL8ZUfpB.mjs +0 -125
  199. package/dist/chunks/ColorPickerPopup-xL8ZUfpB.mjs.map +0 -1
  200. package/dist/chunks/Commands-CicwYoTQ.mjs +0 -286
  201. package/dist/chunks/Commands-CicwYoTQ.mjs.map +0 -1
  202. package/dist/chunks/MarkCommands-CC37WA7Z.mjs +0 -94
  203. package/dist/chunks/MarkCommands-CC37WA7Z.mjs.map +0 -1
  204. package/dist/chunks/ToolbarPlugin-B6JETWaw.mjs.map +0 -1
  205. package/dist/chunks/index-B9GkDVsx.mjs +0 -187
  206. package/dist/chunks/index-B9GkDVsx.mjs.map +0 -1
  207. package/dist/chunks/index-CKPrAOr6.mjs +0 -209
  208. package/dist/chunks/index-CKPrAOr6.mjs.map +0 -1
  209. package/dist/chunks/index-CNs4QQ8l.mjs.map +0 -1
  210. package/dist/chunks/index-CflvcXSd.mjs.map +0 -1
  211. package/dist/chunks/index-CoeD4T9-.mjs.map +0 -1
  212. package/dist/chunks/index-D0s0Q8Wc.mjs.map +0 -1
  213. package/dist/chunks/index-DfzCof6H.mjs +0 -191
  214. package/dist/chunks/index-DfzCof6H.mjs.map +0 -1
  215. package/dist/chunks/index-DyIwN_67.mjs +0 -404
  216. package/dist/chunks/index-DyIwN_67.mjs.map +0 -1
  217. package/dist/chunks/index-FlTg80Pk.mjs.map +0 -1
  218. package/dist/chunks/index-pxbbDHVH.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DyzigvbZ.mjs","sources":["../../src/plugins/image/ImageCommands.ts","../../src/plugins/image/ImageLocale.ts","../../src/plugins/image/ImageNodeView.ts","../../src/plugins/image/ImageUpload.ts","../../src/plugins/image/ImagePlugin.ts","../../src/editor/styles/image.ts"],"sourcesContent":["/**\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\tisGapCursor,\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\tif (isGapCursor(sel)) return false;\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/** Minimum image width in pixels (shared with NodeView). */\nexport const MIN_IMAGE_WIDTH = 50;\n\n/**\n * Resizes the currently selected image by a pixel delta, preserving aspect ratio.\n * Returns false if no image is selected or the image has no width/height attributes.\n */\nexport function resizeImageByDelta(\n\tcontext: PluginContext,\n\tdelta: number,\n\tmaxWidth: number,\n): 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 currentWidth: number | undefined = block.attrs?.width as number | undefined;\n\tconst currentHeight: number | undefined = block.attrs?.height as number | undefined;\n\tif (currentWidth === undefined || currentHeight === undefined) return false;\n\n\tconst aspectRatio: number = currentHeight > 0 ? currentWidth / currentHeight : 1;\n\tconst clampedWidth: number = Math.max(MIN_IMAGE_WIDTH, Math.min(maxWidth, currentWidth + delta));\n\tconst newHeight: number = Math.round(clampedWidth / aspectRatio);\n\n\tif (clampedWidth === currentWidth && newHeight === currentHeight) return false;\n\n\treturn setImageAttr(context, { width: clampedWidth, height: newHeight });\n}\n\n/** Resets the currently selected image to its natural size by removing width/height. */\nexport function resetImageSize(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 path: BlockId[] | undefined = state.getNodePath(sel.nodeId);\n\tif (!path) return false;\n\n\tconst attrs: BlockAttrs = { ...(block.attrs ?? {}) };\n\tconst cleaned: BlockAttrs = Object.fromEntries(\n\t\tObject.entries(attrs).filter(([k]) => k !== 'width' && k !== 'height'),\n\t);\n\n\tconst tr = state.transaction('command').setNodeAttr(path, cleaned).build();\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","/** Locale interface and default English locale for the ImagePlugin. */\n\n// --- Locale Interface ---\n\nexport interface ImageLocale {\n\treadonly insertImage: string;\n\treadonly insertImageTooltip: string;\n\treadonly uploadFromComputer: string;\n\treadonly uploadAria: string;\n\treadonly separator: string;\n\treadonly urlPlaceholder: string;\n\treadonly urlAria: string;\n\treadonly insertButton: string;\n\treadonly insertAria: string;\n\treadonly imageAria: (alt: string, width?: number, height?: number) => string;\n\treadonly resetToNaturalSize: string;\n\treadonly uploadFailed: string;\n}\n\n// --- Default English Locale ---\n\nexport const IMAGE_LOCALE_EN: ImageLocale = {\n\tinsertImage: 'Insert Image',\n\tinsertImageTooltip: 'Insert Image',\n\tuploadFromComputer: 'Upload from computer',\n\tuploadAria: 'Upload image from computer',\n\tseparator: 'or',\n\turlPlaceholder: 'https://...',\n\turlAria: 'Image URL',\n\tinsertButton: 'Insert',\n\tinsertAria: 'Insert image',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || 'Image'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} by ${height} pixels`);\n\t\t}\n\t\treturn parts.join(', ');\n\t},\n\tresetToNaturalSize: 'Image reset to natural size.',\n\tuploadFailed: 'Image upload failed.',\n};\n\n// --- German Locale ---\n\nexport const IMAGE_LOCALE_DE: ImageLocale = {\n\tinsertImage: 'Bild einfügen',\n\tinsertImageTooltip: 'Bild einfügen',\n\tuploadFromComputer: 'Vom Computer hochladen',\n\tuploadAria: 'Bild vom Computer hochladen',\n\tseparator: 'oder',\n\turlPlaceholder: 'https://...',\n\turlAria: 'Bild-URL',\n\tinsertButton: 'Einfügen',\n\tinsertAria: 'Bild einfügen',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || 'Bild'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} mal ${height} Pixel`);\n\t\t}\n\t\treturn parts.join(', ');\n\t},\n\tresetToNaturalSize: 'Bild auf Originalgröße zurückgesetzt.',\n\tuploadFailed: 'Bild-Upload fehlgeschlagen.',\n};\n\n// --- Spanish Locale ---\n\nexport const IMAGE_LOCALE_ES: ImageLocale = {\n\tinsertImage: 'Insertar imagen',\n\tinsertImageTooltip: 'Insertar imagen',\n\tuploadFromComputer: 'Subir desde el ordenador',\n\tuploadAria: 'Subir imagen desde el ordenador',\n\tseparator: 'o',\n\turlPlaceholder: 'https://...',\n\turlAria: 'URL de la imagen',\n\tinsertButton: 'Insertar',\n\tinsertAria: 'Insertar imagen',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || 'Imagen'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} por ${height} píxeles`);\n\t\t}\n\t\treturn parts.join(', ');\n\t},\n\tresetToNaturalSize: 'Imagen restablecida a tamaño natural.',\n\tuploadFailed: 'Error al subir la imagen.',\n};\n\n// --- French Locale ---\n\nexport const IMAGE_LOCALE_FR: ImageLocale = {\n\tinsertImage: 'Insérer une image',\n\tinsertImageTooltip: 'Insérer une image',\n\tuploadFromComputer: 'Télécharger depuis l\\u2019ordinateur',\n\tuploadAria: 'Télécharger une image depuis l\\u2019ordinateur',\n\tseparator: 'ou',\n\turlPlaceholder: 'https://...',\n\turlAria: 'URL de l\\u2019image',\n\tinsertButton: 'Insérer',\n\tinsertAria: 'Insérer une image',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || 'Image'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} par ${height} pixels`);\n\t\t}\n\t\treturn parts.join(', ');\n\t},\n\tresetToNaturalSize: 'Image rétablie à sa taille d\\u2019origine.',\n\tuploadFailed: 'Échec du téléchargement de l\\u2019image.',\n};\n\n// --- Chinese (Simplified) Locale ---\n\nexport const IMAGE_LOCALE_ZH: ImageLocale = {\n\tinsertImage: '插入图片',\n\tinsertImageTooltip: '插入图片',\n\tuploadFromComputer: '从电脑上传',\n\tuploadAria: '从电脑上传图片',\n\tseparator: '或',\n\turlPlaceholder: 'https://...',\n\turlAria: '图片链接',\n\tinsertButton: '插入',\n\tinsertAria: '插入图片',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || '图片'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} x ${height} 像素`);\n\t\t}\n\t\treturn parts.join(',');\n\t},\n\tresetToNaturalSize: '图片已恢复原始大小。',\n\tuploadFailed: '图片上传失败。',\n};\n\n// --- Russian Locale ---\n\nexport const IMAGE_LOCALE_RU: ImageLocale = {\n\tinsertImage: 'Вставить изображение',\n\tinsertImageTooltip: 'Вставить изображение',\n\tuploadFromComputer: 'Загрузить с компьютера',\n\tuploadAria: 'Загрузить изображение с компьютера',\n\tseparator: 'или',\n\turlPlaceholder: 'https://...',\n\turlAria: 'URL изображения',\n\tinsertButton: 'Вставить',\n\tinsertAria: 'Вставить изображение',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || 'Изображение'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} на ${height} пикселей`);\n\t\t}\n\t\treturn parts.join(', ');\n\t},\n\tresetToNaturalSize: 'Изображение сброшено до исходного размера.',\n\tuploadFailed: 'Ошибка загрузки изображения.',\n};\n\n// --- Arabic Locale ---\n\nexport const IMAGE_LOCALE_AR: ImageLocale = {\n\tinsertImage: 'إدراج صورة',\n\tinsertImageTooltip: 'إدراج صورة',\n\tuploadFromComputer: 'رفع من الحاسوب',\n\tuploadAria: 'رفع صورة من الحاسوب',\n\tseparator: 'أو',\n\turlPlaceholder: 'https://...',\n\turlAria: 'رابط الصورة',\n\tinsertButton: 'إدراج',\n\tinsertAria: 'إدراج صورة',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || 'صورة'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} × ${height} بكسل`);\n\t\t}\n\t\treturn parts.join('، ');\n\t},\n\tresetToNaturalSize: 'تمت إعادة الصورة إلى حجمها الطبيعي.',\n\tuploadFailed: 'فشل رفع الصورة.',\n};\n\n// --- Hindi Locale ---\n\nexport const IMAGE_LOCALE_HI: ImageLocale = {\n\tinsertImage: 'चित्र डालें',\n\tinsertImageTooltip: 'चित्र डालें',\n\tuploadFromComputer: 'कंप्यूटर से अपलोड करें',\n\tuploadAria: 'कंप्यूटर से चित्र अपलोड करें',\n\tseparator: 'या',\n\turlPlaceholder: 'https://...',\n\turlAria: 'चित्र URL',\n\tinsertButton: 'डालें',\n\tinsertAria: 'चित्र डालें',\n\timageAria: (alt: string, width?: number, height?: number) => {\n\t\tconst parts: string[] = [alt || 'चित्र'];\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`${width} x ${height} पिक्सेल`);\n\t\t}\n\t\treturn parts.join(', ');\n\t},\n\tresetToNaturalSize: 'चित्र मूल आकार में पुनर्स्थापित।',\n\tuploadFailed: 'चित्र अपलोड विफल।',\n};\n\n// --- Locale Map ---\n\nexport const IMAGE_LOCALES: Record<string, ImageLocale> = {\n\ten: IMAGE_LOCALE_EN,\n\tde: IMAGE_LOCALE_DE,\n\tes: IMAGE_LOCALE_ES,\n\tfr: IMAGE_LOCALE_FR,\n\tzh: IMAGE_LOCALE_ZH,\n\tru: IMAGE_LOCALE_RU,\n\tar: IMAGE_LOCALE_AR,\n\thi: IMAGE_LOCALE_HI,\n};\n","/**\n * NodeView factory for image blocks.\n * Renders <figure> with <img>, handles selection state, upload overlay,\n * resize with 4 corner handles + live size indicator, and a keyboard-hint\n * showing resize shortcuts when the image is selected.\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 {\n\tgetStyleNonceForNode,\n\tsetStyleProperties,\n\tsetStyleProperty,\n} from '../../style/StyleRuntime.js';\nimport type { NodeView, NodeViewFactory } from '../../view/NodeView.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\nimport type { ImageKeymap, 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, referenceNode?: Node): void {\n\tclearGlobalResizeCursor();\n\tactiveCursorStyle = document.createElement('style');\n\tconst nonce = referenceNode ? getStyleNonceForNode(referenceNode) : undefined;\n\tif (nonce) {\n\t\tactiveCursorStyle.setAttribute('nonce', nonce);\n\t}\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/** Builds the keyboard-hint text from the resolved keymap. */\nfunction buildKeyboardHintText(\n\tresolvedKeymap: Readonly<Record<keyof ImageKeymap, string | null>>,\n): string {\n\tconst shrink: string | null = resolvedKeymap.shrinkWidth ?? null;\n\tconst grow: string | null = resolvedKeymap.growWidth ?? null;\n\tif (!shrink || !grow) return '';\n\treturn `${formatShortcut(shrink)} / ${formatShortcut(grow)} to resize`;\n}\n\n/** Creates a NodeViewFactory for image blocks. */\nexport function createImageNodeViewFactory(\n\tconfig: ImagePluginConfig,\n\tuploadStates: Map<BlockId, UploadState>,\n\tresolvedKeymap?: Readonly<Record<keyof ImageKeymap, string | null>>,\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// --- ARIA Label ---\n\n\t\tfunction updateAriaLabel(n: BlockNode): void {\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\n\t\t\tconst parts: string[] = [];\n\t\t\tif (alt) {\n\t\t\t\tparts.push(alt);\n\t\t\t} else {\n\t\t\t\tparts.push('Image');\n\t\t\t}\n\t\t\tif (width !== undefined && height !== undefined) {\n\t\t\t\tparts.push(`${width} by ${height} pixels`);\n\t\t\t}\n\t\t\tfigure.setAttribute('aria-label', parts.join(', '));\n\t\t}\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\t// Only update src when it changes to avoid re-triggering load events\n\t\t\tif (img.src !== src) img.src = src;\n\t\t\timg.alt = alt;\n\n\t\t\tif (width !== undefined) {\n\t\t\t\tsetStyleProperty(img, 'width', `${width}px`);\n\t\t\t} else {\n\t\t\t\tsetStyleProperty(img, 'width', '');\n\t\t\t}\n\t\t\tif (height !== undefined) {\n\t\t\t\tsetStyleProperty(img, 'height', `${height}px`);\n\t\t\t} else {\n\t\t\t\tsetStyleProperty(img, '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\n\t\t\tif (isUploading) {\n\t\t\t\toverlay.textContent = 'Uploading...';\n\t\t\t} else if (uploadState === 'error') {\n\t\t\t\toverlay.textContent = 'Upload failed';\n\t\t\t} else {\n\t\t\t\toverlay.textContent = '';\n\t\t\t}\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\n\t\t\tupdateAriaLabel(n);\n\t\t}\n\n\t\tapplyAttrs(node);\n\n\t\t// --- Commit natural dimensions on first load ---\n\n\t\tlet dimensionsCommitted = false;\n\n\t\timg.addEventListener('load', () => {\n\t\t\tif (dimensionsCommitted) return;\n\n\t\t\tconst state: EditorState = getState();\n\t\t\tconst block: BlockNode | undefined = state.getBlock(currentNodeId);\n\t\t\tif (!block || block.type !== 'image') return;\n\n\t\t\tconst hasWidth: boolean = block.attrs?.width !== undefined;\n\t\t\tconst hasHeight: boolean = block.attrs?.height !== undefined;\n\t\t\tif (hasWidth && hasHeight) {\n\t\t\t\tdimensionsCommitted = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst naturalW: number = img.naturalWidth;\n\t\t\tconst naturalH: number = img.naturalHeight;\n\t\t\tif (naturalW === 0 || naturalH === 0) return;\n\n\t\t\tconst clampedW: number = Math.min(naturalW, config.maxWidth);\n\t\t\tconst ratio: number = naturalW > 0 ? naturalH / naturalW : 1;\n\t\t\tconst clampedH: number = Math.round(clampedW * ratio);\n\n\t\t\tconst path: BlockId[] | undefined = state.getNodePath(currentNodeId);\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: clampedW,\n\t\t\t\theight: clampedH,\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\tdimensionsCommitted = true;\n\t\t});\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\tsetStyleProperties(img, {\n\t\t\t\t\twidth: `${newWidth}px`,\n\t\t\t\t\theight: `${newHeight}px`,\n\t\t\t\t});\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], figure);\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\t\t\tresizeOverlay.setAttribute('data-notectl-no-print', '');\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('role', 'separator');\n\t\t\t\thandle.setAttribute('aria-label', HANDLE_LABELS[pos]);\n\t\t\t\tattachHandleListeners(handle, pos, nodeId, sizeIndicator);\n\t\t\t\tresizeOverlay.appendChild(handle);\n\t\t\t}\n\n\t\t\t// Keyboard hint (hidden from screenreaders, visual only)\n\t\t\tif (resolvedKeymap) {\n\t\t\t\tconst hintText: string = buildKeyboardHintText(resolvedKeymap);\n\t\t\t\tif (hintText) {\n\t\t\t\t\tconst hint: HTMLDivElement = document.createElement('div');\n\t\t\t\t\thint.className = 'notectl-image__keyboard-hint';\n\t\t\t\t\thint.setAttribute('aria-hidden', 'true');\n\t\t\t\t\thint.textContent = hintText;\n\t\t\t\t\tresizeOverlay.appendChild(hint);\n\t\t\t\t}\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';\nimport type { ImageLocale } from './ImageLocale.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// --- Keyboard Bindings ---\n\n/**\n * Configurable keyboard bindings for image resize actions.\n * Omit a slot to use the default; set to `null` to disable the binding.\n *\n * Key descriptor format: `'Mod-Shift-ArrowRight'`, etc.\n * `Mod` resolves to Cmd on macOS, Ctrl on Windows/Linux.\n */\nexport interface ImageKeymap {\n\treadonly growWidth?: string | null;\n\treadonly shrinkWidth?: string | null;\n\treadonly growWidthLarge?: string | null;\n\treadonly shrinkWidthLarge?: string | null;\n\treadonly resetSize?: string | null;\n}\n\nexport const DEFAULT_IMAGE_KEYMAP: Readonly<Record<keyof ImageKeymap, string>> = {\n\tgrowWidth: 'Mod-Shift-ArrowRight',\n\tshrinkWidth: 'Mod-Shift-ArrowLeft',\n\tgrowWidthLarge: 'Mod-Shift-Alt-ArrowRight',\n\tshrinkWidthLarge: 'Mod-Shift-Alt-ArrowLeft',\n\tresetSize: 'Mod-Shift-0',\n};\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\t/** Pixels to grow/shrink per small resize step. @default 10 */\n\treadonly resizeStep?: number;\n\t/** Pixels to grow/shrink per large resize step. @default 50 */\n\treadonly resizeStepLarge?: number;\n\t/** Customize keyboard bindings for image resize actions. */\n\treadonly keymap?: ImageKeymap;\n\t/** Locale override for user-facing strings. */\n\treadonly locale?: ImageLocale;\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\tresizeStep: 10,\n\tresizeStepLarge: 50,\n};\n","/**\n * ImagePlugin: registers an image void block type with NodeSpec,\n * NodeView, commands, file handler, toolbar button, and accessible\n * keyboard resize with screenreader announcements.\n */\n\nimport { IMAGE_CSS } from '../../editor/styles/image.js';\nimport { resolvePluginLocale } from '../../i18n/resolvePluginLocale.js';\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 { setStyleProperty, setStyleText } from '../../style/StyleRuntime.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../toolbar/ToolbarItem.js';\nimport {\n\tinsertImage,\n\tregisterImageCommands,\n\tresetImageSize,\n\tresizeImageByDelta,\n} from './ImageCommands.js';\nimport { IMAGE_LOCALES, type ImageLocale } from './ImageLocale.js';\nimport { createImageNodeViewFactory } from './ImageNodeView.js';\nimport {\n\tDEFAULT_IMAGE_CONFIG,\n\tDEFAULT_IMAGE_KEYMAP,\n\tIMAGE_UPLOAD_SERVICE,\n\ttype ImageKeymap,\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 resolvedKeymap: Readonly<Record<keyof ImageKeymap, string | null>>;\n\tprivate readonly uploadStates = new Map<BlockId, UploadState>();\n\tprivate readonly blobUrls = new Set<string>();\n\tprivate context: PluginContext | null = null;\n\tprivate locale!: ImageLocale;\n\n\tconstructor(config?: Partial<ImagePluginConfig>) {\n\t\tthis.config = { ...DEFAULT_IMAGE_CONFIG, ...config };\n\t\tthis.resolvedKeymap = { ...DEFAULT_IMAGE_KEYMAP, ...config?.keymap };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tthis.locale = resolvePluginLocale(IMAGE_LOCALES, context, this.config.locale);\n\t\tcontext.registerStyleSheet(IMAGE_CSS);\n\t\tthis.context = context;\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerNodeView(context);\n\t\tregisterImageCommands(context);\n\t\tthis.registerResizeCommands(context);\n\t\tthis.registerResizeKeymaps(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\tthis.context = null;\n\t}\n\n\tonStateChange(oldState: EditorState, newState: EditorState, _tr: Transaction): void {\n\t\tif (!this.context) return;\n\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\n\t\t// Announce image selection for screenreaders\n\t\tconst oldIsImage: boolean = this.isImageSelected(oldState);\n\t\tconst nowIsImage: boolean = this.isImageSelected(newState);\n\n\t\tif (!oldIsImage && nowIsImage) {\n\t\t\tthis.announceImageSelection(newState);\n\t\t}\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tconst locale = this.locale;\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 alt: string = (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\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 = alt;\n\t\t\t\timg.draggable = false;\n\n\t\t\t\tif (width !== undefined) setStyleProperty(img, 'width', `${width}px`);\n\t\t\t\tif (height !== undefined) setStyleProperty(img, '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\tfigure.setAttribute('aria-label', locale.imageAria(alt, width, height));\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\tconst alignStyle: string = align ? ` style=\"text-align: ${escapeHTML(align)}\"` : '';\n\n\t\t\t\treturn `<figure${alignStyle}><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\t// Check inline style first (new format), then class names (legacy)\n\t\t\t\t\t\tconst textAlign: string = el.style?.textAlign ?? '';\n\t\t\t\t\t\tif (textAlign === 'left' || textAlign === 'right' || textAlign === 'center') {\n\t\t\t\t\t\t\tattrs.align = textAlign;\n\t\t\t\t\t\t} else if (el.classList.contains('notectl-image--left')) {\n\t\t\t\t\t\t\tattrs.align = 'left';\n\t\t\t\t\t\t} else if (el.classList.contains('notectl-image--right')) {\n\t\t\t\t\t\t\tattrs.align = 'right';\n\t\t\t\t\t\t}\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', 'style'],\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerNodeView(context: PluginContext): void {\n\t\tcontext.registerNodeView(\n\t\t\t'image',\n\t\t\tcreateImageNodeViewFactory(this.config, this.uploadStates, this.resolvedKeymap),\n\t\t);\n\t}\n\n\tprivate registerResizeCommands(context: PluginContext): void {\n\t\tconst step: number = this.config.resizeStep ?? 10;\n\t\tconst stepLarge: number = this.config.resizeStepLarge ?? 50;\n\t\tconst maxWidth: number = this.config.maxWidth;\n\n\t\tcontext.registerCommand('resizeImageGrow', () => {\n\t\t\tconst result: boolean = resizeImageByDelta(context, step, maxWidth);\n\t\t\tif (result) this.announceCurrentSize(context);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('resizeImageShrink', () => {\n\t\t\tconst result: boolean = resizeImageByDelta(context, -step, maxWidth);\n\t\t\tif (result) this.announceCurrentSize(context);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('resizeImageGrowLarge', () => {\n\t\t\tconst result: boolean = resizeImageByDelta(context, stepLarge, maxWidth);\n\t\t\tif (result) this.announceCurrentSize(context);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('resizeImageShrinkLarge', () => {\n\t\t\tconst result: boolean = resizeImageByDelta(context, -stepLarge, maxWidth);\n\t\t\tif (result) this.announceCurrentSize(context);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('resetImageSize', () => {\n\t\t\tconst result: boolean = resetImageSize(context);\n\t\t\tif (result) context.announce(this.locale.resetToNaturalSize);\n\t\t\treturn result;\n\t\t});\n\t}\n\n\tprivate registerResizeKeymaps(context: PluginContext): void {\n\t\tconst bindings: Record<string, () => boolean> = {};\n\t\tconst commands: Record<keyof ImageKeymap, string> = {\n\t\t\tgrowWidth: 'resizeImageGrow',\n\t\t\tshrinkWidth: 'resizeImageShrink',\n\t\t\tgrowWidthLarge: 'resizeImageGrowLarge',\n\t\t\tshrinkWidthLarge: 'resizeImageShrinkLarge',\n\t\t\tresetSize: 'resetImageSize',\n\t\t};\n\n\t\tfor (const [slot, commandName] of Object.entries(commands)) {\n\t\t\tconst binding: string | null = this.resolvedKeymap[slot as keyof ImageKeymap] ?? null;\n\t\t\tif (binding) {\n\t\t\t\tbindings[binding] = () => context.executeCommand(commandName);\n\t\t\t}\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\tprivate registerFileHandler(context: PluginContext): void {\n\t\tcontext.registerFileHandler('image/*', async (file, _position) => {\n\t\t\tif (!this.isAcceptedType(file.type)) return false;\n\t\t\tthis.handleFileInsert(context, file);\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\tcontext.announce(this.locale.uploadFailed);\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: this.locale.insertImage,\n\t\t\ttooltip: this.locale.insertImageTooltip,\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, onClose) => {\n\t\t\t\tthis.renderImagePopup(container, ctx, onClose);\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate renderImagePopup(\n\t\tcontainer: HTMLElement,\n\t\tcontext: PluginContext,\n\t\tonClose: () => void,\n\t): void {\n\t\tsetStyleProperty(container, 'padding', '8px');\n\t\tsetStyleProperty(container, '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\tsetStyleText(fileInput, 'position:absolute;width:0;height:0;overflow:hidden;opacity:0;');\n\n\t\tconst uploadBtn: HTMLButtonElement = document.createElement('button');\n\t\tuploadBtn.type = 'button';\n\t\tuploadBtn.textContent = this.locale.uploadFromComputer;\n\t\tuploadBtn.setAttribute('aria-label', this.locale.uploadAria);\n\t\tsetStyleText(\n\t\t\tuploadBtn,\n\t\t\t'display:block;width:100%;padding:8px 12px;cursor:pointer;' +\n\t\t\t\t'text-align:center;box-sizing:border-box;' +\n\t\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t\t'background:var(--notectl-surface-raised);color:var(--notectl-fg);',\n\t\t);\n\n\t\tuploadBtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tfileInput.click();\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\tonClose();\n\t\t\t\tcontext.getContainer().focus();\n\t\t\t}\n\t\t});\n\n\t\tcontainer.appendChild(fileInput);\n\t\tcontainer.appendChild(uploadBtn);\n\n\t\t// --- Separator ---\n\t\tconst separator: HTMLDivElement = document.createElement('div');\n\t\tsetStyleText(\n\t\t\tseparator,\n\t\t\t'display:flex;align-items:center;margin:8px 0;' +\n\t\t\t\t'color:var(--notectl-fg-muted);font-size:12px;',\n\t\t);\n\t\tconst line1: HTMLSpanElement = document.createElement('span');\n\t\tsetStyleText(line1, 'flex:1;height:1px;background:var(--notectl-border);');\n\t\tconst orText: HTMLSpanElement = document.createElement('span');\n\t\torText.textContent = this.locale.separator;\n\t\tsetStyleText(orText, 'padding:0 8px;');\n\t\tconst line2: HTMLSpanElement = document.createElement('span');\n\t\tsetStyleText(line2, '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 = this.locale.urlPlaceholder;\n\t\turlInput.setAttribute('aria-label', this.locale.urlAria);\n\t\tsetStyleText(\n\t\t\turlInput,\n\t\t\t'width:100%;padding:6px 8px;box-sizing:border-box;' +\n\t\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t\t'background:var(--notectl-bg);color:var(--notectl-fg);',\n\t\t);\n\n\t\tconst insertBtn: HTMLButtonElement = document.createElement('button');\n\t\tinsertBtn.type = 'button';\n\t\tinsertBtn.textContent = this.locale.insertButton;\n\t\tinsertBtn.setAttribute('aria-label', this.locale.insertAria);\n\t\tsetStyleText(\n\t\t\tinsertBtn,\n\t\t\t'width:100%;padding:8px 12px;margin-top:4px;cursor:pointer;' +\n\t\t\t\t'border:1px solid var(--notectl-border);border-radius:4px;' +\n\t\t\t\t'background:var(--notectl-surface-raised);color:var(--notectl-fg);',\n\t\t);\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\tonClose();\n\t\t\t\tcontext.getContainer().focus();\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\tprivate isImageSelected(state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return false;\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\t\treturn block?.type === 'image';\n\t}\n\n\tprivate announceImageSelection(state: EditorState): void {\n\t\tif (!this.context) return;\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\t\tif (!block || block.type !== 'image') return;\n\n\t\tconst alt: string = (block.attrs?.alt as string | undefined) ?? '';\n\t\tconst width: number | undefined = block.attrs?.width as number | undefined;\n\t\tconst height: number | undefined = block.attrs?.height as number | undefined;\n\n\t\tconst parts: string[] = ['Image selected.'];\n\t\tif (alt) parts.push(`Alt text: ${alt}.`);\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tparts.push(`Size: ${width} by ${height} pixels.`);\n\t\t}\n\n\t\tconst shrinkKey: string | null = this.resolvedKeymap.shrinkWidth ?? null;\n\t\tconst growKey: string | null = this.resolvedKeymap.growWidth ?? null;\n\t\tif (shrinkKey && growKey) {\n\t\t\tparts.push(`${formatShortcut(shrinkKey)} / ${formatShortcut(growKey)} to resize.`);\n\t\t}\n\n\t\tthis.context.announce(parts.join(' '));\n\t}\n\n\tprivate announceCurrentSize(context: PluginContext): void {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isNodeSelection(sel)) return;\n\n\t\tconst block: BlockNode | undefined = state.getBlock(sel.nodeId);\n\t\tif (!block || block.type !== 'image') return;\n\n\t\tconst width: number | undefined = block.attrs?.width as number | undefined;\n\t\tconst height: number | undefined = block.attrs?.height as number | undefined;\n\t\tif (width !== undefined && height !== undefined) {\n\t\t\tcontext.announce(`Image resized to ${width} by ${height} pixels.`);\n\t\t}\n\t}\n}\n","/** Image styles — display, alignment, resize handles, upload overlay. */\nexport const IMAGE_CSS = `\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/* Keyboard resize hint (shown on selection, hidden during drag) */\n.notectl-image__keyboard-hint {\n\tdisplay: none;\n\tposition: absolute;\n\tbottom: -28px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tpadding: 2px 8px;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n\twhite-space: nowrap;\n\tpointer-events: none;\n\tz-index: 3;\n}\n\n.notectl-image--selected .notectl-image__keyboard-hint {\n\tdisplay: block;\n}\n\n.notectl-image--resizing .notectl-image__keyboard-hint {\n\tdisplay: none;\n}\n\n/* Resizing feedback */\n.notectl-image--resizing .notectl-image__img {\n\topacity: 0.85;\n}\n`;\n"],"names":["insertImage","context","attrs","state","getState","sel","selection","imageAttrs","src","alt","align","width","height","isGapCursor","anchorBlockId","isNodeSelection","nodeId","anchor","blockId","cellId","bid","block","getBlock","type","path","getNodePath","id","node","cellPath","imageBlock","createBlockNode","nodeType","cell","builder","transaction","blockChildren","getBlockChildren","i","length","rawIndex","children","findIndex","c","isBlockNode","removeNode","insertNode","setSelection","createNodeSelection","dispatch","build","blockIndex","doc","b","newParagraph","tr","resizeImageByDelta","delta","maxWidth","currentWidth","currentHeight","aspectRatio","clampedWidth","Math","max","min","newHeight","round","merged","setNodeAttr","IMAGE_LOCALE_EN","insertImageTooltip","uploadFromComputer","uploadAria","separator","urlPlaceholder","urlAria","insertButton","insertAria","imageAria","parts","push","join","resetToNaturalSize","uploadFailed","IMAGE_LOCALES","en","de","es","fr","zh","ru","ar","hi","ALIGNMENT_CLASSES","left","center","right","HANDLE_CURSORS","nw","ne","sw","se","HANDLE_X_SIGN","HANDLE_LABELS","activeCursorStyle","clearGlobalResizeCursor","remove","createImageNodeViewFactory","config","uploadStates","resolvedKeymap","figure","document","createElement","className","setAttribute","container","img","draggable","overlay","appendChild","currentNodeId","resizeOverlay","applyAttrs","n","setStyleProperty","cls","Object","values","classList","alignClass","add","uploadState","get","isUploading","toggle","textContent","removeAttribute","dimensionsCommitted","attachHandleListeners","handle","position","sizeIndicator","startX","startWidth","onPointerMove","e","deltaX","clientX","newWidth","setStyleProperties","onPointerUp","removeEventListener","finalWidth","getBoundingClientRect","finalHeight","prevWidth","prevHeight","target","releasePointerCapture","pointerId","addEventListener","preventDefault","stopPropagation","imgHeight","cursor","referenceNode","nonce","getStyleNonceForNode","head","setPointerCapture","removeResizeOverlay","hasWidth","hasHeight","naturalW","naturalWidth","naturalH","naturalHeight","clampedW","ratio","clampedH","dom","contentDOM","update","updatedNode","selectNode","resizable","positions","pos","hintText","shrink","shrinkWidth","grow","growWidth","formatShortcut","hint","destroy","IMAGE_UPLOAD_SERVICE","ServiceKey","DEFAULT_IMAGE_KEYMAP","growWidthLarge","shrinkWidthLarge","resetSize","DEFAULT_IMAGE_CONFIG","maxFileSize","acceptedTypes","resizeStep","resizeStepLarge","ImagePlugin","name","priority","Map","blobUrls","Set","locale","this","keymap","resolvePluginLocale","registerStyleSheet","registerNodeSpec","registerNodeView","registerCommand","nodePath","parentPath","slice","parent","parentId","imageIndex","selectionTarget","removedId","rootChildren","idx","adjacent","createCollapsedSelection","registerResizeCommands","registerResizeKeymaps","registerFileHandler","registerToolbarItem","url","URL","revokeObjectURL","clear","oldState","newState","_tr","keys","delete","oldIsImage","isImageSelected","nowIsImage","announceImageSelection","group","isVoid","selectable","default","createBlockElement","imgContainer","escapeHTML","sizeAttrs","parseHTML","tag","el","querySelector","getAttribute","Number","parseInt","textAlign","style","contains","sanitize","tags","step","stepLarge","result","announceCurrentSize","cleaned","fromEntries","entries","filter","k","announce","bindings","commands","slot","commandName","binding","executeCommand","registerKeymap","async","file","_position","isAcceptedType","handleFileInsert","size","blobUrl","createObjectURL","imageBlockId","set","getService","uploadFile","uploadService","upload","icon","label","tooltip","command","popupType","separatorAfter","renderPopup","ctx","onClose","renderImagePopup","fileInput","accept","setStyleText","uploadBtn","click","files","getContainer","focus","line1","orText","line2","urlInput","placeholder","insertBtn","applyUrl","value","trim","key","requestAnimationFrame","mimeType","some","accepted","endsWith","startsWith","shrinkKey","growKey"],"mappings":"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"}
@@ -0,0 +1,296 @@
1
+ import { k as t, f as n, u as e, d as o, c as r, t as i, g as c } from "./Document-Brtw2jL1.mjs";
2
+ import { i as s, b as l, s as d, a as u } from "./NavigationUtils-Cspt2ZrK.mjs";
3
+ import { f } from "./NodeResolver-C2XYkeOi.mjs";
4
+ import { b as a, s as b, d as k, i as g, a as I, j as h, e as m, c as p } from "./Selection-BRTab5hO.mjs";
5
+ import { n as S, i as B } from "./TypeBrands-C09nE2qO.mjs";
6
+ function x(t2, n2) {
7
+ if (0 === n2.length) return t2.doc.children;
8
+ const e2 = t2.getBlock(n2[n2.length - 1]);
9
+ return e2 ? e2.children : [];
10
+ }
11
+ function O(e2) {
12
+ return t(S("paragraph"), [n("")], e2);
13
+ }
14
+ function N(t2, n2) {
15
+ if (a(t2)) return { blockId: t2.anchor.blockId, offset: t2.anchor.offset };
16
+ const e2 = b(t2, n2);
17
+ return { blockId: e2.from.blockId, offset: e2.from.offset };
18
+ }
19
+ function T(t2, n2) {
20
+ const i2 = f(t2.doc, n2.nodeId);
21
+ if (!i2) return null;
22
+ const c2 = i2.length > 1 ? i2.slice(0, -1) : [], s2 = x(t2, c2), l2 = s2.findIndex((t3) => "id" in t3 && t3.id === n2.nodeId);
23
+ if (l2 < 0) return null;
24
+ const d2 = t2.transaction("input");
25
+ if (1 === s2.length && 0 === c2.length) {
26
+ const t3 = e();
27
+ return d2.insertNode(c2, 0, O(t3)), d2.removeNode(c2, 1), d2.setSelection(k(t3, 0)), d2.build();
28
+ }
29
+ d2.removeNode(c2, l2);
30
+ const u2 = s2[l2 - 1];
31
+ if (u2 && o(u2)) {
32
+ const n3 = (function(t3) {
33
+ let n4 = t3;
34
+ for (; ; ) {
35
+ let t4;
36
+ for (let e2 = n4.children.length - 1; e2 >= 0; e2--) {
37
+ const r2 = n4.children[e2];
38
+ if (r2 && o(r2)) {
39
+ t4 = r2;
40
+ break;
41
+ }
42
+ }
43
+ if (!t4) return n4.id;
44
+ n4 = t4;
45
+ }
46
+ })(u2);
47
+ if (n3) {
48
+ const e2 = t2.getBlock(n3), o2 = e2 ? r(e2) : 0;
49
+ d2.setSelection(k(n3, o2));
50
+ }
51
+ } else {
52
+ const t3 = s2[l2 + 1];
53
+ if (t3 && o(t3)) {
54
+ const n3 = (function(t4) {
55
+ let n4 = t4;
56
+ for (; ; ) {
57
+ const t5 = n4.children.find((t6) => o(t6));
58
+ if (!t5) return n4.id;
59
+ n4 = t5;
60
+ }
61
+ })(t3);
62
+ n3 && d2.setSelection(k(n3, 0));
63
+ }
64
+ }
65
+ return d2.build();
66
+ }
67
+ function A(t2, n2) {
68
+ const e2 = t2.selection, o2 = t2.getBlockOrder();
69
+ return g(e2) ? (function(t3, n3, e3, o3) {
70
+ const i2 = o3.indexOf(n3.nodeId), c2 = f(t3.doc, n3.nodeId) ?? [];
71
+ if ("left" === e3 || "up" === e3) {
72
+ if (i2 > 0) {
73
+ const e4 = o3[i2 - 1];
74
+ if (!e4) return null;
75
+ if (s(t3, e4)) return t3.transaction("input").setSelection(h(n3.nodeId, "before", c2)).build();
76
+ const l2 = t3.getBlock(e4), d2 = l2 ? r(l2) : 0;
77
+ return t3.transaction("input").setSelection(k(e4, d2)).build();
78
+ }
79
+ return t3.transaction("input").setSelection(h(n3.nodeId, "before", c2)).build();
80
+ }
81
+ if (i2 < o3.length - 1) {
82
+ const e4 = o3[i2 + 1];
83
+ return e4 ? s(t3, e4) ? t3.transaction("input").setSelection(h(n3.nodeId, "after", c2)).build() : t3.transaction("input").setSelection(k(e4, 0)).build() : null;
84
+ }
85
+ return t3.transaction("input").setSelection(h(n3.nodeId, "after", c2)).build();
86
+ })(t2, e2, n2, o2) : I(e2) ? null : a(e2) ? (function(t3, n3, e3, o3) {
87
+ const i2 = o3.indexOf(n3.anchor.blockId), c2 = t3.getBlock(n3.anchor.blockId);
88
+ if (!c2) return null;
89
+ const l2 = r(c2);
90
+ if (("right" === e3 || "down" === e3) && n3.anchor.offset === l2 && i2 < o3.length - 1) {
91
+ const n4 = o3[i2 + 1];
92
+ if (n4 && s(t3, n4)) {
93
+ const e4 = f(t3.doc, n4) ?? [];
94
+ return t3.transaction("input").setSelection(m(n4, e4)).build();
95
+ }
96
+ }
97
+ if (("left" === e3 || "up" === e3) && 0 === n3.anchor.offset && i2 > 0) {
98
+ const n4 = o3[i2 - 1];
99
+ if (n4 && s(t3, n4)) {
100
+ const e4 = f(t3.doc, n4) ?? [];
101
+ return t3.transaction("input").setSelection(m(n4, e4)).build();
102
+ }
103
+ }
104
+ return null;
105
+ })(t2, e2, n2, o2) : null;
106
+ }
107
+ function j(t2, n2) {
108
+ if ("after" === n2.side) return M(t2, n2);
109
+ const e2 = t2.getBlockOrder(), o2 = e2.indexOf(n2.blockId);
110
+ if (o2 <= 0) return null;
111
+ const i2 = e2[o2 - 1];
112
+ if (!i2) return null;
113
+ if (s(t2, i2)) {
114
+ const n3 = f(t2.doc, i2) ?? [];
115
+ return t2.transaction("input").setSelection(m(i2, n3)).build();
116
+ }
117
+ const c2 = t2.getBlock(i2);
118
+ if (!c2) return null;
119
+ const l2 = r(c2);
120
+ return t2.transaction("input").setSelection(k(i2, l2)).build();
121
+ }
122
+ function y(t2, n2) {
123
+ if ("before" === n2.side) return M(t2, n2);
124
+ const e2 = t2.getBlockOrder(), o2 = e2.indexOf(n2.blockId);
125
+ if (o2 >= e2.length - 1) return null;
126
+ const r2 = e2[o2 + 1];
127
+ if (!r2) return null;
128
+ if (s(t2, r2)) {
129
+ const n3 = f(t2.doc, r2) ?? [];
130
+ return t2.transaction("input").setSelection(m(r2, n3)).build();
131
+ }
132
+ return t2.transaction("input").setSelection(k(r2, 0)).build();
133
+ }
134
+ function M(t2, n2) {
135
+ const e2 = f(t2.doc, n2.blockId) ?? [];
136
+ return T(t2, m(n2.blockId, e2));
137
+ }
138
+ function H(t2, n2, o2 = "input") {
139
+ const r2 = t2.selection;
140
+ if (g(r2)) return (function(t3, n3, o3, r3) {
141
+ const i3 = f(t3.doc, n3.nodeId), c2 = i3 && i3.length > 1 ? i3.slice(0, -1) : [], s3 = x(t3, c2), l3 = s3.findIndex((t4) => "id" in t4 && t4.id === n3.nodeId), d3 = e(), u2 = t3.transaction(r3), a2 = l3 >= 0 ? l3 + 1 : s3.length;
142
+ return u2.insertNode(c2, a2, O(d3)), u2.insertText(d3, 0, o3, []), u2.setSelection(k(d3, o3.length)), u2.build();
143
+ })(t2, r2, n2, o2);
144
+ if (I(r2)) return (function(t3, n3, o3, r3) {
145
+ const i3 = f(t3.doc, n3.blockId), c2 = i3 && i3.length > 1 ? i3.slice(0, -1) : [], s3 = x(t3, c2), l3 = s3.findIndex((t4) => "id" in t4 && t4.id === n3.blockId), d3 = "before" === n3.side ? Math.max(l3, 0) : l3 >= 0 ? l3 + 1 : s3.length, u2 = e(), a2 = t3.transaction(r3);
146
+ return a2.insertNode(c2, d3, O(u2)), a2.insertText(u2, 0, o3, []), a2.setSelection(k(u2, o3.length)), a2.build();
147
+ })(t2, r2, n2, o2);
148
+ const i2 = t2.transaction(o2), s2 = (function(t3) {
149
+ if (t3.storedMarks) return t3.storedMarks;
150
+ if (g(t3.selection) || I(t3.selection)) return [];
151
+ const n3 = t3.getBlock(t3.selection.anchor.blockId);
152
+ return n3 ? c(n3, t3.selection.anchor.offset) : [];
153
+ })(t2);
154
+ a(r2) || _(t2, i2);
155
+ const { blockId: l2, offset: d2 } = N(r2, t2.getBlockOrder());
156
+ return i2.insertText(l2, d2, n2, s2), i2.setSelection(k(l2, d2 + n2.length)), i2.build();
157
+ }
158
+ function v(t2) {
159
+ if (g(t2.selection)) return T(t2, t2.selection);
160
+ if (I(t2.selection)) return null;
161
+ if (a(t2.selection)) return null;
162
+ const n2 = t2.transaction("input");
163
+ _(t2, n2);
164
+ const e2 = b(t2.selection, t2.getBlockOrder());
165
+ return n2.setSelection(k(e2.from.blockId, e2.from.offset)), n2.build();
166
+ }
167
+ function C(t2) {
168
+ const n2 = t2.selection;
169
+ if (g(n2)) return (function(t3, n3) {
170
+ const o3 = f(t3.doc, n3.nodeId);
171
+ if (!o3) return null;
172
+ const r3 = o3.length > 1 ? o3.slice(0, -1) : [], i3 = x(t3, r3).findIndex((t4) => "id" in t4 && t4.id === n3.nodeId);
173
+ if (i3 < 0) return null;
174
+ const c3 = e(), s2 = t3.transaction("input");
175
+ return s2.insertNode(r3, i3 + 1, O(c3)), s2.setSelection(k(c3, 0)), s2.build();
176
+ })(t2, n2);
177
+ if (I(n2)) return (function(t3, n3) {
178
+ const o3 = f(t3.doc, n3.blockId);
179
+ if (!o3) return null;
180
+ const r3 = o3.length > 1 ? o3.slice(0, -1) : [], i3 = x(t3, r3).findIndex((t4) => "id" in t4 && t4.id === n3.blockId);
181
+ if (i3 < 0) return null;
182
+ const c3 = "before" === n3.side ? i3 : i3 + 1, s2 = e(), l2 = t3.transaction("input");
183
+ return l2.insertNode(r3, c3, O(s2)), l2.setSelection(k(s2, 0)), l2.build();
184
+ })(t2, n2);
185
+ const o2 = t2.transaction("input");
186
+ a(n2) || _(t2, o2);
187
+ const { blockId: r2, offset: i2 } = N(n2, t2.getBlockOrder()), c2 = e();
188
+ return o2.splitBlock(r2, i2, c2), o2.setSelection(k(c2, 0)), o2.build();
189
+ }
190
+ function K(t2) {
191
+ const n2 = t2.selection;
192
+ if (g(n2) || I(n2)) return null;
193
+ const e2 = t2.transaction("input");
194
+ a(n2) || _(t2, e2);
195
+ const { blockId: o2, offset: r2 } = N(n2, t2.getBlockOrder()), c2 = i(B("hard_break"));
196
+ return e2.insertInlineNode(o2, r2, c2), e2.setSelection(k(o2, r2 + 1)), e2.build();
197
+ }
198
+ function D(t2) {
199
+ const n2 = t2.selection;
200
+ if (g(n2) || I(n2)) return null;
201
+ const e2 = t2.getBlockOrder(), o2 = e2.indexOf(n2.anchor.blockId);
202
+ if (o2 <= 0) return null;
203
+ const i2 = e2[o2 - 1];
204
+ if (!i2) return null;
205
+ if (l(t2, n2.anchor.blockId) || l(t2, i2)) return null;
206
+ if (!d(t2, n2.anchor.blockId, i2) && u(t2, n2.anchor.blockId)) return null;
207
+ if (s(t2, i2)) {
208
+ const n3 = f(t2.doc, i2) ?? [];
209
+ return t2.transaction("input").setSelection(m(i2, n3)).build();
210
+ }
211
+ const c2 = t2.getBlock(i2);
212
+ if (!c2) return null;
213
+ const a2 = r(c2);
214
+ return t2.transaction("input").mergeBlocksAt(i2, n2.anchor.blockId).setSelection(k(i2, a2)).build();
215
+ }
216
+ function E(t2) {
217
+ const n2 = t2.selection;
218
+ if (g(n2) || I(n2)) return null;
219
+ const e2 = t2.getBlockOrder(), o2 = e2.indexOf(n2.anchor.blockId);
220
+ if (o2 >= e2.length - 1) return null;
221
+ const r2 = e2[o2 + 1];
222
+ if (!r2) return null;
223
+ if (l(t2, n2.anchor.blockId) || l(t2, r2)) return null;
224
+ if (!d(t2, n2.anchor.blockId, r2) && u(t2, n2.anchor.blockId)) return null;
225
+ if (s(t2, r2)) {
226
+ const n3 = f(t2.doc, r2) ?? [];
227
+ return t2.transaction("input").setSelection(m(r2, n3)).build();
228
+ }
229
+ return t2.transaction("input").mergeBlocksAt(n2.anchor.blockId, r2).setSelection(k(n2.anchor.blockId, n2.anchor.offset)).build();
230
+ }
231
+ function L(t2) {
232
+ const n2 = t2.doc.children, e2 = n2[0], o2 = n2[n2.length - 1];
233
+ if (!e2 || !o2) return t2.transaction("command").setSelection(t2.selection).build();
234
+ const i2 = r(o2);
235
+ return t2.transaction("command").setSelection(p({ blockId: e2.id, offset: 0 }, { blockId: o2.id, offset: i2 })).build();
236
+ }
237
+ function _(t2, n2) {
238
+ if (g(t2.selection) || I(t2.selection)) return;
239
+ const e2 = t2.getBlockOrder(), o2 = b(t2.selection, e2), i2 = e2.indexOf(o2.from.blockId), c2 = e2.indexOf(o2.to.blockId);
240
+ if (i2 === c2) n2.deleteTextAt(o2.from.blockId, o2.from.offset, o2.to.offset);
241
+ else {
242
+ const s2 = t2.getBlock(o2.from.blockId);
243
+ if (!s2) return;
244
+ const l2 = r(s2);
245
+ o2.from.offset < l2 && n2.deleteTextAt(o2.from.blockId, o2.from.offset, l2), o2.to.offset > 0 && n2.deleteTextAt(o2.to.blockId, 0, o2.to.offset);
246
+ for (let s3 = i2 + 1; s3 < c2; s3++) {
247
+ const i3 = e2[s3];
248
+ if (!i3) continue;
249
+ const c3 = t2.getBlock(i3);
250
+ if (!c3) continue;
251
+ const l3 = r(c3);
252
+ l3 > 0 && n2.deleteTextAt(i3, 0, l3), n2.mergeBlocksAt(o2.from.blockId, i3);
253
+ }
254
+ n2.mergeBlocksAt(o2.from.blockId, o2.to.blockId);
255
+ }
256
+ }
257
+ class w {
258
+ id = "hard-break";
259
+ name = "Hard Break";
260
+ priority = 10;
261
+ init(t2) {
262
+ this.registerInlineNodeSpec(t2), this.registerCommands(t2), this.registerKeymap(t2);
263
+ }
264
+ registerInlineNodeSpec(t2) {
265
+ t2.registerInlineNodeSpec({ type: "hard_break", toDOM: () => document.createElement("br"), toHTMLString: () => "<br>", parseHTML: [{ tag: "br" }], sanitize: { tags: ["br"] } });
266
+ }
267
+ registerCommands(t2) {
268
+ t2.registerCommand("insertHardBreak", () => {
269
+ const n2 = K(t2.getState());
270
+ return !!n2 && (t2.dispatch(n2), true);
271
+ });
272
+ }
273
+ registerKeymap(t2) {
274
+ t2.registerKeymap({ "Shift-Enter": () => {
275
+ const n2 = K(t2.getState());
276
+ return !!n2 && (t2.dispatch(n2), true);
277
+ } });
278
+ }
279
+ }
280
+ export {
281
+ w as H,
282
+ v as a,
283
+ D as b,
284
+ C as c,
285
+ T as d,
286
+ j as e,
287
+ y as f,
288
+ K as g,
289
+ _ as h,
290
+ H as i,
291
+ E as m,
292
+ A as n,
293
+ N as r,
294
+ L as s
295
+ };
296
+ //# sourceMappingURL=index-ErZ5_a1o.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-ErZ5_a1o.mjs","sources":["../../src/commands/CommandHelpers.ts","../../src/commands/NodeSelectionCommands.ts","../../src/commands/GapCursorCommands.ts","../../src/commands/Commands.ts","../../src/plugins/hard-break/HardBreakPlugin.ts"],"sourcesContent":["/**\n * Shared helpers used across multiple command modules.\n *\n * - {@link getSiblings} — resolves a parent path to its child list\n * - {@link createEmptyParagraph} — builds an empty paragraph BlockNode\n * - {@link resolveInsertPoint} — normalizes a text selection to a single insert position\n */\n\nimport type { BlockNode, ChildNode } from '../model/Document.js';\nimport { createBlockNode, createTextNode } from '../model/Document.js';\nimport { isCollapsed, selectionRange } from '../model/Selection.js';\nimport type { Selection } from '../model/Selection.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport { nodeType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\n\n/** The resolved insert position within a single block. */\nexport interface InsertPoint {\n\treadonly blockId: BlockId;\n\treadonly offset: number;\n}\n\n/** Resolves the children of a parent path: doc root or a nested block. */\nexport function getSiblings(\n\tstate: EditorState,\n\tparentPath: readonly BlockId[],\n): readonly ChildNode[] {\n\tif (parentPath.length === 0) return state.doc.children;\n\tconst parent: BlockNode | undefined = state.getBlock(\n\t\tparentPath[parentPath.length - 1] as BlockId,\n\t);\n\treturn parent ? parent.children : [];\n}\n\n/** Creates an empty paragraph block node with the given ID. */\nexport function createEmptyParagraph(id: BlockId): BlockNode {\n\treturn createBlockNode(nodeType('paragraph'), [createTextNode('')], id);\n}\n\n/**\n * Normalizes a text selection to a single insert point.\n *\n * - Collapsed selection → anchor position.\n * - Range selection → normalized `from` position (document-order start).\n */\nexport function resolveInsertPoint(sel: Selection, blockOrder: readonly BlockId[]): InsertPoint {\n\tif (isCollapsed(sel)) {\n\t\treturn { blockId: sel.anchor.blockId, offset: sel.anchor.offset };\n\t}\n\tconst range = selectionRange(sel, blockOrder);\n\treturn { blockId: range.from.blockId, offset: range.from.offset };\n}\n","/**\n * Commands for NodeSelection: deleting void blocks, inserting paragraphs\n * after void blocks, and navigating arrow keys into/out of void blocks.\n */\n\nimport { type BlockNode, generateBlockId, getBlockLength, isBlockNode } from '../model/Document.js';\nimport { isVoidBlock } from '../model/NavigationUtils.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { NodeSelection } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateGapCursor,\n\tcreateNodeSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n} 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 { createEmptyParagraph, getSiblings } from './CommandHelpers.js';\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\tconst parentPath: BlockId[] = path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\tconst siblings = getSiblings(state, parentPath);\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(parentPath, 0, createEmptyParagraph(newId));\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\n/** Inserts a new paragraph after a NodeSelection-targeted void block. */\nexport function 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\tconst siblings = getSiblings(state, parentPath);\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(parentPath, index + 1, createEmptyParagraph(newId));\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. */\nexport function 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\tconst siblings = getSiblings(state, parentPath);\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(parentPath, insertIdx, createEmptyParagraph(newId));\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\treturn navigateAwayFromNodeSelection(state, sel, direction, blockOrder);\n\t}\n\n\t// GapCursor is handled by navigateFromGapCursor in CaretNavigation\n\tif (isGapCursor(sel)) return null;\n\n\t// Text selection: check if navigating into a void block\n\tif (!isCollapsed(sel)) return null;\n\n\treturn navigateIntoVoid(state, sel, direction, blockOrder);\n}\n\n/** Finds the first leaf (deepest-first-child) block ID in a subtree. */\nexport function 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\n/** Finds the last leaf (deepest-last-child) block ID in a subtree. */\nexport function 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// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Handles navigation away from a NodeSelection (arrow keys while void is selected). */\nfunction navigateAwayFromNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n\tdirection: 'left' | 'right' | 'up' | 'down',\n\tblockOrder: readonly BlockId[],\n): Transaction | null {\n\tconst nodeIdx = blockOrder.indexOf(sel.nodeId);\n\tconst nodePath = (findNodePath(state.doc, sel.nodeId) ?? []) as BlockId[];\n\n\tif (direction === 'left' || direction === 'up') {\n\t\tif (nodeIdx > 0) {\n\t\t\tconst prevId = blockOrder[nodeIdx - 1];\n\t\t\tif (!prevId) return null;\n\t\t\tif (isVoidBlock(state, prevId)) {\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createGapCursor(sel.nodeId, 'before', nodePath))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t\tconst prevBlock = state.getBlock(prevId);\n\t\t\tconst prevLen = prevBlock ? getBlockLength(prevBlock) : 0;\n\t\t\treturn state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setSelection(createCollapsedSelection(prevId, prevLen))\n\t\t\t\t.build();\n\t\t}\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createGapCursor(sel.nodeId, 'before', nodePath))\n\t\t\t.build();\n\t}\n\n\t// right or down\n\tif (nodeIdx < blockOrder.length - 1) {\n\t\tconst nextId = blockOrder[nodeIdx + 1];\n\t\tif (!nextId) return null;\n\t\tif (isVoidBlock(state, nextId)) {\n\t\t\treturn state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setSelection(createGapCursor(sel.nodeId, 'after', nodePath))\n\t\t\t\t.build();\n\t\t}\n\t\treturn state.transaction('input').setSelection(createCollapsedSelection(nextId, 0)).build();\n\t}\n\treturn state\n\t\t.transaction('input')\n\t\t.setSelection(createGapCursor(sel.nodeId, 'after', nodePath))\n\t\t.build();\n}\n\n/** Handles text selection navigating into an adjacent void block. */\nfunction navigateIntoVoid(\n\tstate: EditorState,\n\tsel: { readonly anchor: { readonly blockId: BlockId; readonly offset: number } },\n\tdirection: 'left' | 'right' | 'up' | 'down',\n\tblockOrder: readonly BlockId[],\n): Transaction | null {\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 * Commands for GapCursor: deleting void blocks adjacent to gap cursors\n * and inserting paragraphs at gap positions.\n */\n\nimport { generateBlockId, getBlockLength } from '../model/Document.js';\nimport { isVoidBlock } from '../model/NavigationUtils.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { GapCursorSelection, NodeSelection } from '../model/Selection.js';\nimport { createCollapsedSelection, createNodeSelection } 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 { createEmptyParagraph, getSiblings } from './CommandHelpers.js';\nimport { deleteNodeSelection } from './NodeSelectionCommands.js';\n\n/**\n * Deletes the void block adjacent to a GapCursor when pressing Backspace.\n *\n * - `side === 'after'` → void block is behind the cursor → delete it.\n * - `side === 'before'` → void block is ahead → navigate backward (to previous block).\n * - At document start with `side === 'before'` → `null` (no-op).\n */\nexport function deleteBackwardAtGap(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n): Transaction | null {\n\tif (sel.side === 'after') {\n\t\treturn deleteVoidAtGap(state, sel);\n\t}\n\n\t// side === 'before': navigate to previous block\n\tconst blockOrder: readonly BlockId[] = state.getBlockOrder();\n\tconst blockIdx: number = blockOrder.indexOf(sel.blockId);\n\n\tif (blockIdx <= 0) return null;\n\n\tconst prevId: BlockId | undefined = blockOrder[blockIdx - 1];\n\tif (!prevId) return null;\n\n\tif (isVoidBlock(state, prevId)) {\n\t\tconst path = findNodePath(state.doc, prevId) ?? [];\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createNodeSelection(prevId, path as BlockId[]))\n\t\t\t.build();\n\t}\n\n\tconst prevBlock = state.getBlock(prevId);\n\tif (!prevBlock) return null;\n\tconst prevLen: number = getBlockLength(prevBlock);\n\treturn state.transaction('input').setSelection(createCollapsedSelection(prevId, prevLen)).build();\n}\n\n/**\n * Deletes the void block adjacent to a GapCursor when pressing Delete.\n *\n * - `side === 'before'` → void block is ahead of the cursor → delete it.\n * - `side === 'after'` → void block is behind → navigate forward (to next block).\n * - At document end with `side === 'after'` → `null` (no-op).\n */\nexport function deleteForwardAtGap(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n): Transaction | null {\n\tif (sel.side === 'before') {\n\t\treturn deleteVoidAtGap(state, sel);\n\t}\n\n\t// side === 'after': navigate to next block\n\tconst blockOrder: readonly BlockId[] = state.getBlockOrder();\n\tconst blockIdx: number = blockOrder.indexOf(sel.blockId);\n\n\tif (blockIdx >= blockOrder.length - 1) return null;\n\n\tconst nextId: BlockId | undefined = blockOrder[blockIdx + 1];\n\tif (!nextId) return null;\n\n\tif (isVoidBlock(state, nextId)) {\n\t\tconst path = findNodePath(state.doc, nextId) ?? [];\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createNodeSelection(nextId, path as BlockId[]))\n\t\t\t.build();\n\t}\n\n\treturn state.transaction('input').setSelection(createCollapsedSelection(nextId, 0)).build();\n}\n\n/** Deletes the void block that the GapCursor is adjacent to, delegating to deleteNodeSelection. */\nfunction deleteVoidAtGap(state: EditorState, sel: GapCursorSelection): Transaction | null {\n\tconst path = (findNodePath(state.doc, sel.blockId) ?? []) as BlockId[];\n\tconst nodeSel: NodeSelection = createNodeSelection(sel.blockId, path);\n\treturn deleteNodeSelection(state, nodeSel);\n}\n\n/** Inserts a new paragraph at a GapCursor position (before or after the void block). */\nexport function insertParagraphAtGap(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n): Transaction | null {\n\tconst path = findNodePath(state.doc, sel.blockId);\n\tif (!path) return null;\n\n\tconst parentPath: BlockId[] = path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\tconst siblings = getSiblings(state, parentPath);\n\n\tconst index: number = siblings.findIndex((c) => 'id' in c && c.id === sel.blockId);\n\tif (index < 0) return null;\n\n\tconst insertIdx: number = sel.side === 'before' ? index : index + 1;\n\tconst newId = generateBlockId();\n\tconst builder = state.transaction('input');\n\tbuilder.insertNode(parentPath, insertIdx, createEmptyParagraph(newId));\n\tbuilder.setSelection(createCollapsedSelection(newId, 0));\n\treturn builder.build();\n}\n\n/** Inserts text in a new paragraph at a GapCursor position. */\nexport function insertTextAtGap(\n\tstate: EditorState,\n\tsel: GapCursorSelection,\n\ttext: string,\n\torigin: 'input' | 'paste',\n): Transaction {\n\tconst path = findNodePath(state.doc, sel.blockId);\n\tconst parentPath: BlockId[] = path && path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n\tconst siblings = getSiblings(state, parentPath);\n\n\tconst index: number = siblings.findIndex((c) => 'id' in c && c.id === sel.blockId);\n\tconst insertIdx: number =\n\t\tsel.side === 'before' ? Math.max(index, 0) : index >= 0 ? index + 1 : siblings.length;\n\n\tconst newId = generateBlockId();\n\tconst builder = state.transaction(origin);\n\tbuilder.insertNode(parentPath, insertIdx, createEmptyParagraph(newId));\n\tbuilder.insertText(newId, 0, text, []);\n\tbuilder.setSelection(createCollapsedSelection(newId, text.length));\n\treturn builder.build();\n}\n","/**\n * Core editor commands and barrel re-exports from submodules.\n *\n * This module contains text insertion, block splitting, block merging,\n * selection deletion, and select-all. Mark, delete, gap-cursor, node-selection,\n * and word-boundary commands are re-exported from their respective modules.\n */\n\nimport {\n\ttype Mark,\n\tcreateInlineNode,\n\tgenerateBlockId,\n\tgetBlockLength,\n\tgetBlockMarksAtOffset,\n} from '../model/Document.js';\nimport {\n\tisInsideIsolating,\n\tisIsolatingBlock,\n\tisVoidBlock,\n\tsharesParent,\n} from '../model/NavigationUtils.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tcreateSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n\tselectionRange,\n} from '../model/Selection.js';\nimport { type BlockId, inlineType } 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';\nimport { resolveInsertPoint } from './CommandHelpers.js';\nimport { insertParagraphAtGap, insertTextAtGap } from './GapCursorCommands.js';\nimport {\n\tdeleteNodeSelection,\n\tinsertParagraphAfterNodeSelection,\n\tinsertTextAfterNodeSelection,\n} from './NodeSelectionCommands.js';\n\n// --- Re-exports from submodules ---\n\nexport {\n\tcanCrossBlockBoundary,\n\tisInsideIsolating,\n\tisIsolatingBlock,\n\tisVoidBlock,\n\tsharesParent,\n} from '../model/NavigationUtils.js';\n\nexport type { FeatureConfig } from './MarkCommands.js';\nexport {\n\tisMarkActive,\n\ttoggleBold,\n\ttoggleItalic,\n\ttoggleMark,\n\ttoggleUnderline,\n} from './MarkCommands.js';\n\nexport {\n\tdeleteBackward,\n\tdeleteForward,\n\tdeleteSoftLineBackward,\n\tdeleteSoftLineForward,\n\tdeleteWordBackward,\n\tdeleteWordForward,\n} from './DeleteCommands.js';\n\nexport {\n\tdeleteNodeSelection,\n\tfindFirstLeafBlockId,\n\tfindLastLeafBlockId,\n\tinsertParagraphAfterNodeSelection,\n\tinsertTextAfterNodeSelection,\n\tnavigateArrowIntoVoid,\n} from './NodeSelectionCommands.js';\n\nexport {\n\tdeleteBackwardAtGap,\n\tdeleteForwardAtGap,\n\tinsertParagraphAtGap,\n\tinsertTextAtGap,\n} from './GapCursorCommands.js';\n\nexport {\n\tfindWordBoundaryBackward,\n\tfindWordBoundaryForward,\n} from './WordBoundary.js';\n\nexport {\n\tapplyAttributedMark,\n\tgetMarkAttrAtSelection,\n\tisAttributedMarkActive,\n\tremoveAttributedMark,\n} from './AttributedMarkCommands.js';\n\nexport { forEachBlockInRange } from './RangeIterator.js';\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\t// GapCursor: insert paragraph at the gap position with the text\n\tif (isGapCursor(sel)) {\n\t\treturn insertTextAtGap(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 { blockId: insertBlockId, offset: insertOffset } = resolveInsertPoint(\n\t\tsel,\n\t\tstate.getBlockOrder(),\n\t);\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 (isGapCursor(state.selection)) return null;\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/** 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\t// GapCursor: insert empty paragraph at the gap position\n\tif (isGapCursor(sel)) {\n\t\treturn insertParagraphAtGap(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, offset } = resolveInsertPoint(sel, state.getBlockOrder());\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) || isGapCursor(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 { blockId: insertBlockId, offset: insertOffset } = resolveInsertPoint(\n\t\tsel,\n\t\tstate.getBlockOrder(),\n\t);\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/**\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) || isGapCursor(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 */\nexport function mergeBlockForward(state: EditorState): Transaction | null {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel) || isGapCursor(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// --- Internal Helpers ---\n\nfunction resolveActiveMarks(state: EditorState): readonly Mark[] {\n\tif (state.storedMarks) return state.storedMarks;\n\tif (isNodeSelection(state.selection) || isGapCursor(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) || isGapCursor(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 * 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"],"names":["getSiblings","state","parentPath","length","doc","children","parent","getBlock","createEmptyParagraph","id","createBlockNode","nodeType","createTextNode","resolveInsertPoint","sel","blockOrder","isCollapsed","blockId","anchor","offset","range","selectionRange","from","deleteNodeSelection","path","findNodePath","nodeId","slice","siblings","index","findIndex","c","builder","transaction","newId","generateBlockId","insertNode","removeNode","setSelection","createCollapsedSelection","build","prevSibling","isBlockNode","prevLeafId","node","current","lastBlockChild","i","child","prevLeaf","prevLen","getBlockLength","nextSibling","nextLeafId","firstBlockChild","find","navigateArrowIntoVoid","direction","selection","getBlockOrder","isNodeSelection","nodeIdx","indexOf","nodePath","prevId","isVoidBlock","createGapCursor","prevBlock","nextId","isGapCursor","blockIdx","block","blockLen","createNodeSelection","deleteBackwardAtGap","side","deleteVoidAtGap","deleteForwardAtGap","insertTextCommand","text","origin","insertIdx","insertText","Math","max","marks","storedMarks","getBlockMarksAtOffset","addDeleteSelectionSteps","insertBlockId","insertOffset","deleteSelectionCommand","splitBlockCommand","newBlockId","splitBlock","insertHardBreakCommand","hardBreak","createInlineNode","inlineType","insertInlineNode","mergeBlockBackward","prevBlockId","isIsolatingBlock","sharesParent","isInsideIsolating","mergeBlocksAt","mergeBlockForward","nextBlockId","selectAll","blocks","firstBlock","lastBlock","lastBlockLen","createSelection","fromIdx","toIdx","to","deleteTextAt","firstLen","midBlockId","midBlock","midLen","HardBreakPlugin","name","priority","context","this","registerInlineNodeSpec","registerCommands","registerKeymap","type","toDOM","document","createElement","toHTMLString","parseHTML","tag","sanitize","tags","registerCommand","tr","getState","dispatch"],"mappings":"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"}