@notectl/core 2.0.0 → 2.0.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 (343) hide show
  1. package/README.md +12 -10
  2. package/dist/chunks/{AttrRegistry-B2AGfTE0.mjs → AttrRegistry-iNpjvcSG.mjs} +2 -2
  3. package/dist/chunks/{AttrRegistry-B2AGfTE0.mjs.map → AttrRegistry-iNpjvcSG.mjs.map} +1 -1
  4. package/dist/chunks/AttributedMarkCommands-BY1BSYWM.mjs +2 -0
  5. package/dist/chunks/AttributedMarkCommands-BY1BSYWM.mjs.map +1 -0
  6. package/dist/chunks/BlockInsertion-BJFhE0jA.mjs +2 -0
  7. package/dist/chunks/BlockInsertion-BJFhE0jA.mjs.map +1 -0
  8. package/dist/chunks/{ColorPickerPopup-DRzFvt7o.mjs → ColorPickerPopup-D6XjShhv.mjs} +2 -2
  9. package/dist/chunks/ColorPickerPopup-D6XjShhv.mjs.map +1 -0
  10. package/dist/chunks/CommandHelpers-M6mPS6Ww.mjs +2 -0
  11. package/dist/chunks/CommandHelpers-M6mPS6Ww.mjs.map +1 -0
  12. package/dist/chunks/Commands-D_gMCnVa.mjs +2 -0
  13. package/dist/chunks/Commands-D_gMCnVa.mjs.map +1 -0
  14. package/dist/chunks/Document-3pNX7ear.mjs +2 -0
  15. package/dist/chunks/Document-3pNX7ear.mjs.map +1 -0
  16. package/dist/chunks/DocumentParser-LvzDQOd1.mjs +2 -0
  17. package/dist/chunks/DocumentParser-LvzDQOd1.mjs.map +1 -0
  18. package/dist/chunks/DomUtils-CznMAZZg.mjs +2 -0
  19. package/dist/chunks/DomUtils-CznMAZZg.mjs.map +1 -0
  20. package/dist/chunks/HTMLUtils-Cxy99Ak2.mjs +2 -0
  21. package/dist/chunks/HTMLUtils-Cxy99Ak2.mjs.map +1 -0
  22. package/dist/chunks/HeadingPlugin-BmkeUXj8.mjs +2 -0
  23. package/dist/chunks/HeadingPlugin-BmkeUXj8.mjs.map +1 -0
  24. package/dist/chunks/MarkCommands-CeCa4WSC.mjs +2 -0
  25. package/dist/chunks/MarkCommands-CeCa4WSC.mjs.map +1 -0
  26. package/dist/chunks/NavigationQueries-11qe4j9x.mjs +2 -0
  27. package/dist/chunks/NavigationQueries-11qe4j9x.mjs.map +1 -0
  28. package/dist/chunks/NodeResolver-z0ReCR34.mjs +2 -0
  29. package/dist/chunks/NodeResolver-z0ReCR34.mjs.map +1 -0
  30. package/dist/chunks/NodeSelectionCommands-CXrOcPtG.mjs +2 -0
  31. package/dist/chunks/NodeSelectionCommands-CXrOcPtG.mjs.map +1 -0
  32. package/dist/chunks/NotectlEditor-BJD7-FFx.mjs +4 -0
  33. package/dist/chunks/NotectlEditor-BJD7-FFx.mjs.map +1 -0
  34. package/dist/chunks/PluginHelpers-CdPR0MuT.mjs +2 -0
  35. package/dist/chunks/PluginHelpers-CdPR0MuT.mjs.map +1 -0
  36. package/dist/chunks/PopupManager-0b_Q0m7K.mjs +2 -0
  37. package/dist/chunks/PopupManager-0b_Q0m7K.mjs.map +1 -0
  38. package/dist/chunks/PrintTypes-DukwDSWS.mjs +2 -0
  39. package/dist/chunks/{PrintTypes-ehbL7ipA.mjs.map → PrintTypes-DukwDSWS.mjs.map} +1 -1
  40. package/dist/chunks/{RangeIterator-CNI6smOg.mjs → RangeIterator-XFN5FaYf.mjs} +2 -2
  41. package/dist/chunks/{RangeIterator-CNI6smOg.mjs.map → RangeIterator-XFN5FaYf.mjs.map} +1 -1
  42. package/dist/chunks/{Selection-6-W6Flxc.mjs → Selection-DhbizDM4.mjs} +2 -2
  43. package/dist/chunks/{Selection-6-W6Flxc.mjs.map → Selection-DhbizDM4.mjs.map} +1 -1
  44. package/dist/chunks/SelectionTransactions-DzIZxcuN.mjs +2 -0
  45. package/dist/chunks/{SelectionTransactions-q71GEzgE.mjs.map → SelectionTransactions-DzIZxcuN.mjs.map} +1 -1
  46. package/dist/chunks/{TextDirectionLocale-DB_aqrMg.mjs → TextDirectionLocale-CKz0ZrH_.mjs} +2 -2
  47. package/dist/chunks/{TextDirectionLocale-DB_aqrMg.mjs.map → TextDirectionLocale-CKz0ZrH_.mjs.map} +1 -1
  48. package/dist/chunks/XmlPatterns-DxQXGjP8.mjs +2 -0
  49. package/dist/chunks/XmlPatterns-DxQXGjP8.mjs.map +1 -0
  50. package/dist/chunks/ar-b6VdnxAs.mjs +2 -0
  51. package/dist/chunks/ar-b6VdnxAs.mjs.map +1 -0
  52. package/dist/chunks/de-fXvs5vQT.mjs +2 -0
  53. package/dist/chunks/de-fXvs5vQT.mjs.map +1 -0
  54. package/dist/chunks/es-BTqy_aQ4.mjs +2 -0
  55. package/dist/chunks/es-BTqy_aQ4.mjs.map +1 -0
  56. package/dist/chunks/fr-VdiCNF4J.mjs +2 -0
  57. package/dist/chunks/fr-VdiCNF4J.mjs.map +1 -0
  58. package/dist/chunks/hi-BdtVhAzs.mjs +2 -0
  59. package/dist/chunks/hi-BdtVhAzs.mjs.map +1 -0
  60. package/dist/chunks/index-C-L4awHz.mjs +2 -0
  61. package/dist/chunks/index-C-L4awHz.mjs.map +1 -0
  62. package/dist/chunks/index-Cs9iqxhF.mjs +2 -0
  63. package/dist/chunks/index-Cs9iqxhF.mjs.map +1 -0
  64. package/dist/chunks/pt-K0BUlM9X.mjs +2 -0
  65. package/dist/chunks/pt-K0BUlM9X.mjs.map +1 -0
  66. package/dist/chunks/ru-Tzd5N37W.mjs +2 -0
  67. package/dist/chunks/ru-Tzd5N37W.mjs.map +1 -0
  68. package/dist/chunks/zh-Di3WqY4_.mjs +2 -0
  69. package/dist/chunks/zh-Di3WqY4_.mjs.map +1 -0
  70. package/dist/{input → commands}/BlockInsertion.d.ts +14 -1
  71. package/dist/commands/BlockInsertion.d.ts.map +1 -0
  72. package/dist/commands/CommandHelpers.d.ts +17 -2
  73. package/dist/commands/CommandHelpers.d.ts.map +1 -1
  74. package/dist/commands/Commands.d.ts.map +1 -1
  75. package/dist/commands/GapCursorCommands.d.ts.map +1 -1
  76. package/dist/commands/NodeSelectionCommands.d.ts +3 -8
  77. package/dist/commands/NodeSelectionCommands.d.ts.map +1 -1
  78. package/dist/commands/PasteCommand.d.ts.map +1 -1
  79. package/dist/editor/ContentSerializer.d.ts.map +1 -1
  80. package/dist/editor/EditorConfig.d.ts +50 -0
  81. package/dist/editor/EditorConfig.d.ts.map +1 -0
  82. package/dist/editor/EditorConfigController.d.ts +1 -1
  83. package/dist/editor/EditorConfigController.d.ts.map +1 -1
  84. package/dist/editor/EditorDOM.d.ts.map +1 -1
  85. package/dist/editor/EditorInitializer.d.ts +37 -0
  86. package/dist/editor/EditorInitializer.d.ts.map +1 -0
  87. package/dist/editor/EditorLifecycleCoordinator.d.ts +6 -1
  88. package/dist/editor/EditorLifecycleCoordinator.d.ts.map +1 -1
  89. package/dist/editor/EditorThemeController.d.ts.map +1 -1
  90. package/dist/editor/NotectlEditor.d.ts +13 -51
  91. package/dist/editor/NotectlEditor.d.ts.map +1 -1
  92. package/dist/editor/PluginBootstrapper.d.ts +1 -1
  93. package/dist/editor/PluginBootstrapper.d.ts.map +1 -1
  94. package/dist/editor/styles/code-block.d.ts +1 -1
  95. package/dist/editor/styles/code-block.d.ts.map +1 -1
  96. package/dist/editor/theme/ThemeEngine.d.ts.map +1 -1
  97. package/dist/editor/theme/ThemeTokens.d.ts +17 -1
  98. package/dist/editor/theme/ThemeTokens.d.ts.map +1 -1
  99. package/dist/full.d.ts +1 -0
  100. package/dist/full.d.ts.map +1 -1
  101. package/dist/full.mjs +1 -1
  102. package/dist/html.mjs +1 -1
  103. package/dist/index.d.ts +1 -1
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/input/ClipboardHandler.d.ts +5 -0
  106. package/dist/input/ClipboardHandler.d.ts.map +1 -1
  107. package/dist/input/HTMLParser.d.ts +9 -5
  108. package/dist/input/HTMLParser.d.ts.map +1 -1
  109. package/dist/input/InputHandler.d.ts +1 -0
  110. package/dist/input/InputHandler.d.ts.map +1 -1
  111. package/dist/input/InputManager.d.ts +2 -0
  112. package/dist/input/InputManager.d.ts.map +1 -1
  113. package/dist/input/InternalClipboard.d.ts +2 -22
  114. package/dist/input/InternalClipboard.d.ts.map +1 -1
  115. package/dist/input/PasteHTMLHandler.d.ts +25 -0
  116. package/dist/input/PasteHTMLHandler.d.ts.map +1 -0
  117. package/dist/input/PasteHandler.d.ts +7 -25
  118. package/dist/input/PasteHandler.d.ts.map +1 -1
  119. package/dist/input/PasteRichBlockHandler.d.ts +23 -0
  120. package/dist/input/PasteRichBlockHandler.d.ts.map +1 -0
  121. package/dist/input/SelectionDocument.d.ts +10 -0
  122. package/dist/input/SelectionDocument.d.ts.map +1 -0
  123. package/dist/model/Document.d.ts.map +1 -1
  124. package/dist/model/HTMLUtils.d.ts +2 -0
  125. package/dist/model/HTMLUtils.d.ts.map +1 -1
  126. package/dist/model/PasteInterceptor.d.ts +21 -0
  127. package/dist/model/PasteInterceptor.d.ts.map +1 -0
  128. package/dist/model/RichBlockData.d.ts +34 -0
  129. package/dist/model/RichBlockData.d.ts.map +1 -0
  130. package/dist/model/SchemaRegistry.d.ts +2 -0
  131. package/dist/model/SchemaRegistry.d.ts.map +1 -1
  132. package/dist/notectl-core.mjs +1 -1
  133. package/dist/notectl-core.umd.js +1 -1
  134. package/dist/notectl-core.umd.js.map +1 -1
  135. package/dist/plugins/Plugin.d.ts +3 -0
  136. package/dist/plugins/Plugin.d.ts.map +1 -1
  137. package/dist/plugins/PluginContextFactory.d.ts +73 -0
  138. package/dist/plugins/PluginContextFactory.d.ts.map +1 -0
  139. package/dist/plugins/PluginManager.d.ts +12 -0
  140. package/dist/plugins/PluginManager.d.ts.map +1 -1
  141. package/dist/plugins/alignment/AlignmentPlugin.d.ts.map +1 -1
  142. package/dist/plugins/alignment.mjs +1 -1
  143. package/dist/plugins/alignment.mjs.map +1 -1
  144. package/dist/plugins/blockquote/BlockquoteKeyboardHandlers.d.ts.map +1 -1
  145. package/dist/plugins/blockquote/BlockquotePlugin.d.ts.map +1 -1
  146. package/dist/plugins/blockquote.mjs +1 -1
  147. package/dist/plugins/blockquote.mjs.map +1 -1
  148. package/dist/plugins/caret-navigation/CaretNavigationPlugin.d.ts.map +1 -1
  149. package/dist/plugins/caret-navigation.mjs +1 -1
  150. package/dist/plugins/code-block/CodeBlockKeyboardHandlers.d.ts.map +1 -1
  151. package/dist/plugins/code-block/CodeBlockPlugin.d.ts +5 -0
  152. package/dist/plugins/code-block/CodeBlockPlugin.d.ts.map +1 -1
  153. package/dist/plugins/code-block/CodeBlockTypes.d.ts +7 -0
  154. package/dist/plugins/code-block/CodeBlockTypes.d.ts.map +1 -1
  155. package/dist/plugins/code-block/highlighter/RegexTokenizer.d.ts +14 -0
  156. package/dist/plugins/code-block/highlighter/RegexTokenizer.d.ts.map +1 -0
  157. package/dist/plugins/code-block/highlighter/TokenizerTypes.d.ts +15 -0
  158. package/dist/plugins/code-block/highlighter/TokenizerTypes.d.ts.map +1 -0
  159. package/dist/plugins/code-block/highlighter/languages/index.d.ts +3 -0
  160. package/dist/plugins/code-block/highlighter/languages/index.d.ts.map +1 -0
  161. package/dist/plugins/code-block/highlighter/languages/json.d.ts +3 -0
  162. package/dist/plugins/code-block/highlighter/languages/json.d.ts.map +1 -0
  163. package/dist/plugins/code-block/highlighter/languages/xml.d.ts +3 -0
  164. package/dist/plugins/code-block/highlighter/languages/xml.d.ts.map +1 -0
  165. package/dist/plugins/code-block/index.d.ts +5 -1
  166. package/dist/plugins/code-block/index.d.ts.map +1 -1
  167. package/dist/plugins/code-block.mjs +1 -1
  168. package/dist/plugins/code-block.mjs.map +1 -1
  169. package/dist/plugins/font/FontPlugin.d.ts.map +1 -1
  170. package/dist/plugins/font-size/FontSizePlugin.d.ts.map +1 -1
  171. package/dist/plugins/font-size.mjs +1 -1
  172. package/dist/plugins/font-size.mjs.map +1 -1
  173. package/dist/plugins/font.mjs +1 -1
  174. package/dist/plugins/font.mjs.map +1 -1
  175. package/dist/plugins/gap-cursor/GapCursorPlugin.d.ts.map +1 -1
  176. package/dist/plugins/gap-cursor.mjs +1 -1
  177. package/dist/plugins/hard-break.mjs +1 -1
  178. package/dist/plugins/heading/HeadingInputRules.d.ts.map +1 -1
  179. package/dist/plugins/heading/HeadingKeyboardHandlers.d.ts.map +1 -1
  180. package/dist/plugins/heading/HeadingPlugin.d.ts.map +1 -1
  181. package/dist/plugins/heading.mjs +1 -1
  182. package/dist/plugins/highlight/HighlightPlugin.d.ts.map +1 -1
  183. package/dist/plugins/highlight.mjs +1 -1
  184. package/dist/plugins/highlight.mjs.map +1 -1
  185. package/dist/plugins/horizontal-rule/HorizontalRulePlugin.d.ts.map +1 -1
  186. package/dist/plugins/horizontal-rule.mjs +1 -1
  187. package/dist/plugins/horizontal-rule.mjs.map +1 -1
  188. package/dist/plugins/image/ImageCommands.d.ts.map +1 -1
  189. package/dist/plugins/image/ImagePlugin.d.ts +0 -1
  190. package/dist/plugins/image/ImagePlugin.d.ts.map +1 -1
  191. package/dist/plugins/image/ImagePopup.d.ts +11 -0
  192. package/dist/plugins/image/ImagePopup.d.ts.map +1 -0
  193. package/dist/plugins/image.mjs +1 -1
  194. package/dist/plugins/image.mjs.map +1 -1
  195. package/dist/plugins/link/LinkPlugin.d.ts.map +1 -1
  196. package/dist/plugins/link.mjs +1 -1
  197. package/dist/plugins/link.mjs.map +1 -1
  198. package/dist/plugins/list/ListPlugin.d.ts.map +1 -1
  199. package/dist/plugins/list.mjs +1 -1
  200. package/dist/plugins/list.mjs.map +1 -1
  201. package/dist/plugins/print/PrintPlugin.d.ts.map +1 -1
  202. package/dist/plugins/print.mjs +1 -1
  203. package/dist/plugins/print.mjs.map +1 -1
  204. package/dist/plugins/shared/ColorMarkOperations.d.ts +1 -2
  205. package/dist/plugins/shared/ColorMarkOperations.d.ts.map +1 -1
  206. package/dist/plugins/shared/ColorPickerPopup.d.ts +1 -8
  207. package/dist/plugins/shared/ColorPickerPopup.d.ts.map +1 -1
  208. package/dist/plugins/shared/PluginHelpers.d.ts +8 -0
  209. package/dist/plugins/shared/PluginHelpers.d.ts.map +1 -1
  210. package/dist/plugins/shared/PopupManager.d.ts.map +1 -1
  211. package/dist/plugins/shared/XmlPatterns.d.ts +10 -0
  212. package/dist/plugins/shared/XmlPatterns.d.ts.map +1 -0
  213. package/dist/plugins/shared/index.d.ts +1 -0
  214. package/dist/plugins/shared/index.d.ts.map +1 -1
  215. package/dist/plugins/shared.mjs +1 -1
  216. package/dist/plugins/shared.mjs.map +1 -1
  217. package/dist/plugins/smart-paste/SmartPasteLocale.d.ts +7 -0
  218. package/dist/plugins/smart-paste/SmartPasteLocale.d.ts.map +1 -0
  219. package/dist/plugins/smart-paste/SmartPastePlugin.d.ts +19 -0
  220. package/dist/plugins/smart-paste/SmartPastePlugin.d.ts.map +1 -0
  221. package/dist/plugins/smart-paste/SmartPasteTypes.d.ts +24 -0
  222. package/dist/plugins/smart-paste/SmartPasteTypes.d.ts.map +1 -0
  223. package/dist/plugins/smart-paste/detectors/JsonDetector.d.ts +6 -0
  224. package/dist/plugins/smart-paste/detectors/JsonDetector.d.ts.map +1 -0
  225. package/dist/plugins/smart-paste/detectors/XmlDetector.d.ts +26 -0
  226. package/dist/plugins/smart-paste/detectors/XmlDetector.d.ts.map +1 -0
  227. package/dist/plugins/smart-paste/index.d.ts +7 -0
  228. package/dist/plugins/smart-paste/index.d.ts.map +1 -0
  229. package/dist/plugins/smart-paste/locales/ar.d.ts +4 -0
  230. package/dist/plugins/smart-paste/locales/ar.d.ts.map +1 -0
  231. package/dist/plugins/smart-paste/locales/de.d.ts +4 -0
  232. package/dist/plugins/smart-paste/locales/de.d.ts.map +1 -0
  233. package/dist/plugins/smart-paste/locales/es.d.ts +4 -0
  234. package/dist/plugins/smart-paste/locales/es.d.ts.map +1 -0
  235. package/dist/plugins/smart-paste/locales/fr.d.ts +4 -0
  236. package/dist/plugins/smart-paste/locales/fr.d.ts.map +1 -0
  237. package/dist/plugins/smart-paste/locales/hi.d.ts +4 -0
  238. package/dist/plugins/smart-paste/locales/hi.d.ts.map +1 -0
  239. package/dist/plugins/smart-paste/locales/pt.d.ts +4 -0
  240. package/dist/plugins/smart-paste/locales/pt.d.ts.map +1 -0
  241. package/dist/plugins/smart-paste/locales/ru.d.ts +4 -0
  242. package/dist/plugins/smart-paste/locales/ru.d.ts.map +1 -0
  243. package/dist/plugins/smart-paste/locales/zh.d.ts +4 -0
  244. package/dist/plugins/smart-paste/locales/zh.d.ts.map +1 -0
  245. package/dist/plugins/smart-paste.mjs +2 -0
  246. package/dist/plugins/smart-paste.mjs.map +1 -0
  247. package/dist/plugins/strikethrough/StrikethroughPlugin.d.ts.map +1 -1
  248. package/dist/plugins/strikethrough.mjs +1 -1
  249. package/dist/plugins/strikethrough.mjs.map +1 -1
  250. package/dist/plugins/super-sub/SuperSubPlugin.d.ts.map +1 -1
  251. package/dist/plugins/super-sub.mjs +1 -1
  252. package/dist/plugins/super-sub.mjs.map +1 -1
  253. package/dist/plugins/table/TableCommands.d.ts +1 -0
  254. package/dist/plugins/table/TableCommands.d.ts.map +1 -1
  255. package/dist/plugins/table/TableContextMenu.d.ts.map +1 -1
  256. package/dist/plugins/table/TableNavigation.d.ts.map +1 -1
  257. package/dist/plugins/table/TablePlugin.d.ts.map +1 -1
  258. package/dist/plugins/table/TableSelection.d.ts.map +1 -1
  259. package/dist/plugins/table/index.d.ts +1 -0
  260. package/dist/plugins/table/index.d.ts.map +1 -1
  261. package/dist/plugins/table.mjs +1 -1
  262. package/dist/plugins/table.mjs.map +1 -1
  263. package/dist/plugins/text-color/TextColorPlugin.d.ts.map +1 -1
  264. package/dist/plugins/text-color.mjs +1 -1
  265. package/dist/plugins/text-color.mjs.map +1 -1
  266. package/dist/plugins/text-direction/TextDirectionCorePlugin.d.ts.map +1 -1
  267. package/dist/plugins/text-direction/TextDirectionPlugin.d.ts.map +1 -1
  268. package/dist/plugins/text-direction-advanced.mjs +1 -1
  269. package/dist/plugins/text-direction-advanced.mjs.map +1 -1
  270. package/dist/plugins/text-direction.mjs +1 -1
  271. package/dist/plugins/text-direction.mjs.map +1 -1
  272. package/dist/plugins/text-formatting/TextFormattingPlugin.d.ts.map +1 -1
  273. package/dist/plugins/text-formatting.mjs +1 -1
  274. package/dist/plugins/text-formatting.mjs.map +1 -1
  275. package/dist/plugins/toolbar/ToolbarOverflowController.d.ts +2 -0
  276. package/dist/plugins/toolbar/ToolbarOverflowController.d.ts.map +1 -1
  277. package/dist/plugins/toolbar/ToolbarPlugin.d.ts.map +1 -1
  278. package/dist/plugins/toolbar.mjs +1 -1
  279. package/dist/plugins/toolbar.mjs.map +1 -1
  280. package/dist/presets/FullPreset.d.ts.map +1 -1
  281. package/dist/presets/PresetTypes.d.ts +2 -0
  282. package/dist/presets/PresetTypes.d.ts.map +1 -1
  283. package/dist/presets/full.mjs +1 -1
  284. package/dist/presets/full.mjs.map +1 -1
  285. package/dist/serialization/DocumentSerializer.d.ts.map +1 -1
  286. package/dist/state/InlineContentOps.d.ts.map +1 -1
  287. package/dist/state/StepInversion.d.ts +7 -0
  288. package/dist/state/StepInversion.d.ts.map +1 -0
  289. package/dist/state/Steps.d.ts +108 -0
  290. package/dist/state/Steps.d.ts.map +1 -0
  291. package/dist/state/Transaction.d.ts +5 -174
  292. package/dist/state/Transaction.d.ts.map +1 -1
  293. package/dist/state/TransactionBuilder.d.ts +69 -0
  294. package/dist/state/TransactionBuilder.d.ts.map +1 -0
  295. package/dist/test/TestUtils.d.ts.map +1 -1
  296. package/dist/view/CaretNavigation.d.ts.map +1 -1
  297. package/dist/view/DomUtils.d.ts +10 -1
  298. package/dist/view/DomUtils.d.ts.map +1 -1
  299. package/dist/view/EditorView.d.ts +10 -60
  300. package/dist/view/EditorView.d.ts.map +1 -1
  301. package/dist/view/EditorViewEvents.d.ts +54 -0
  302. package/dist/view/EditorViewEvents.d.ts.map +1 -0
  303. package/dist/view/EditorViewNavigation.d.ts +47 -0
  304. package/dist/view/EditorViewNavigation.d.ts.map +1 -0
  305. package/dist/view/SelectionSync.d.ts.map +1 -1
  306. package/dist/view/ViewMovementCommands.d.ts.map +1 -1
  307. package/package.json +12 -2
  308. package/dist/chunks/AttributedMarkCommands-BB7lzFct.mjs +0 -2
  309. package/dist/chunks/AttributedMarkCommands-BB7lzFct.mjs.map +0 -1
  310. package/dist/chunks/ColorPickerPopup-DRzFvt7o.mjs.map +0 -1
  311. package/dist/chunks/Commands-P9wS8qtN.mjs +0 -2
  312. package/dist/chunks/Commands-P9wS8qtN.mjs.map +0 -1
  313. package/dist/chunks/Document-BFYAonMF.mjs +0 -2
  314. package/dist/chunks/Document-BFYAonMF.mjs.map +0 -1
  315. package/dist/chunks/DocumentParser-DFcvVMGY.mjs +0 -2
  316. package/dist/chunks/DocumentParser-DFcvVMGY.mjs.map +0 -1
  317. package/dist/chunks/DomUtils-Cdz1eDKM.mjs +0 -2
  318. package/dist/chunks/DomUtils-Cdz1eDKM.mjs.map +0 -1
  319. package/dist/chunks/HTMLUtils-CCvQ5f83.mjs +0 -2
  320. package/dist/chunks/HTMLUtils-CCvQ5f83.mjs.map +0 -1
  321. package/dist/chunks/HeadingPlugin-DYy3IoT_.mjs +0 -2
  322. package/dist/chunks/HeadingPlugin-DYy3IoT_.mjs.map +0 -1
  323. package/dist/chunks/LocaleService-B6Z-wyAF.mjs +0 -2
  324. package/dist/chunks/LocaleService-B6Z-wyAF.mjs.map +0 -1
  325. package/dist/chunks/MarkCommands-B_erV7zz.mjs +0 -2
  326. package/dist/chunks/MarkCommands-B_erV7zz.mjs.map +0 -1
  327. package/dist/chunks/NavigationQueries-ogQuObz7.mjs +0 -2
  328. package/dist/chunks/NavigationQueries-ogQuObz7.mjs.map +0 -1
  329. package/dist/chunks/NotectlEditor-4NFnXLyD.mjs +0 -2
  330. package/dist/chunks/NotectlEditor-4NFnXLyD.mjs.map +0 -1
  331. package/dist/chunks/Plugin-OzM8Oxm_.mjs +0 -2
  332. package/dist/chunks/Plugin-OzM8Oxm_.mjs.map +0 -1
  333. package/dist/chunks/PluginHelpers-DjZt0pQi.mjs +0 -2
  334. package/dist/chunks/PluginHelpers-DjZt0pQi.mjs.map +0 -1
  335. package/dist/chunks/PopupManager-BM8IT6M7.mjs +0 -2
  336. package/dist/chunks/PopupManager-BM8IT6M7.mjs.map +0 -1
  337. package/dist/chunks/PrintTypes-ehbL7ipA.mjs +0 -2
  338. package/dist/chunks/SelectionTransactions-q71GEzgE.mjs +0 -2
  339. package/dist/chunks/index-C8xtb3SM.mjs +0 -2
  340. package/dist/chunks/index-C8xtb3SM.mjs.map +0 -1
  341. package/dist/chunks/index-DAoSt12h.mjs +0 -2
  342. package/dist/chunks/index-DAoSt12h.mjs.map +0 -1
  343. package/dist/input/BlockInsertion.d.ts.map +0 -1
package/README.md CHANGED
@@ -38,10 +38,12 @@ npm install @notectl/core
38
38
  ### Preset — full editor in 5 lines
39
39
 
40
40
  ```ts
41
- import { createEditor, createFullPreset, ThemePreset } from '@notectl/core';
41
+ import { createEditor, ThemePreset } from '@notectl/core';
42
+ import { STARTER_FONTS } from '@notectl/core/fonts';
43
+ import { createFullPreset } from '@notectl/core/presets';
42
44
 
43
45
  const editor = await createEditor({
44
- ...createFullPreset(),
46
+ ...createFullPreset({ font: { fonts: STARTER_FONTS } }),
45
47
  theme: ThemePreset.Light,
46
48
  placeholder: 'Start typing...',
47
49
  });
@@ -49,7 +51,7 @@ const editor = await createEditor({
49
51
  document.body.appendChild(editor);
50
52
  ```
51
53
 
52
- All 19 plugins, toolbar groups, and keyboard shortcuts — ready to go.
54
+ All standard plugins, toolbar groups, and keyboard shortcuts — ready to go.
53
55
 
54
56
  ### Custom — pick exactly what you need
55
57
 
@@ -57,12 +59,12 @@ All 19 plugins, toolbar groups, and keyboard shortcuts — ready to go.
57
59
  import {
58
60
  createEditor,
59
61
  ThemePreset,
60
- TextFormattingPlugin,
61
- HeadingPlugin,
62
- ListPlugin,
63
- LinkPlugin,
64
- TablePlugin,
65
62
  } from '@notectl/core';
63
+ import { HeadingPlugin } from '@notectl/core/plugins/heading';
64
+ import { LinkPlugin } from '@notectl/core/plugins/link';
65
+ import { ListPlugin } from '@notectl/core/plugins/list';
66
+ import { TablePlugin } from '@notectl/core/plugins/table';
67
+ import { TextFormattingPlugin } from '@notectl/core/plugins/text-formatting';
66
68
 
67
69
  const editor = await createEditor({
68
70
  theme: ThemePreset.Light,
@@ -151,7 +153,7 @@ See the [plugin documentation](https://samyssmile.github.io/notectl/plugins/over
151
153
  ## Built-in Features
152
154
 
153
155
  - **Themes** — Dark and Light presets, or create fully custom themes
154
- - **i18n** — 8 languages: English, German, Spanish, French, Chinese, Russian, Arabic, Hindi + auto-detect via `Locale.BROWSER`
156
+ - **i18n** — 9 languages: English, German, Spanish, French, Chinese, Russian, Arabic, Hindi, Portuguese + auto-detect via `Locale.BROWSER`
155
157
  - **Paper sizes** — DIN A4, DIN A5, US Letter, US Legal for WYSIWYG page layout
156
158
  - **CSP-compliant** — Style delivery via `adoptedStyleSheets`, no inline styles required
157
159
  - **Markdown shortcuts** — `#` → H1, `##` → H2, `-` → bullet list, `1.` → ordered list, `>` → blockquote
@@ -165,7 +167,7 @@ Read and write content in any format:
165
167
 
166
168
  ```ts
167
169
  await editor.getContentHTML(); // export as HTML
168
- editor.setContentHTML('<p>Hello <strong>world</strong></p>'); // import HTML
170
+ await editor.setContentHTML('<p>Hello <strong>world</strong></p>'); // import HTML
169
171
  editor.getJSON(); // structured JSON
170
172
  editor.setJSON(doc); // import JSON
171
173
  editor.getText(); // plain text
@@ -1,2 +1,2 @@
1
- import{o as n}from"./Document-BFYAonMF.mjs";function t(n,t){return n.type===t}function e(n,t){return n.type===t}function r(t,e){return n(t)&&t.inlineType===e}export{e as a,t as b,r as i};
2
- //# sourceMappingURL=AttrRegistry-B2AGfTE0.mjs.map
1
+ import{o as n}from"./Document-3pNX7ear.mjs";function t(n,t){return n.type===t}function e(n,t){return n.type===t}function r(t,e){return n(t)&&t.inlineType===e}export{e as a,t as b,r as i};
2
+ //# sourceMappingURL=AttrRegistry-iNpjvcSG.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"AttrRegistry-B2AGfTE0.mjs","sources":["../../src/model/AttrRegistry.ts"],"sourcesContent":["/**\n * Module-augmentable attribute registries for type-safe node/mark attributes.\n *\n * Plugins extend these interfaces via `declare module`:\n * @example\n * declare module '../../model/AttrRegistry.js' {\n * interface NodeAttrRegistry {\n * heading: { level: HeadingLevel; align?: BlockAlignment };\n * }\n * }\n */\n\nimport type { BlockAlignment } from './BlockAlignment.js';\nimport type { BlockNode, InlineNode, Mark } from './Document.js';\nimport { isInlineNode } from './Document.js';\n\n/** Plugins augment this interface to register typed node attributes. */\nexport interface NodeAttrRegistry {\n\tparagraph: { align?: BlockAlignment };\n}\n\n/** Plugins augment this interface to register typed mark attributes. */\nexport interface MarkAttrRegistry {\n\tbold: Record<string, never>;\n\titalic: Record<string, never>;\n\tunderline: Record<string, never>;\n}\n\n/** Resolves typed attributes for known node types, falls back for unknown. */\nexport type NodeAttrsFor<T extends string> = T extends keyof NodeAttrRegistry\n\t? NodeAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Resolves typed attributes for known mark types, falls back for unknown. */\nexport type MarkAttrsFor<T extends string> = T extends keyof MarkAttrRegistry\n\t? MarkAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Narrows a BlockNode to a typed variant with known attributes. */\nexport function isNodeOfType<T extends keyof NodeAttrRegistry>(\n\tnode: BlockNode,\n\ttype: T,\n): node is BlockNode & { readonly type: T; readonly attrs: NodeAttrRegistry[T] } {\n\treturn (node.type as string) === type;\n}\n\n/** Narrows a Mark to a typed variant with known attributes. */\nexport function isMarkOfType<T extends keyof MarkAttrRegistry>(\n\tmark: Mark,\n\ttype: T,\n): mark is Mark & { readonly type: T; readonly attrs: MarkAttrRegistry[T] } {\n\treturn (mark.type as string) === type;\n}\n\n// --- InlineNode Attribute Registry ---\n\n/** Plugins augment this interface to register typed inline node attributes. */\n// biome-ignore lint/suspicious/noEmptyInterface: module augmentation requires interface\nexport interface InlineNodeAttrRegistry {}\n\n/** Resolves typed attributes for known inline node types, falls back for unknown. */\nexport type InlineNodeAttrsFor<T extends string> = T extends keyof InlineNodeAttrRegistry\n\t? InlineNodeAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Narrows an InlineNode to a typed variant with known attributes. */\nexport function isInlineNodeOfType<T extends keyof InlineNodeAttrRegistry>(\n\tnode: InlineNode,\n\tinlineNodeType: T,\n): node is InlineNode & {\n\treadonly inlineType: T;\n\treadonly attrs: InlineNodeAttrRegistry[T];\n} {\n\treturn isInlineNode(node) && (node.inlineType as string) === inlineNodeType;\n}\n"],"names":["isNodeOfType","node","type","isMarkOfType","mark","isInlineNodeOfType","inlineNodeType","isInlineNode","inlineType"],"mappings":"4CAuCO,SAASA,EACfC,EACAC,GAEA,OAAQD,EAAKC,OAAoBA,CAClC,CAGO,SAASC,EACfC,EACAF,GAEA,OAAQE,EAAKF,OAAoBA,CAClC,CAcO,SAASG,EACfJ,EACAK,GAKA,OAAOC,EAAaN,IAAUA,EAAKO,aAA0BF,CAC9D"}
1
+ {"version":3,"file":"AttrRegistry-iNpjvcSG.mjs","sources":["../../src/model/AttrRegistry.ts"],"sourcesContent":["/**\n * Module-augmentable attribute registries for type-safe node/mark attributes.\n *\n * Plugins extend these interfaces via `declare module`:\n * @example\n * declare module '../../model/AttrRegistry.js' {\n * interface NodeAttrRegistry {\n * heading: { level: HeadingLevel; align?: BlockAlignment };\n * }\n * }\n */\n\nimport type { BlockAlignment } from './BlockAlignment.js';\nimport type { BlockNode, InlineNode, Mark } from './Document.js';\nimport { isInlineNode } from './Document.js';\n\n/** Plugins augment this interface to register typed node attributes. */\nexport interface NodeAttrRegistry {\n\tparagraph: { align?: BlockAlignment };\n}\n\n/** Plugins augment this interface to register typed mark attributes. */\nexport interface MarkAttrRegistry {\n\tbold: Record<string, never>;\n\titalic: Record<string, never>;\n\tunderline: Record<string, never>;\n}\n\n/** Resolves typed attributes for known node types, falls back for unknown. */\nexport type NodeAttrsFor<T extends string> = T extends keyof NodeAttrRegistry\n\t? NodeAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Resolves typed attributes for known mark types, falls back for unknown. */\nexport type MarkAttrsFor<T extends string> = T extends keyof MarkAttrRegistry\n\t? MarkAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Narrows a BlockNode to a typed variant with known attributes. */\nexport function isNodeOfType<T extends keyof NodeAttrRegistry>(\n\tnode: BlockNode,\n\ttype: T,\n): node is BlockNode & { readonly type: T; readonly attrs: NodeAttrRegistry[T] } {\n\treturn (node.type as string) === type;\n}\n\n/** Narrows a Mark to a typed variant with known attributes. */\nexport function isMarkOfType<T extends keyof MarkAttrRegistry>(\n\tmark: Mark,\n\ttype: T,\n): mark is Mark & { readonly type: T; readonly attrs: MarkAttrRegistry[T] } {\n\treturn (mark.type as string) === type;\n}\n\n// --- InlineNode Attribute Registry ---\n\n/** Plugins augment this interface to register typed inline node attributes. */\n// biome-ignore lint/suspicious/noEmptyInterface: module augmentation requires interface\nexport interface InlineNodeAttrRegistry {}\n\n/** Resolves typed attributes for known inline node types, falls back for unknown. */\nexport type InlineNodeAttrsFor<T extends string> = T extends keyof InlineNodeAttrRegistry\n\t? InlineNodeAttrRegistry[T]\n\t: Record<string, string | number | boolean>;\n\n/** Narrows an InlineNode to a typed variant with known attributes. */\nexport function isInlineNodeOfType<T extends keyof InlineNodeAttrRegistry>(\n\tnode: InlineNode,\n\tinlineNodeType: T,\n): node is InlineNode & {\n\treadonly inlineType: T;\n\treadonly attrs: InlineNodeAttrRegistry[T];\n} {\n\treturn isInlineNode(node) && (node.inlineType as string) === inlineNodeType;\n}\n"],"names":["isNodeOfType","node","type","isMarkOfType","mark","isInlineNodeOfType","inlineNodeType","isInlineNode","inlineType"],"mappings":"4CAuCO,SAASA,EACfC,EACAC,GAEA,OAAQD,EAAKC,OAAoBA,CAClC,CAGO,SAASC,EACfC,EACAF,GAEA,OAAQE,EAAKF,OAAoBA,CAClC,CAcO,SAASG,EACfJ,EACAK,GAKA,OAAOC,EAAaN,IAAUA,EAAKO,aAA0BF,CAC9D"}
@@ -0,0 +1,2 @@
1
+ import{a as t}from"./AttrRegistry-iNpjvcSG.mjs";import{h as n,m as o,k as r,q as e}from"./Document-3pNX7ear.mjs";import{j as s,i as c,s as a}from"./Selection-DhbizDM4.mjs";import{m as i}from"./TypeBrands-Bp_Z_o5Y.mjs";import{f as l}from"./RangeIterator-XFN5FaYf.mjs";function f(t,o){const r=t.selection;if(!s(r))return null;const e=i(o.type);if(c(r)){const s=t.getBlock(r.anchor.blockId);if(!s)return null;const c=[...(t.storedMarks??n(s,r.anchor.offset)).filter(t=>t.type!==e),o];return t.transaction("command").setStoredMarks(c,t.storedMarks).setSelection(r).build()}const f=a(r,t.getBlockOrder()),u=t.transaction("command");return l(t,f,(n,r,s)=>{const c=t.getBlock(n);if(c){const t=k(c,e,r,s);t&&u.removeMark(n,r,s,t)}u.addMark(n,r,s,o)}),u.setSelection(r),u.build()}function u(t,r){const e=t.selection;if(!s(e))return null;if(c(e)){const s=t.getBlock(e.anchor.blockId);if(!s)return null;const c=t.storedMarks??n(s,e.anchor.offset);if(!o(c,r))return null;const a=c.filter(t=>t.type!==r);return t.transaction("command").setStoredMarks(a,t.storedMarks).setSelection(e).build()}const i=a(e,t.getBlockOrder()),f=t.transaction("command");return l(t,i,(n,o,e)=>{const s=t.getBlock(n),c=s?k(s,r,o,e):void 0;f.removeMark(n,o,e,c??{type:r})}),f.setSelection(e),f.build()}function m(o,r,e){const a=o.selection;if(!s(a))return null;if(c(a)&&o.storedMarks){const n=o.storedMarks.find(t=>t.type===r);return n&&t(n,r)?e(n):null}const i=o.getBlock(a.anchor.blockId);if(!i)return null;const l=n(i,a.anchor.offset).find(t=>t.type===r);return l&&t(l,r)?e(l):null}function d(t,n){return null!==m(t,n,()=>!0)}function k(t,n,o,s){const c=r(t);let a=0;for(const r of c){if(!e(r)){a+=1;continue}const t=a+r.text.length;if(t>o&&a<s){const t=r.marks.find(t=>t.type===n);if(t)return t}a=t}}export{f as a,m as g,d as i,u as r};
2
+ //# sourceMappingURL=AttributedMarkCommands-BY1BSYWM.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttributedMarkCommands-BY1BSYWM.mjs","sources":["../../src/commands/AttributedMarkCommands.ts"],"sourcesContent":["/**\n * Generic helpers for attributed marks (marks with key/value attrs).\n *\n * Unlike boolean marks (`bold`, `italic`) that toggle on/off, attributed\n * marks (`font`, `fontSize`, `textColor`, `highlight`) carry data and use\n * **replace** semantics: applying a new value removes the old one first.\n *\n * These helpers extract the duplicated collapsed-vs-range branching that\n * was previously copy-pasted across ColorMarkOperations, FontSizeOperations,\n * and FontPlugin.\n */\n\nimport { isMarkOfType } from '../model/AttrRegistry.js';\nimport type { MarkAttrRegistry } from '../model/AttrRegistry.js';\nimport type { BlockNode, Mark, TextNode } from '../model/Document.js';\nimport {\n\tgetBlockMarksAtOffset,\n\tgetInlineChildren,\n\thasMark,\n\tisTextNode,\n} from '../model/Document.js';\nimport type { InlineNode } from '../model/Document.js';\nimport { isCollapsed, isTextSelection, selectionRange } from '../model/Selection.js';\nimport { markType } from '../model/TypeBrands.js';\nimport type { MarkTypeName } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { forEachBlockInRange } from './RangeIterator.js';\n\n/**\n * Applies an attributed mark to the current selection.\n *\n * - **Collapsed cursor**: replaces stored marks (filters out old mark of the\n * same type, appends the new one).\n * - **Range selection**: removes then re-adds the mark in every block span.\n *\n * Returns the built `Transaction`, or `null` when the selection is\n * unsupported (node-selection / gap-cursor) or the anchor block is missing.\n */\nexport function applyAttributedMark(state: EditorState, mark: Mark): Transaction | null {\n\tconst sel = state.selection;\n\tif (!isTextSelection(sel)) return null;\n\n\tconst typeName: MarkTypeName = markType(mark.type as string);\n\n\tif (isCollapsed(sel)) {\n\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\tif (!anchorBlock) return null;\n\t\tconst currentMarks: readonly Mark[] =\n\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\tconst withoutMark: readonly Mark[] = currentMarks.filter((m) => m.type !== typeName);\n\t\tconst newMarks: readonly Mark[] = [...withoutMark, mark];\n\n\t\treturn state\n\t\t\t.transaction('command')\n\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t}\n\n\tconst range = selectionRange(sel, state.getBlockOrder());\n\tconst builder = state.transaction('command');\n\n\tforEachBlockInRange(state, range, (blockId, from, to) => {\n\t\tconst block: BlockNode | undefined = state.getBlock(blockId);\n\t\tif (block) {\n\t\t\tconst existing: Mark | undefined = findMarkInRange(block, typeName, from, to);\n\t\t\tif (existing) {\n\t\t\t\tbuilder.removeMark(blockId, from, to, existing);\n\t\t\t}\n\t\t}\n\t\tbuilder.addMark(blockId, from, to, mark);\n\t});\n\n\tbuilder.setSelection(sel);\n\treturn builder.build();\n}\n\n/**\n * Removes an attributed mark from the current selection.\n *\n * - **Collapsed cursor**: filters the mark out of stored marks.\n * Returns `null` when the mark was not present.\n * - **Range selection**: removes the mark across all block spans.\n *\n * Returns the built `Transaction`, or `null` when the selection is\n * unsupported or the mark is absent at a collapsed cursor.\n */\nexport function removeAttributedMark(\n\tstate: EditorState,\n\tmarkTypeName: MarkTypeName,\n): Transaction | null {\n\tconst sel = state.selection;\n\tif (!isTextSelection(sel)) return null;\n\n\tif (isCollapsed(sel)) {\n\t\tconst anchorBlock = state.getBlock(sel.anchor.blockId);\n\t\tif (!anchorBlock) return null;\n\t\tconst currentMarks: readonly Mark[] =\n\t\t\tstate.storedMarks ?? getBlockMarksAtOffset(anchorBlock, sel.anchor.offset);\n\t\tif (!hasMark(currentMarks, markTypeName)) return null;\n\n\t\tconst newMarks: readonly Mark[] = currentMarks.filter((m) => m.type !== markTypeName);\n\t\treturn state\n\t\t\t.transaction('command')\n\t\t\t.setStoredMarks(newMarks, state.storedMarks)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t}\n\n\tconst range = selectionRange(sel, state.getBlockOrder());\n\tconst builder = state.transaction('command');\n\n\tforEachBlockInRange(state, range, (blockId, from, to) => {\n\t\tconst block: BlockNode | undefined = state.getBlock(blockId);\n\t\tconst existing: Mark | undefined = block\n\t\t\t? findMarkInRange(block, markTypeName, from, to)\n\t\t\t: undefined;\n\t\tbuilder.removeMark(blockId, from, to, existing ?? { type: markTypeName });\n\t});\n\n\tbuilder.setSelection(sel);\n\treturn builder.build();\n}\n\n/**\n * Extracts a typed attribute value from the mark at the current selection.\n *\n * Looks at stored marks (collapsed w/ stored), block marks at cursor offset\n * (collapsed w/o stored), or anchor-block marks (range).\n *\n * @param extractFn — Narrows the found mark and returns the desired value,\n * or `null` when the mark's attrs don't match expectations.\n */\nexport function getMarkAttrAtSelection<K extends keyof MarkAttrRegistry, V>(\n\tstate: EditorState,\n\tmarkTypeName: K,\n\textractFn: (mark: Mark & { readonly type: K; readonly attrs: MarkAttrRegistry[K] }) => V | null,\n): V | null {\n\tconst sel = state.selection;\n\tif (!isTextSelection(sel)) return null;\n\n\tif (isCollapsed(sel) && state.storedMarks) {\n\t\tconst found = state.storedMarks.find((m) => (m.type as string) === markTypeName);\n\t\treturn found && isMarkOfType(found, markTypeName) ? extractFn(found) : null;\n\t}\n\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\tconst marks: readonly Mark[] = getBlockMarksAtOffset(block, sel.anchor.offset);\n\tconst found = marks.find((m) => (m.type as string) === markTypeName);\n\treturn found && isMarkOfType(found, markTypeName) ? extractFn(found) : null;\n}\n\n/**\n * Returns `true` when the given attributed mark type is present at the\n * current selection (collapsed or range).\n */\nexport function isAttributedMarkActive<K extends keyof MarkAttrRegistry>(\n\tstate: EditorState,\n\tmarkTypeName: K,\n): boolean {\n\treturn getMarkAttrAtSelection(state, markTypeName, () => true as const) !== null;\n}\n\n/**\n * Finds the first mark of the given type within an offset range of a block.\n *\n * Returns the full mark (including attrs) so callers can pass it to\n * `removeMark` for correct undo inversion, or `undefined` when absent.\n */\nfunction findMarkInRange(\n\tblock: BlockNode,\n\ttypeName: MarkTypeName,\n\tfrom: number,\n\tto: number,\n): Mark | undefined {\n\tconst children: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet pos = 0;\n\n\tfor (const child of children) {\n\t\tif (!isTextNode(child)) {\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst nodeEnd: number = pos + child.text.length;\n\t\tif (nodeEnd > from && pos < to) {\n\t\t\tconst found: Mark | undefined = child.marks.find((m) => m.type === typeName);\n\t\t\tif (found) return found;\n\t\t}\n\t\tpos = nodeEnd;\n\t}\n\treturn undefined;\n}\n"],"names":["applyAttributedMark","state","mark","sel","selection","isTextSelection","typeName","markType","type","isCollapsed","anchorBlock","getBlock","anchor","blockId","newMarks","storedMarks","getBlockMarksAtOffset","offset","filter","m","transaction","setStoredMarks","setSelection","build","range","selectionRange","getBlockOrder","builder","forEachBlockInRange","from","to","block","existing","findMarkInRange","removeMark","addMark","removeAttributedMark","markTypeName","currentMarks","hasMark","getMarkAttrAtSelection","extractFn","found","find","isMarkOfType","isAttributedMarkActive","children","getInlineChildren","pos","child","isTextNode","nodeEnd","text","length","marks"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{n as t,s as n,c as e,i as o,e as r,d as s}from"./Document-3pNX7ear.mjs";import{a as i}from"./NodeResolver-z0ReCR34.mjs";import{h as c,g as a}from"./Selection-DhbizDM4.mjs";import{n as f,i as u}from"./TypeBrands-Bp_Z_o5Y.mjs";import{e as d,g as p,f as m}from"./CommandHelpers-M6mPS6Ww.mjs";function l(t,n,e){const o=i(t.doc,n),r=d(o),s=p(t,r),c=m(s,n);if(!(c<0))return{parentPath:r,anchorIndex:c,isAnchorEmpty:b(t,n,e)}}function h(n,e,o,r){const s=i(n.doc,o);if(!s)return;const c=n.getBlock(o);return c?{parentPath:s,anchorIndex:c.children.findIndex(n=>t(n)&&n.id===e),isAnchorEmpty:b(n,e,r)}:void 0}function y(t,n){const e=t.getBlock(n);if("table_cell"===e?.type)return n;const o=i(t.doc,n);if(o)for(const r of o){const n=t.getBlock(r);if("table_cell"===n?.type)return r}}function g(t){return c(t)?t.nodeId:a(t)?t.blockId:t.anchor.blockId}function x(t,n,e,o,r,s){const i=y(t,e);if(i){const r=h(t,e,i,s);if(!r)return!1;const c=r.anchorIndex+1;n.insertNode(r.parentPath,c,o),r.isAnchorEmpty&&r.anchorIndex>=0&&n.removeNode(r.parentPath,r.anchorIndex)}else{const i=l(t,e,s);if(!i)return!1;const c=a(r)&&"before"===r.side?0:1;n.insertNode(i.parentPath,i.anchorIndex+c,o),i.isAnchorEmpty&&!a(r)&&n.removeNode(i.parentPath,i.anchorIndex)}return!0}function I(o,r){const s=o.children.map(e=>t(e)?I(e,n()):e);return e(o.type,s,r,o.attrs)}function k(n,e){if(n.id===e)return n;for(const o of n.children){if(!t(o))continue;const n=k(o,e);if(n)return n}}function v(t,n){if(!n)return;const e={};let o=!1;for(const r of Object.keys(n)){const s=n[r],i=t?.[r];"string"==typeof i||"number"==typeof i||"boolean"==typeof i?e[r]=i:void 0!==s.default&&(e[r]=s.default),r in e&&(o=!0)}return o?e:void 0}function b(t,n,e){const r=t.getBlock(n);if(!r)return!1;const s=e?.getNodeSpec(r.type);return!s?.isVoid&&""===o(r)}function N(t,n){if(!t.type)return;if(!n)return t;const e=n.getNodeSpec(t.type);if(!e)return;const o=v(t.attrs,e.attrs),r=t.segments?function(t,n){const e=[];for(const o of t){if("inline"===o.kind){const t=n.getInlineNodeSpec(o.inlineType);if(!t)continue;const r=v(o.attrs,t.attrs);e.push({kind:"inline",inlineType:o.inlineType,...r?{attrs:r}:{}});continue}e.push(o)}return e}(t.segments,n):void 0;return{...t,...o?{attrs:o}:{},...r?{segments:r}:t.segments?{segments:[]}:{}}}function j(t){const o=n(),i=function(t,n){return t.segments&&t.segments.length>0?function(t){const n=[];for(const e of t){if("inline"===e.kind){n.push(s(u(e.inlineType),e.attrs));continue}if(0===e.text.length)continue;const t=e.marks.map(t=>({type:t.type,...t.attrs?{attrs:t.attrs}:{}}));n.push(r(e.text,t))}return n}(t.segments):n?[r(n)]:void 0}(t,t.text??""),c=t.attrs?t.attrs:void 0;return e(f(t.type),i,o,c)}export{y as a,h as b,I as c,j as d,g as e,k as f,x as i,l as r,v as s,N as v};
2
+ //# sourceMappingURL=BlockInsertion-BJFhE0jA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlockInsertion-BJFhE0jA.mjs","sources":["../../src/commands/BlockInsertion.ts"],"sourcesContent":["/**\n * Block insertion utilities for paste and clipboard operations.\n *\n * Provides context resolution (parent path, anchor index, empty detection)\n * for inserting blocks into the document tree — both at root level and\n * inside table cells. Also contains pure helpers for block cloning,\n * recursive lookup, and attribute sanitization against a NodeSpec.\n */\n\nimport {\n\ttype BlockAttrs,\n\ttype BlockNode,\n\ttype ChildNode,\n\ttype InlineNode,\n\ttype Mark,\n\ttype TextNode,\n\tcreateBlockNode,\n\tcreateInlineNode,\n\tcreateTextNode,\n\tgenerateBlockId,\n\tgetBlockText,\n\tisBlockNode,\n} from '../model/Document.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { AttrSpec } from '../model/NodeSpec.js';\nimport type { RichBlockData, RichSegment } from '../model/RichBlockData.js';\nimport type { SchemaRegistry } from '../model/SchemaRegistry.js';\nimport type { EditorSelection } from '../model/Selection.js';\nimport { isGapCursor, isNodeSelection } from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport { inlineType, nodeType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { TransactionBuilder } from '../state/Transaction.js';\nimport { extractParentPath, findSiblingIndex, getSiblings } from './CommandHelpers.js';\n\n/**\n * Resolved insertion target within the document tree.\n * Contains everything needed to insert blocks at a specific anchor position.\n */\nexport interface InsertionContext {\n\treadonly parentPath: readonly BlockId[];\n\treadonly anchorIndex: number;\n\treadonly isAnchorEmpty: boolean;\n}\n\n/**\n * Resolves an insertion context for root-level (or nested-parent-level) insertion.\n * Computes the parent path, anchor index among siblings, and whether the anchor is empty.\n */\nexport function resolveRootInsertionContext(\n\tstate: EditorState,\n\tanchorBlockId: BlockId,\n\tschemaRegistry?: SchemaRegistry,\n): InsertionContext | undefined {\n\tconst path: readonly string[] | undefined = findNodePath(state.doc, anchorBlockId);\n\tconst parentPath: BlockId[] = extractParentPath(path);\n\n\tconst siblings: readonly ChildNode[] = getSiblings(state, parentPath);\n\tconst anchorIndex: number = findSiblingIndex(siblings, anchorBlockId);\n\tif (anchorIndex < 0) return undefined;\n\n\tconst isAnchorEmpty: boolean = isBlockEmpty(state, anchorBlockId, schemaRegistry);\n\treturn { parentPath, anchorIndex, isAnchorEmpty };\n}\n\n/**\n * Resolves an insertion context within a table cell.\n * The parent path points to the cell itself; siblings are the cell's children.\n */\nexport function resolveCellInsertionContext(\n\tstate: EditorState,\n\tanchorBlockId: BlockId,\n\tcellId: BlockId,\n\tschemaRegistry?: SchemaRegistry,\n): InsertionContext | undefined {\n\tconst cellPath: BlockId[] | undefined = findNodePath(state.doc, cellId) as BlockId[] | undefined;\n\tif (!cellPath) return undefined;\n\n\tconst cell: BlockNode | undefined = state.getBlock(cellId);\n\tif (!cell) return undefined;\n\n\tconst anchorIndex: number = cell.children.findIndex(\n\t\t(c) => isBlockNode(c) && c.id === anchorBlockId,\n\t);\n\n\tconst isAnchorEmpty: boolean = isBlockEmpty(state, anchorBlockId, schemaRegistry);\n\treturn { parentPath: cellPath, anchorIndex, isAnchorEmpty };\n}\n\n/**\n * Finds a table_cell ancestor for the given block.\n * Walks the node path upward, returning the first table_cell BlockId found.\n */\nexport function findTableCellAncestor(state: EditorState, blockId: BlockId): BlockId | undefined {\n\tconst block: BlockNode | undefined = state.getBlock(blockId);\n\tif (block?.type === 'table_cell') return blockId;\n\n\tconst path: BlockId[] | undefined = findNodePath(state.doc, blockId) as BlockId[] | undefined;\n\tif (!path) return undefined;\n\n\tfor (const id of path) {\n\t\tconst node: BlockNode | undefined = state.getBlock(id as BlockId);\n\t\tif (node?.type === 'table_cell') return id as BlockId;\n\t}\n\treturn undefined;\n}\n\n/**\n * Resolves the anchor block ID from the current editor selection.\n * Handles text selection, node selection, and gap cursor uniformly.\n */\nexport function resolveAnchorBlockId(selection: EditorSelection): BlockId {\n\tif (isNodeSelection(selection)) return selection.nodeId;\n\tif (isGapCursor(selection)) return selection.blockId;\n\treturn selection.anchor.blockId;\n}\n\n/**\n * Inserts a block node after the anchor position, resolving cell vs root context.\n * Removes the anchor block if it is empty (matching standard paste behavior).\n * Returns true on success, false if context resolution fails.\n */\nexport function insertBlockAfterAnchor(\n\tstate: EditorState,\n\tbuilder: TransactionBuilder,\n\tanchorBlockId: BlockId,\n\tblock: BlockNode,\n\tselection: EditorSelection,\n\tschemaRegistry?: SchemaRegistry,\n): boolean {\n\tconst cellId: BlockId | undefined = findTableCellAncestor(state, anchorBlockId);\n\n\tif (cellId) {\n\t\tconst ctx: InsertionContext | undefined = resolveCellInsertionContext(\n\t\t\tstate,\n\t\t\tanchorBlockId,\n\t\t\tcellId,\n\t\t\tschemaRegistry,\n\t\t);\n\t\tif (!ctx) return false;\n\n\t\tconst insertIndex: number = ctx.anchorIndex + 1;\n\t\tbuilder.insertNode(ctx.parentPath, insertIndex, block);\n\n\t\tif (ctx.isAnchorEmpty && ctx.anchorIndex >= 0) {\n\t\t\tbuilder.removeNode(ctx.parentPath, ctx.anchorIndex);\n\t\t}\n\t} else {\n\t\tconst ctx: InsertionContext | undefined = resolveRootInsertionContext(\n\t\t\tstate,\n\t\t\tanchorBlockId,\n\t\t\tschemaRegistry,\n\t\t);\n\t\tif (!ctx) return false;\n\n\t\tconst insertOffset: number = isGapCursor(selection) && selection.side === 'before' ? 0 : 1;\n\t\tbuilder.insertNode(ctx.parentPath, ctx.anchorIndex + insertOffset, block);\n\n\t\tif (ctx.isAnchorEmpty && !isGapCursor(selection)) {\n\t\t\tbuilder.removeNode(ctx.parentPath, ctx.anchorIndex);\n\t\t}\n\t}\n\n\treturn true;\n}\n\n/** Recursively clones a block tree, assigning new IDs to all block nodes. */\nexport function cloneBlockWithNewIds(block: BlockNode, newId: BlockId): BlockNode {\n\tconst children = block.children.map((child) => {\n\t\tif (isBlockNode(child)) {\n\t\t\treturn cloneBlockWithNewIds(child, generateBlockId());\n\t\t}\n\t\treturn child;\n\t});\n\treturn createBlockNode(block.type, children, newId, block.attrs);\n}\n\n/** Recursively searches a block tree for a block with the given ID (DFS). */\nexport function findBlockRecursive(block: BlockNode, blockId: BlockId): BlockNode | undefined {\n\tif (block.id === blockId) return block;\n\tfor (const child of block.children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tconst found: BlockNode | undefined = findBlockRecursive(child, blockId);\n\t\tif (found) return found;\n\t}\n\treturn undefined;\n}\n\n/**\n * Validates incoming attributes against the declared AttrSpec.\n * Only keys declared in the spec are kept; non-primitive values fall back to defaults.\n */\nexport function sanitizeAttrs(\n\tincoming: Record<string, unknown> | undefined,\n\tspecAttrs: Readonly<Record<string, AttrSpec>> | undefined,\n): Record<string, string | number | boolean> | undefined {\n\tif (!specAttrs) return undefined;\n\n\tconst result: Record<string, string | number | boolean> = {};\n\tlet hasKeys = false;\n\n\tfor (const key of Object.keys(specAttrs)) {\n\t\tconst spec: AttrSpec = specAttrs[key] as AttrSpec;\n\t\tconst raw: unknown = incoming?.[key];\n\n\t\tif (typeof raw === 'string' || typeof raw === 'number' || typeof raw === 'boolean') {\n\t\t\tresult[key] = raw;\n\t\t} else if (spec.default !== undefined) {\n\t\t\tresult[key] = spec.default;\n\t\t}\n\t\tif (key in result) hasKeys = true;\n\t}\n\n\treturn hasKeys ? result : undefined;\n}\n\n/** Checks whether a block is empty (has no text and is not a void block). */\nfunction isBlockEmpty(\n\tstate: EditorState,\n\tblockId: BlockId,\n\tschemaRegistry?: SchemaRegistry,\n): boolean {\n\tconst block: BlockNode | undefined = state.getBlock(blockId);\n\tif (!block) return false;\n\n\tconst spec = schemaRegistry?.getNodeSpec(block.type);\n\treturn !spec?.isVoid && getBlockText(block) === '';\n}\n\n// --- Rich block creation ---\n\n/**\n * Validates a rich block against the schema registry.\n * Returns undefined for blocks with unknown types; sanitizes attributes\n * against the declared spec.\n */\nexport function validateRichBlockData(\n\traw: RichBlockData,\n\tschemaRegistry?: SchemaRegistry,\n): RichBlockData | undefined {\n\tif (!raw.type) return undefined;\n\tif (!schemaRegistry) return raw;\n\n\tconst spec = schemaRegistry.getNodeSpec(raw.type);\n\tif (!spec) return undefined;\n\n\tconst attrs: Record<string, string | number | boolean> | undefined = sanitizeAttrs(\n\t\traw.attrs,\n\t\tspec.attrs,\n\t);\n\tconst segments: RichSegment[] | undefined = raw.segments\n\t\t? sanitizeRichSegments(raw.segments, schemaRegistry)\n\t\t: undefined;\n\treturn {\n\t\t...raw,\n\t\t...(attrs ? { attrs } : {}),\n\t\t...(segments ? { segments } : raw.segments ? { segments: [] } : {}),\n\t};\n}\n\n/**\n * Creates a BlockNode from validated rich block data.\n * Converts segments or plain text into inline children.\n */\nexport function createBlockFromRichData(blockData: RichBlockData): BlockNode {\n\tconst newId: BlockId = generateBlockId();\n\tconst text: string = blockData.text ?? '';\n\tconst children: readonly (TextNode | InlineNode)[] | undefined = createChildrenFromRichBlock(\n\t\tblockData,\n\t\ttext,\n\t);\n\tconst attrs: BlockAttrs | undefined = blockData.attrs\n\t\t? (blockData.attrs as BlockAttrs)\n\t\t: undefined;\n\n\treturn createBlockNode(nodeType(blockData.type) as NodeTypeName, children, newId, attrs);\n}\n\n/**\n * Creates inline children from rich block data.\n * Uses mark-preserving segments when available, falls back to plain text.\n */\nfunction createChildrenFromRichBlock(\n\tblockData: RichBlockData,\n\ttext: string,\n): readonly (TextNode | InlineNode)[] | undefined {\n\tif (blockData.segments && blockData.segments.length > 0) {\n\t\treturn createChildrenFromSegments(blockData.segments);\n\t}\n\treturn text ? [createTextNode(text)] : undefined;\n}\n\n/** Converts rich segments into TextNode children with marks. */\nfunction createChildrenFromSegments(\n\tsegments: readonly RichSegment[],\n): readonly (TextNode | InlineNode)[] {\n\tconst children: (TextNode | InlineNode)[] = [];\n\tfor (const seg of segments) {\n\t\tif (seg.kind === 'inline') {\n\t\t\tchildren.push(\n\t\t\t\tcreateInlineNode(\n\t\t\t\t\tinlineType(seg.inlineType),\n\t\t\t\t\tseg.attrs as Readonly<Record<string, string | number | boolean>> | undefined,\n\t\t\t\t),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tif (seg.text.length === 0) continue;\n\t\tconst marks: readonly Mark[] = seg.marks.map((m) => ({\n\t\t\ttype: m.type as Mark['type'],\n\t\t\t...(m.attrs ? { attrs: m.attrs as Mark['attrs'] } : {}),\n\t\t}));\n\t\tchildren.push(createTextNode(seg.text, marks));\n\t}\n\treturn children;\n}\n\nfunction sanitizeRichSegments(\n\tsegments: readonly RichSegment[],\n\tschemaRegistry: SchemaRegistry,\n): RichSegment[] {\n\tconst sanitized: RichSegment[] = [];\n\tfor (const segment of segments) {\n\t\tif (segment.kind === 'inline') {\n\t\t\tconst spec = schemaRegistry.getInlineNodeSpec(segment.inlineType);\n\t\t\tif (!spec) continue;\n\t\t\tconst attrs = sanitizeAttrs(segment.attrs, spec.attrs);\n\t\t\tsanitized.push({\n\t\t\t\tkind: 'inline',\n\t\t\t\tinlineType: segment.inlineType,\n\t\t\t\t...(attrs ? { attrs } : {}),\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tsanitized.push(segment);\n\t}\n\treturn sanitized;\n}\n"],"names":["resolveRootInsertionContext","state","anchorBlockId","schemaRegistry","path","findNodePath","doc","parentPath","extractParentPath","siblings","getSiblings","anchorIndex","findSiblingIndex","isAnchorEmpty","isBlockEmpty","resolveCellInsertionContext","cellId","cellPath","cell","getBlock","children","findIndex","c","isBlockNode","id","findTableCellAncestor","blockId","block","type","node","resolveAnchorBlockId","selection","isNodeSelection","nodeId","isGapCursor","anchor","insertBlockAfterAnchor","builder","ctx","insertIndex","insertNode","removeNode","insertOffset","side","cloneBlockWithNewIds","newId","map","child","generateBlockId","createBlockNode","attrs","findBlockRecursive","found","sanitizeAttrs","incoming","specAttrs","result","hasKeys","key","Object","keys","spec","raw","default","getNodeSpec","isVoid","getBlockText","validateRichBlockData","segments","sanitized","segment","kind","getInlineNodeSpec","inlineType","push","sanitizeRichSegments","createBlockFromRichData","blockData","text","length","seg","createInlineNode","marks","m","createTextNode","createChildrenFromSegments","createChildrenFromRichBlock","nodeType"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{r as e}from"./ColorGrid-CpkbKfXg.mjs";import{a as o,g as t,r}from"./AttributedMarkCommands-BB7lzFct.mjs";import{m as a}from"./TypeBrands-Bp_Z_o5Y.mjs";import{i as n}from"./ColorValidation-DCSKq9B2.mjs";function s(e,o){return t(e,o,e=>e.attrs.color??null)}function l(e,o){return null!==s(e,o)}function i(e,t,r,s){if(!n(s))return!1;const l={type:a(r),attrs:{color:s}},i=o(t,l);return!!i&&(e.dispatch(i),!0)}function c(e,o,t){const n=r(o,a(t));return!!n&&(e.dispatch(n),!0)}function m(o,t,r){o.classList.add("notectl-color-picker");const a=s(t.getState(),r.markType),n=r.columns||10,l=t.getContainer(),c=document.createElement("button");c.type="button",c.className="notectl-color-picker__default",c.textContent=r.resetLabel,c.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),t.executeCommand(r.resetCommand),r.onClose({restoreFocusTo:l})}),c.addEventListener("keydown",e=>{"Escape"===e.key&&(e.preventDefault(),r.onClose())}),o.appendChild(c),e(o,{colors:r.colors,columns:n,ariaLabel:`${r.ariaLabelPrefix} color picker`,ariaLabelPrefix:r.ariaLabelPrefix,activeColor:a,onSelect:e=>{i(t,t.getState(),r.markType,e),r.onClose({restoreFocusTo:l})},onClose:r.onClose})}export{i as a,m as b,s as g,l as i,c as r};
2
- //# sourceMappingURL=ColorPickerPopup-DRzFvt7o.mjs.map
1
+ import{r as e}from"./ColorGrid-CpkbKfXg.mjs";import{a as o,g as t,r}from"./AttributedMarkCommands-BY1BSYWM.mjs";import{m as a}from"./TypeBrands-Bp_Z_o5Y.mjs";import{i as n}from"./ColorValidation-DCSKq9B2.mjs";function s(e,o){return t(e,o,e=>e.attrs.color??null)}function l(e,o){return null!==s(e,o)}function i(e,t,r,s){if(!n(s))return!1;const l={type:a(r),attrs:{color:s}},i=o(t,l);return!!i&&(e.dispatch(i),!0)}function c(e,o,t){const n=r(o,a(t));return!!n&&(e.dispatch(n),!0)}function m(o,t,r){o.classList.add("notectl-color-picker");const a=s(t.getState(),r.markType),n=r.columns||10,l=t.getContainer(),c=document.createElement("button");c.type="button",c.className="notectl-color-picker__default",c.textContent=r.resetLabel,c.addEventListener("mousedown",e=>{e.preventDefault(),e.stopPropagation(),t.executeCommand(r.resetCommand),r.onClose({restoreFocusTo:l})}),c.addEventListener("keydown",e=>{"Escape"===e.key&&(e.preventDefault(),r.onClose())}),o.appendChild(c),e(o,{colors:r.colors,columns:n,ariaLabel:`${r.ariaLabelPrefix} color picker`,ariaLabelPrefix:r.ariaLabelPrefix,activeColor:a,onSelect:e=>{i(t,t.getState(),r.markType,e),r.onClose({restoreFocusTo:l})},onClose:r.onClose})}export{i as a,m as b,s as g,l as i,c as r};
2
+ //# sourceMappingURL=ColorPickerPopup-D6XjShhv.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColorPickerPopup-D6XjShhv.mjs","sources":["../../src/plugins/shared/ColorMarkOperations.ts","../../src/plugins/shared/ColorPickerPopup.ts"],"sourcesContent":["/**\n * Shared color mark operations for color-based mark plugins.\n * All functions are parameterized by mark type name so they work\n * identically for TextColor, Highlight, or any future color mark.\n *\n * Delegates to the generic AttributedMarkCommands helpers for the\n * collapsed-vs-range branching logic.\n */\n\nimport {\n\tapplyAttributedMark,\n\tgetMarkAttrAtSelection,\n\tremoveAttributedMark,\n} from '../../commands/AttributedMarkCommands.js';\nimport type { MarkAttrRegistry } from '../../model/AttrRegistry.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { PluginContext } from '../Plugin.js';\nimport { isValidCSSColor } from './ColorValidation.js';\n\n/** Color mark type names that have `{ color: string }` attrs. */\nexport type ColorMarkType = {\n\t[K in keyof MarkAttrRegistry]: MarkAttrRegistry[K] extends { color: string } ? K : never;\n}[keyof MarkAttrRegistry];\n\n/**\n * Returns the active color value for the given mark type at the current\n * selection, or `null` if the mark is not present.\n */\nexport function getActiveColor(state: EditorState, markTypeName: ColorMarkType): string | null {\n\treturn getMarkAttrAtSelection(state, markTypeName, (m) => m.attrs.color ?? null);\n}\n\n/** Returns `true` when the given color mark is active at the current selection. */\nexport function isColorMarkActive(state: EditorState, markTypeName: ColorMarkType): boolean {\n\treturn getActiveColor(state, markTypeName) !== null;\n}\n\n/**\n * Applies the given color to the selection. For collapsed selections,\n * sets stored marks. For range selections, removes then re-adds the mark.\n */\nexport function applyColorMark(\n\tcontext: PluginContext,\n\tstate: EditorState,\n\tmarkTypeName: ColorMarkType,\n\tcolor: string,\n): boolean {\n\tif (!isValidCSSColor(color)) return false;\n\n\tconst mark = { type: markType(markTypeName), attrs: { color } };\n\tconst tr = applyAttributedMark(state, mark);\n\tif (!tr) return false;\n\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/**\n * Removes the given color mark from the selection.\n * Returns `false` when the mark was not present.\n */\nexport function removeColorMark(\n\tcontext: PluginContext,\n\tstate: EditorState,\n\tmarkTypeName: ColorMarkType,\n): boolean {\n\tconst tr = removeAttributedMark(state, markType(markTypeName));\n\tif (!tr) return false;\n\n\tcontext.dispatch(tr);\n\treturn true;\n}\n","/**\n * Shared color picker popup rendering with WAI-ARIA grid keyboard navigation.\n * Used by TextColorPlugin and HighlightPlugin.\n * Delegates grid rendering to the shared ColorGrid module.\n */\n\nimport type { PluginContext } from '../Plugin.js';\nimport { renderColorGrid } from './ColorGrid.js';\nimport type { ColorMarkType } from './ColorMarkOperations.js';\nimport { applyColorMark, getActiveColor } from './ColorMarkOperations.js';\nimport type { PopupCloseOptions } from './PopupManager.js';\n\n/** Configuration for `renderColorPickerPopup`. */\nexport interface ColorPickerConfig {\n\treadonly markType: ColorMarkType;\n\treadonly colors: readonly string[];\n\treadonly columns: number;\n\treadonly resetLabel: string;\n\treadonly resetCommand: string;\n\treadonly ariaLabelPrefix: string;\n\treadonly onClose: (options?: PopupCloseOptions) => void;\n}\n\nconst COLUMNS = 10;\n\n/**\n * Renders an accessible color picker popup into `container`.\n *\n * Features:\n * - WAI-ARIA `role=\"grid\"` with row/gridcell structure\n * - Arrow key navigation (wraps around, clamps on partial last row)\n * - Enter/Space selects color and closes popup\n * - Escape closes popup\n * - Roving tabindex on swatches\n */\nexport function renderColorPickerPopup(\n\tcontainer: HTMLElement,\n\tcontext: PluginContext,\n\tconfig: ColorPickerConfig,\n): void {\n\tcontainer.classList.add('notectl-color-picker');\n\n\tconst state = context.getState();\n\tconst activeColor: string | null = getActiveColor(state, config.markType);\n\tconst columns: number = config.columns || COLUMNS;\n\tconst contentElement: HTMLElement = context.getContainer();\n\n\t// --- Reset button ---\n\tconst resetBtn: HTMLButtonElement = document.createElement('button');\n\tresetBtn.type = 'button';\n\tresetBtn.className = 'notectl-color-picker__default';\n\tresetBtn.textContent = config.resetLabel;\n\tresetBtn.addEventListener('mousedown', (e: MouseEvent) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tcontext.executeCommand(config.resetCommand);\n\t\tconfig.onClose({ restoreFocusTo: contentElement });\n\t});\n\tresetBtn.addEventListener('keydown', (e: KeyboardEvent) => {\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\tconfig.onClose();\n\t\t}\n\t});\n\tcontainer.appendChild(resetBtn);\n\n\t// --- Color grid (delegated to shared ColorGrid) ---\n\trenderColorGrid(container, {\n\t\tcolors: config.colors,\n\t\tcolumns,\n\t\tariaLabel: `${config.ariaLabelPrefix} color picker`,\n\t\tariaLabelPrefix: config.ariaLabelPrefix,\n\t\tactiveColor,\n\t\tonSelect: (color: string) => {\n\t\t\tapplyColorMark(context, context.getState(), config.markType, color);\n\t\t\tconfig.onClose({ restoreFocusTo: contentElement });\n\t\t},\n\t\tonClose: config.onClose,\n\t});\n}\n"],"names":["getActiveColor","state","markTypeName","getMarkAttrAtSelection","m","attrs","color","isColorMarkActive","applyColorMark","context","isValidCSSColor","mark","type","markType","tr","applyAttributedMark","dispatch","removeColorMark","removeAttributedMark","renderColorPickerPopup","container","config","classList","add","activeColor","getState","columns","contentElement","getContainer","resetBtn","document","createElement","className","textContent","resetLabel","addEventListener","e","preventDefault","stopPropagation","executeCommand","resetCommand","onClose","restoreFocusTo","key","appendChild","renderColorGrid","colors","ariaLabel","ariaLabelPrefix","onSelect"],"mappings":"iNA6BO,SAASA,EAAeC,EAAoBC,GAClD,OAAOC,EAAuBF,EAAOC,EAAeE,GAAMA,EAAEC,MAAMC,OAAS,KAC5E,CAGO,SAASC,EAAkBN,EAAoBC,GACrD,OAA+C,OAAxCF,EAAeC,EAAOC,EAC9B,CAMO,SAASM,EACfC,EACAR,EACAC,EACAI,GAEA,IAAKI,EAAgBJ,GAAQ,OAAO,EAEpC,MAAMK,EAAO,CAAEC,KAAMC,EAASX,GAAeG,MAAO,CAAEC,UAChDQ,EAAKC,EAAoBd,EAAOU,GACtC,QAAKG,IAELL,EAAQO,SAASF,IACV,EACR,CAMO,SAASG,EACfR,EACAR,EACAC,GAEA,MAAMY,EAAKI,EAAqBjB,EAAOY,EAASX,IAChD,QAAKY,IAELL,EAAQO,SAASF,IACV,EACR,CCrCO,SAASK,EACfC,EACAX,EACAY,GAEAD,EAAUE,UAAUC,IAAI,wBAExB,MACMC,EAA6BxB,EADrBS,EAAQgB,WACmCJ,EAAOR,UAC1Da,EAAkBL,EAAOK,SArBhB,GAsBTC,EAA8BlB,EAAQmB,eAGtCC,EAA8BC,SAASC,cAAc,UAC3DF,EAASjB,KAAO,SAChBiB,EAASG,UAAY,gCACrBH,EAASI,YAAcZ,EAAOa,WAC9BL,EAASM,iBAAiB,YAAcC,IACvCA,EAAEC,iBACFD,EAAEE,kBACF7B,EAAQ8B,eAAelB,EAAOmB,cAC9BnB,EAAOoB,QAAQ,CAAEC,eAAgBf,MAElCE,EAASM,iBAAiB,UAAYC,IACvB,WAAVA,EAAEO,MACLP,EAAEC,iBACFhB,EAAOoB,aAGTrB,EAAUwB,YAAYf,GAGtBgB,EAAgBzB,EAAW,CAC1B0B,OAAQzB,EAAOyB,OACfpB,UACAqB,UAAW,GAAG1B,EAAO2B,+BACrBA,gBAAiB3B,EAAO2B,gBACxBxB,cACAyB,SAAW3C,IACVE,EAAeC,EAASA,EAAQgB,WAAYJ,EAAOR,SAAUP,GAC7De,EAAOoB,QAAQ,CAAEC,eAAgBf,KAElCc,QAASpB,EAAOoB,SAElB"}
@@ -0,0 +1,2 @@
1
+ import{n,c as r,e as t,f as o,p as e}from"./Document-3pNX7ear.mjs";import{b as s,c as i,i as c,s as f}from"./Selection-DhbizDM4.mjs";import{n as a}from"./TypeBrands-Bp_Z_o5Y.mjs";import{b as u}from"./NavigationQueries-11qe4j9x.mjs";function l(n,r){if(0===r.length)return n.doc.children;const t=n.getBlock(r[r.length-1]);return t?t.children:[]}function d(n){return r(a("paragraph"),[t("")],n)}function m(n,r){if(c(n))return{blockId:n.anchor.blockId,offset:n.anchor.offset};const t=f(n,r);return{blockId:t.from.blockId,offset:t.from.offset}}function h(n){return n&&n.length>1?n.slice(0,-1):[]}function g(r,t){return r.findIndex(r=>n(r)&&r.id===t)}function p(r){if(e(r))return r.id;for(const t of r.children)if(n(t))return p(t);return r.id}function b(r){if(e(r))return r.id;for(let t=r.children.length-1;t>=0;t--){const o=r.children[t];if(o&&n(o))return b(o)}return r.id}function k(n,r,t){const e=n.getBlock(r);if(!e)return null;if(u(n,r)){const t=n.getNodePath(r);return t?s(r,t):null}const c="start"===t?p(e):b(e),f=n.getBlock(c);if(!f)return null;const a="start"===t?0:o(f);return i(c,a)}export{k as a,p as b,d as c,b as d,h as e,g as f,l as g,m as r};
2
+ //# sourceMappingURL=CommandHelpers-M6mPS6Ww.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandHelpers-M6mPS6Ww.mjs","sources":["../../src/commands/CommandHelpers.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, Document } from '../model/Document.js';\nimport {\n\tcreateBlockNode,\n\tcreateTextNode,\n\tgetBlockLength,\n\tisBlockNode,\n\tisLeafBlock,\n} from '../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tisCollapsed,\n\tselectionRange,\n} from '../model/Selection.js';\nimport type { EditorSelection, 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';\nimport { isVoidBlock } from '../state/NavigationQueries.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/** Extracts the parent path from a full node path (all elements except the last). */\nexport function extractParentPath(path: readonly string[] | undefined): BlockId[] {\n\treturn path && path.length > 1 ? (path.slice(0, -1) as BlockId[]) : [];\n}\n\n/** Finds the index of a block by ID within a sibling list. */\nexport function findSiblingIndex(siblings: readonly ChildNode[], targetId: BlockId): number {\n\treturn siblings.findIndex((c) => isBlockNode(c) && c.id === targetId);\n}\n\n/** Finds the first leaf block ID in a subtree. */\nexport function findFirstLeafBlockId(node: BlockNode): BlockId {\n\tif (isLeafBlock(node)) return node.id;\n\n\tfor (const child of node.children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\treturn findFirstLeafBlockId(child);\n\t}\n\n\treturn node.id;\n}\n\n/** Finds the last leaf block ID in a subtree. */\nexport function findLastLeafBlockId(node: BlockNode): BlockId {\n\tif (isLeafBlock(node)) return node.id;\n\n\tfor (let i = node.children.length - 1; i >= 0; i--) {\n\t\tconst child = node.children[i];\n\t\tif (child && isBlockNode(child)) {\n\t\t\treturn findLastLeafBlockId(child);\n\t\t}\n\t}\n\n\treturn node.id;\n}\n\n/**\n * Resolves a valid editor selection at the start or end of a block subtree.\n * Void blocks become NodeSelections; text-capable blocks resolve to leaf cursors.\n */\nexport function createSelectionForBlockBoundary(\n\tstate: EditorState,\n\tblockId: BlockId,\n\tboundary: 'start' | 'end',\n): EditorSelection | null {\n\tconst block = state.getBlock(blockId);\n\tif (!block) return null;\n\n\tif (isVoidBlock(state, blockId)) {\n\t\tconst path = state.getNodePath(blockId);\n\t\treturn path ? createNodeSelection(blockId, path) : null;\n\t}\n\n\tconst leafId: BlockId =\n\t\tboundary === 'start' ? findFirstLeafBlockId(block) : findLastLeafBlockId(block);\n\tconst leaf = state.getBlock(leafId);\n\tif (!leaf) return null;\n\n\tconst offset = boundary === 'start' ? 0 : getBlockLength(leaf);\n\treturn createCollapsedSelection(leafId, offset);\n}\n\n/** Returns the root-level block IDs in document order. */\nexport function getRootBlockIds(doc: Document): readonly BlockId[] {\n\treturn doc.children.map((child) => child.id);\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","extractParentPath","path","slice","findSiblingIndex","siblings","targetId","findIndex","c","isBlockNode","findFirstLeafBlockId","node","isLeafBlock","child","findLastLeafBlockId","i","createSelectionForBlockBoundary","boundary","block","isVoidBlock","getNodePath","createNodeSelection","leafId","leaf","getBlockLength","createCollapsedSelection"],"mappings":"wOAmCO,SAASA,EACfC,EACAC,GAEA,GAA0B,IAAtBA,EAAWC,OAAc,OAAOF,EAAMG,IAAIC,SAC9C,MAAMC,EAAgCL,EAAMM,SAC3CL,EAAWA,EAAWC,OAAS,IAEhC,OAAOG,EAASA,EAAOD,SAAW,EACnC,CAGO,SAASG,EAAqBC,GACpC,OAAOC,EAAgBC,EAAS,aAAc,CAACC,EAAe,KAAMH,EACrE,CAQO,SAASI,EAAmBC,EAAgBC,GAClD,GAAIC,EAAYF,GACf,MAAO,CAAEG,QAASH,EAAII,OAAOD,QAASE,OAAQL,EAAII,OAAOC,QAE1D,MAAMC,EAAQC,EAAeP,EAAKC,GAClC,MAAO,CAAEE,QAASG,EAAME,KAAKL,QAASE,OAAQC,EAAME,KAAKH,OAC1D,CAGO,SAASI,EAAkBC,GACjC,OAAOA,GAAQA,EAAKrB,OAAS,EAAKqB,EAAKC,MAAM,GAAG,GAAoB,EACrE,CAGO,SAASC,EAAiBC,EAAgCC,GAChE,OAAOD,EAASE,UAAWC,GAAMC,EAAYD,IAAMA,EAAErB,KAAOmB,EAC7D,CAGO,SAASI,EAAqBC,GACpC,GAAIC,EAAYD,GAAO,OAAOA,EAAKxB,GAEnC,IAAA,MAAW0B,KAASF,EAAK5B,SACxB,GAAK0B,EAAYI,GACjB,OAAOH,EAAqBG,GAG7B,OAAOF,EAAKxB,EACb,CAGO,SAAS2B,EAAoBH,GACnC,GAAIC,EAAYD,GAAO,OAAOA,EAAKxB,GAEnC,IAAA,IAAS4B,EAAIJ,EAAK5B,SAASF,OAAS,EAAGkC,GAAK,EAAGA,IAAK,CACnD,MAAMF,EAAQF,EAAK5B,SAASgC,GAC5B,GAAIF,GAASJ,EAAYI,GACxB,OAAOC,EAAoBD,EAE7B,CAEA,OAAOF,EAAKxB,EACb,CAMO,SAAS6B,EACfrC,EACAgB,EACAsB,GAEA,MAAMC,EAAQvC,EAAMM,SAASU,GAC7B,IAAKuB,EAAO,OAAO,KAEnB,GAAIC,EAAYxC,EAAOgB,GAAU,CAChC,MAAMO,EAAOvB,EAAMyC,YAAYzB,GAC/B,OAAOO,EAAOmB,EAAoB1B,EAASO,GAAQ,IACpD,CAEA,MAAMoB,EACQ,UAAbL,EAAuBP,EAAqBQ,GAASJ,EAAoBI,GACpEK,EAAO5C,EAAMM,SAASqC,GAC5B,IAAKC,EAAM,OAAO,KAElB,MAAM1B,EAAsB,UAAboB,EAAuB,EAAIO,EAAeD,GACzD,OAAOE,EAAyBH,EAAQzB,EACzC"}
@@ -0,0 +1,2 @@
1
+ import{f as t,s as e,d as o,h as n,p as r}from"./Document-3pNX7ear.mjs";import{a as c}from"./NodeResolver-z0ReCR34.mjs";import{b as s,c as i,h as l,g as f,i as d,s as u,j as a,e as k}from"./Selection-DhbizDM4.mjs";import{i as b}from"./TypeBrands-Bp_Z_o5Y.mjs";import{b as m,a as I,s as g,i as h}from"./NavigationQueries-11qe4j9x.mjs";import{e as p,g as B,f as S,c as x,r as O,b as A,d as j}from"./CommandHelpers-M6mPS6Ww.mjs";import{d as N,i as T,a as v}from"./NodeSelectionCommands-CXrOcPtG.mjs";function w(e,o){if("after"===o.side)return C(e,o);const n=e.getBlockOrder(),r=n.indexOf(o.blockId);if(r<=0)return null;const l=n[r-1];if(!l)return null;if(m(e,l)){const t=c(e.doc,l)??[];return e.transaction("input").setSelection(s(l,t)).build()}const f=e.getBlock(l);if(!f)return null;const d=t(f);return e.transaction("input").setSelection(i(l,d)).build()}function M(t,e){if("before"===e.side)return C(t,e);const o=t.getBlockOrder(),n=o.indexOf(e.blockId);if(n>=o.length-1)return null;const r=o[n+1];if(!r)return null;if(m(t,r)){const e=c(t.doc,r)??[];return t.transaction("input").setSelection(s(r,e)).build()}return t.transaction("input").setSelection(i(r,0)).build()}function C(t,e){const o=c(t.doc,e.blockId)??[],n=s(e.blockId,o);return N(t,n)}function _(t,o,r="input"){const s=t.selection;if(l(s))return T(t,s,o,r);if(f(s))return function(t,o,n,r){const s=c(t.doc,o.blockId),l=p(s),f=B(t,l),d=S(f,o.blockId),u="before"===o.side?Math.max(d,0):d>=0?d+1:f.length,a=e(),k=t.transaction(r);return k.insertNode(l,u,x(a)),k.insertText(a,0,n,[]),k.setSelection(i(a,n.length)),k.build()}(t,s,o,r);const u=t.transaction(r),k=function(t){if(t.storedMarks)return t.storedMarks;if(!a(t.selection))return[];const e=t.getBlock(t.selection.anchor.blockId);return e?n(e,t.selection.anchor.offset):[]}(t);let b;d(s)||(b=E(t,u));const m=O(s,t.getBlockOrder()),I=b??m.blockId,g=b?0:m.offset;return u.insertText(I,g,o,k),u.setSelection(i(I,g+o.length)),u.build()}function y(t){if(l(t.selection))return N(t,t.selection);if(f(t.selection))return null;if(d(t.selection))return null;const e=t.transaction("input"),o=E(t,e),n=u(t.selection,t.getBlockOrder()),r=o??n.from.blockId,c=o?0:n.from.offset;return e.setSelection(i(r,c)),e.build()}function D(t){const o=t.selection;if(l(o))return v(t,o);if(f(o))return function(t,o){const n=c(t.doc,o.blockId);if(!n)return null;const r=p(n),s=B(t,r),l=S(s,o.blockId);if(l<0)return null;const f="before"===o.side?l:l+1,d=e(),u=t.transaction("input");return u.insertNode(r,f,x(d)),u.setSelection(i(d,0)),u.build()}(t,o);const n=t.transaction("input");let r;d(o)||(r=E(t,n));const s=O(o,t.getBlockOrder()),u=r??s.blockId,a=r?0:s.offset,k=e();return n.splitBlock(u,a,k),n.setSelection(i(k,0)),n.build()}function H(t){const e=t.selection;if(!a(e))return null;const n=t.transaction("input");let r;if(d(e)||(r=E(t,n)),r)n.insertInlineNode(r,0,o(b("hard_break"))),n.setSelection(i(r,1));else{const{blockId:r,offset:c}=O(e,t.getBlockOrder());n.insertInlineNode(r,c,o(b("hard_break"))),n.setSelection(i(r,c+1))}return n.build()}function Q(t){return q(t,"backward")}function R(t){return q(t,"forward")}function q(e,o){const n=e.selection;if(!a(n))return null;const r=e.getBlockOrder(),l=r.indexOf(n.anchor.blockId),f="backward"===o?l-1:l+1;if(f<0||f>=r.length)return null;const d=r[f];if(!d)return null;if(I(e,n.anchor.blockId)||I(e,d))return null;if(!g(e,n.anchor.blockId,d)&&h(e,n.anchor.blockId))return null;if(m(e,d)){const t=c(e.doc,d)??[];return e.transaction("input").setSelection(s(d,t)).build()}if("backward"===o){const o=e.getBlock(d);if(!o)return null;const r=t(o);return e.transaction("input").mergeBlocksAt(d,n.anchor.blockId).setSelection(i(d,r)).build()}return e.transaction("input").mergeBlocksAt(n.anchor.blockId,d).setSelection(i(n.anchor.blockId,n.anchor.offset)).build()}function z(e){const o=e.doc.children,n=o[0],r=o[o.length-1];if(!n||!r)return e.transaction("command").setSelection(e.selection).build();const c=A(n),s=j(r),i=e.getBlock(s),l=i?t(i):0;return e.transaction("command").setSelection(k({blockId:c,offset:0},{blockId:s,offset:l})).build()}function E(o,n){if(!a(o.selection))return;const c=o.getBlockOrder(),s=u(o.selection,c),i=c.indexOf(s.from.blockId),l=c.indexOf(s.to.blockId);if(i===l)return void n.deleteTextAt(s.from.blockId,s.from.offset,s.to.offset);const f=F(o,s.from.blockId),d=F(o,s.to.blockId);if(!(f===d||f<0||d<0))return function(o,n,c,s,i){const l=o.doc.children[s],f=o.doc.children[i];if(!l||!f)return;const d=r(l),u=r(f);let a,k=0;if(d||(a=e(),n.insertNode([],s,x(a)),k=1),d){const e=o.getBlock(c.from.blockId);if(e){const o=t(e);c.from.offset<o&&n.deleteTextAt(c.from.blockId,c.from.offset,o)}}u&&c.to.offset>0&&n.deleteTextAt(c.to.blockId,0,c.to.offset);const b=d?s+1:s+k;for(let t=u?i-1+k:i+k;t>=b;t--)n.removeNode([],t);return d&&u&&n.mergeBlocksAt(c.from.blockId,c.to.blockId),a}(o,n,s,f,d);!function(e,o,n,r,c,s){const i=e.getBlock(r.from.blockId);if(!i)return;const l=t(i);r.from.offset<l&&o.deleteTextAt(r.from.blockId,r.from.offset,l),r.to.offset>0&&o.deleteTextAt(r.to.blockId,0,r.to.offset);for(let f=c+1;f<s;f++){const c=n[f];if(!c)continue;const s=e.getBlock(c);if(!s)continue;const i=t(s);i>0&&o.deleteTextAt(c,0,i),o.mergeBlocksAt(r.from.blockId,c)}o.mergeBlocksAt(r.from.blockId,r.to.blockId)}(o,n,c,s,i,l)}function F(t,e){const o=c(t.doc,e);if(!o||0===o.length)return-1;const n=o[0];return t.doc.children.findIndex(t=>t.id===n)}export{M as a,y as b,_ as c,w as d,D as e,R as f,E as g,H as i,Q as m,z as s};
2
+ //# sourceMappingURL=Commands-D_gMCnVa.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Commands-D_gMCnVa.mjs","sources":["../../src/commands/GapCursorCommands.ts","../../src/commands/Commands.ts"],"sourcesContent":["/**\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 { 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 { isVoidBlock } from '../state/NavigationQueries.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport {\n\tcreateEmptyParagraph,\n\textractParentPath,\n\tfindSiblingIndex,\n\tgetSiblings,\n} 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[] = extractParentPath(path);\n\tconst siblings = getSiblings(state, parentPath);\n\n\tconst index: number = findSiblingIndex(siblings, 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[] = extractParentPath(path);\n\tconst siblings = getSiblings(state, parentPath);\n\n\tconst index: number = findSiblingIndex(siblings, 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\tisLeafBlock,\n} from '../model/Document.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateNodeSelection,\n\tcreateSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n\tisTextSelection,\n\tselectionRange,\n} from '../model/Selection.js';\nimport { type BlockId, inlineType } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport {\n\tisInsideIsolating,\n\tisIsolatingBlock,\n\tisVoidBlock,\n\tsharesParent,\n} from '../state/NavigationQueries.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport type { TransactionBuilder } from '../state/Transaction.js';\nimport { createEmptyParagraph, resolveInsertPoint } from './CommandHelpers.js';\nimport { insertParagraphAtGap, insertTextAtGap } from './GapCursorCommands.js';\nimport {\n\tdeleteNodeSelection,\n\tfindFirstLeafBlockId,\n\tfindLastLeafBlockId,\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 '../state/NavigationQueries.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\tlet landingId: BlockId | undefined;\n\tif (!isCollapsed(sel)) {\n\t\tlandingId = addDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst resolved = resolveInsertPoint(sel, state.getBlockOrder());\n\tconst insertBlockId: BlockId = landingId ?? resolved.blockId;\n\tconst insertOffset: number = landingId ? 0 : resolved.offset;\n\n\tbuilder.insertText(insertBlockId, insertOffset, text, marks);\n\tbuilder.setSelection(createCollapsedSelection(insertBlockId, insertOffset + text.length));\n\n\treturn builder.build();\n}\n\n/** Deletes the current selection. */\nexport function deleteSelectionCommand(state: EditorState): Transaction | null {\n\tif (isNodeSelection(state.selection)) {\n\t\treturn deleteNodeSelection(state, state.selection);\n\t}\n\tif (isGapCursor(state.selection)) return null;\n\tif (isCollapsed(state.selection)) return null;\n\n\tconst builder = state.transaction('input');\n\tconst landingId: BlockId | undefined = addDeleteSelectionSteps(state, builder);\n\n\tconst range = selectionRange(state.selection, state.getBlockOrder());\n\tconst cursorBlockId: BlockId = landingId ?? range.from.blockId;\n\tconst cursorOffset: number = landingId ? 0 : range.from.offset;\n\tbuilder.setSelection(createCollapsedSelection(cursorBlockId, cursorOffset));\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\tlet landingId: BlockId | undefined;\n\tif (!isCollapsed(sel)) {\n\t\tlandingId = addDeleteSelectionSteps(state, builder);\n\t}\n\n\tconst resolved = resolveInsertPoint(sel, state.getBlockOrder());\n\tconst blockId: BlockId = landingId ?? resolved.blockId;\n\tconst offset: number = landingId ? 0 : resolved.offset;\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 (!isTextSelection(sel)) return null;\n\n\tconst builder = state.transaction('input');\n\n\tlet cursorBlockId: BlockId | undefined;\n\tif (!isCollapsed(sel)) {\n\t\tconst landingId: BlockId | undefined = addDeleteSelectionSteps(state, builder);\n\t\tcursorBlockId = landingId;\n\t}\n\n\tif (cursorBlockId) {\n\t\t// Cross-root deletion replaced from-block; insert hard break in landing block\n\t\tbuilder.insertInlineNode(cursorBlockId, 0, createInlineNode(inlineType('hard_break')));\n\t\tbuilder.setSelection(createCollapsedSelection(cursorBlockId, 1));\n\t} else {\n\t\tconst { blockId: insertBlockId, offset: insertOffset } = resolveInsertPoint(\n\t\t\tsel,\n\t\t\tstate.getBlockOrder(),\n\t\t);\n\t\tbuilder.insertInlineNode(\n\t\t\tinsertBlockId,\n\t\t\tinsertOffset,\n\t\t\tcreateInlineNode(inlineType('hard_break')),\n\t\t);\n\t\tbuilder.setSelection(createCollapsedSelection(insertBlockId, insertOffset + 1));\n\t}\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\treturn mergeAdjacentBlock(state, 'backward');\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\treturn mergeAdjacentBlock(state, 'forward');\n}\n\n/**\n * Shared implementation for merging adjacent blocks in either direction.\n * Validates selection, isolating boundaries, and void blocks before merging.\n */\nfunction mergeAdjacentBlock(\n\tstate: EditorState,\n\tdirection: 'backward' | 'forward',\n): Transaction | null {\n\tconst sel = state.selection;\n\tif (!isTextSelection(sel)) return null;\n\n\tconst blockOrder = state.getBlockOrder();\n\tconst blockIdx: number = blockOrder.indexOf(sel.anchor.blockId);\n\n\tconst adjacentIdx: number = direction === 'backward' ? blockIdx - 1 : blockIdx + 1;\n\tif (adjacentIdx < 0 || adjacentIdx >= blockOrder.length) return null;\n\n\tconst adjacentId: BlockId | undefined = blockOrder[adjacentIdx];\n\tif (!adjacentId) return null;\n\n\tif (isIsolatingBlock(state, sel.anchor.blockId) || isIsolatingBlock(state, adjacentId)) {\n\t\treturn null;\n\t}\n\tif (!sharesParent(state, sel.anchor.blockId, adjacentId)) {\n\t\tif (isInsideIsolating(state, sel.anchor.blockId)) return null;\n\t}\n\n\tif (isVoidBlock(state, adjacentId)) {\n\t\tconst path = findNodePath(state.doc, adjacentId) ?? [];\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createNodeSelection(adjacentId, path as BlockId[]))\n\t\t\t.build();\n\t}\n\n\tif (direction === 'backward') {\n\t\tconst prevBlock = state.getBlock(adjacentId);\n\t\tif (!prevBlock) return null;\n\t\tconst prevLen: number = getBlockLength(prevBlock);\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.mergeBlocksAt(adjacentId, sel.anchor.blockId)\n\t\t\t.setSelection(createCollapsedSelection(adjacentId, prevLen))\n\t\t\t.build();\n\t}\n\n\treturn state\n\t\t.transaction('input')\n\t\t.mergeBlocksAt(sel.anchor.blockId, adjacentId)\n\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, sel.anchor.offset))\n\t\t.build();\n}\n\n/** Selects all content in the editor, using leaf block endpoints. */\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\n\tconst firstLeafId: BlockId = findFirstLeafBlockId(firstBlock);\n\tconst lastLeafId: BlockId = findLastLeafBlockId(lastBlock);\n\tconst lastLeaf = state.getBlock(lastLeafId);\n\tconst lastLeafLen: number = lastLeaf ? getBlockLength(lastLeaf) : 0;\n\n\treturn state\n\t\t.transaction('command')\n\t\t.setSelection(\n\t\t\tcreateSelection(\n\t\t\t\t{ blockId: firstLeafId, offset: 0 },\n\t\t\t\t{ blockId: lastLeafId, offset: lastLeafLen },\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 (!isTextSelection(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\n/**\n * Adds steps to delete the current text selection.\n * Returns a replacement cursor block ID when the original from-block\n * was inside a composite root that got removed (undefined otherwise).\n */\nexport function addDeleteSelectionSteps(\n\tstate: EditorState,\n\tbuilder: TransactionBuilder,\n): BlockId | undefined {\n\tif (!isTextSelection(state.selection)) return undefined;\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\treturn undefined;\n\t}\n\n\tconst fromRootIdx: number = getRootBlockIndex(state, range.from.blockId);\n\tconst toRootIdx: number = getRootBlockIndex(state, range.to.blockId);\n\n\tif (fromRootIdx === toRootIdx || fromRootIdx < 0 || toRootIdx < 0) {\n\t\tdeleteLeafRange(state, builder, blockOrder, range, fromIdx, toIdx);\n\t\treturn undefined;\n\t}\n\n\treturn deleteCrossRootRange(state, builder, range, fromRootIdx, toRootIdx);\n}\n\n/** Returns the root-level ancestor index in doc.children for a given block. */\nfunction getRootBlockIndex(state: EditorState, blockId: BlockId): number {\n\tconst path = findNodePath(state.doc, blockId);\n\tif (!path || path.length === 0) return -1;\n\tconst rootId: string = path[0] as string;\n\treturn state.doc.children.findIndex((c) => c.id === rootId);\n}\n\n/** Deletes a multi-block selection where all blocks share the same root ancestor. */\nfunction deleteLeafRange(\n\tstate: EditorState,\n\tbuilder: TransactionBuilder,\n\tblockOrder: readonly BlockId[],\n\trange: {\n\t\treadonly from: { readonly blockId: BlockId; readonly offset: number };\n\t\treadonly to: { readonly blockId: BlockId; readonly offset: number };\n\t},\n\tfromIdx: number,\n\ttoIdx: number,\n): void {\n\tconst firstBlock = state.getBlock(range.from.blockId);\n\tif (!firstBlock) return;\n\tconst firstLen = getBlockLength(firstBlock);\n\n\tif (range.from.offset < firstLen) {\n\t\tbuilder.deleteTextAt(range.from.blockId, range.from.offset, firstLen);\n\t}\n\n\tif (range.to.offset > 0) {\n\t\tbuilder.deleteTextAt(range.to.blockId, 0, range.to.offset);\n\t}\n\n\tfor (let i = fromIdx + 1; i < toIdx; i++) {\n\t\tconst midBlockId = blockOrder[i];\n\t\tif (!midBlockId) continue;\n\t\tconst midBlock = state.getBlock(midBlockId);\n\t\tif (!midBlock) continue;\n\t\tconst midLen = getBlockLength(midBlock);\n\t\tif (midLen > 0) {\n\t\t\tbuilder.deleteTextAt(midBlockId, 0, midLen);\n\t\t}\n\t\tbuilder.mergeBlocksAt(range.from.blockId, midBlockId);\n\t}\n\n\tbuilder.mergeBlocksAt(range.from.blockId, range.to.blockId);\n}\n\n/**\n * Deletes a selection spanning different root-level ancestors.\n * Removes intermediate and composite root blocks, merges leaf roots.\n * Returns a replacement cursor block ID if from was inside a removed composite.\n */\nfunction deleteCrossRootRange(\n\tstate: EditorState,\n\tbuilder: TransactionBuilder,\n\trange: {\n\t\treadonly from: { readonly blockId: BlockId; readonly offset: number };\n\t\treadonly to: { readonly blockId: BlockId; readonly offset: number };\n\t},\n\tfromRootIdx: number,\n\ttoRootIdx: number,\n): BlockId | undefined {\n\tconst fromRoot = state.doc.children[fromRootIdx];\n\tconst toRoot = state.doc.children[toRootIdx];\n\tif (!fromRoot || !toRoot) return undefined;\n\n\tconst fromIsLeaf: boolean = isLeafBlock(fromRoot);\n\tconst toIsLeaf: boolean = isLeafBlock(toRoot);\n\n\t// When from is inside a composite root, insert a landing paragraph\n\t// so callers can reference a surviving block for cursor/insert.\n\tlet landingId: BlockId | undefined;\n\tlet indexShift = 0;\n\n\tif (!fromIsLeaf) {\n\t\tlandingId = generateBlockId();\n\t\tbuilder.insertNode([], fromRootIdx, createEmptyParagraph(landingId));\n\t\tindexShift = 1;\n\t}\n\n\t// Delete text in from-leaf (only for leaf roots; composite roots are removed entirely)\n\tif (fromIsLeaf) {\n\t\tconst fromBlock = state.getBlock(range.from.blockId);\n\t\tif (fromBlock) {\n\t\t\tconst fromLen: number = getBlockLength(fromBlock);\n\t\t\tif (range.from.offset < fromLen) {\n\t\t\t\tbuilder.deleteTextAt(range.from.blockId, range.from.offset, fromLen);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Delete text in to-leaf (only for leaf roots)\n\tif (toIsLeaf && range.to.offset > 0) {\n\t\tbuilder.deleteTextAt(range.to.blockId, 0, range.to.offset);\n\t}\n\n\t// Remove root-level blocks in descending index order.\n\t// Keep from-root if it's a leaf; remove if composite (shifted by indexShift).\n\t// Keep to-root if it's a leaf (will merge into from); remove if composite.\n\tconst removeEnd: number = toIsLeaf ? toRootIdx - 1 + indexShift : toRootIdx + indexShift;\n\tconst removeStart: number = fromIsLeaf ? fromRootIdx + 1 : fromRootIdx + indexShift;\n\n\tfor (let i = removeEnd; i >= removeStart; i--) {\n\t\tbuilder.removeNode([], i);\n\t}\n\n\t// Merge to-root into from if both are leaf roots\n\tif (fromIsLeaf && toIsLeaf) {\n\t\tbuilder.mergeBlocksAt(range.from.blockId, range.to.blockId);\n\t}\n\n\treturn landingId;\n}\n"],"names":["deleteBackwardAtGap","state","sel","side","deleteVoidAtGap","blockOrder","getBlockOrder","blockIdx","indexOf","blockId","prevId","isVoidBlock","path","findNodePath","doc","transaction","setSelection","createNodeSelection","build","prevBlock","getBlock","prevLen","getBlockLength","createCollapsedSelection","deleteForwardAtGap","length","nextId","nodeSel","deleteNodeSelection","insertTextCommand","text","origin","selection","isNodeSelection","insertTextAfterNodeSelection","isGapCursor","parentPath","extractParentPath","siblings","getSiblings","index","findSiblingIndex","insertIdx","Math","max","newId","generateBlockId","builder","insertNode","createEmptyParagraph","insertText","insertTextAtGap","marks","storedMarks","isTextSelection","block","anchor","getBlockMarksAtOffset","offset","resolveActiveMarks","landingId","isCollapsed","addDeleteSelectionSteps","resolved","resolveInsertPoint","insertBlockId","insertOffset","deleteSelectionCommand","range","selectionRange","cursorBlockId","from","cursorOffset","splitBlockCommand","insertParagraphAfterNodeSelection","insertParagraphAtGap","newBlockId","splitBlock","insertHardBreakCommand","insertInlineNode","createInlineNode","inlineType","mergeBlockBackward","mergeAdjacentBlock","mergeBlockForward","direction","adjacentIdx","adjacentId","isIsolatingBlock","sharesParent","isInsideIsolating","mergeBlocksAt","selectAll","blocks","children","firstBlock","lastBlock","firstLeafId","findFirstLeafBlockId","lastLeafId","findLastLeafBlockId","lastLeaf","lastLeafLen","createSelection","fromIdx","toIdx","to","deleteTextAt","fromRootIdx","getRootBlockIndex","toRootIdx","fromRoot","toRoot","fromIsLeaf","isLeafBlock","toIsLeaf","indexShift","fromBlock","fromLen","removeStart","i","removeNode","deleteCrossRootRange","firstLen","midBlockId","midBlock","midLen","deleteLeafRange","rootId","findIndex","c","id"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ function t(t,n,r){const o=[];return e(t,n,r,{onText(t,n){o.push({text:t,marks:n})}}),o}function n(t,n,r){const o=[];return e(t,n,r,{onText(t,n){o.push({kind:"text",text:t,marks:n})},onInline(t){o.push({kind:"inline",node:t})}}),o}function e(t,n,e,r){const i=f(t);let s=0;for(const u of i){const t=s+(o(u)?1:u.text.length);if(t<=n||s>=e)s=t;else{if(o(u))r.onInline?.(u);else{const t=Math.max(0,n-s),o=Math.min(u.text.length,e-s),i=u.text.slice(t,o);i.length>0&&r.onText(i,u.marks)}s=t}}}function r(t){return"object"==typeof t&&null!==t&&"text"===t.type&&"string"==typeof t.text}function o(t){return"object"==typeof t&&null!==t&&"inline"===t.type&&"string"==typeof t.inlineType}function i(t){return"object"==typeof t&&null!==t&&"string"==typeof t.id&&"string"==typeof t.type&&"text"!==t.type&&"inline"!==t.type&&Array.isArray(t.children)}function s(t){return t.children.every(t=>r(t)||o(t))}function u(t){return t.children.filter(t=>r(t))}function f(t){return t.children.filter(t=>r(t)||o(t))}function c(t){return t.children.filter(t=>i(t))}function l(){return`block-${crypto.randomUUID()}`}function a(t){return{children:t??[h("paragraph")]}}function h(t,n,e,r){return{id:e??l(),type:t,...r?{attrs:r}:{},children:n??[g("")]}}function g(t,n){return{type:"text",text:t,marks:n??[]}}function x(t,n){return{type:"inline",inlineType:t,attrs:n??{}}}function p(t){const n=f(t);let e="";for(const o of n)r(o)&&(e+=o.text);return e}function y(t){const n=f(t);let e=0;for(const r of n)e+=o(r)?1:r.text.length;return e}function m(t,n){const e=f(t);let i=0;for(const r of e){if(o(r)){if(n===i)return[];i+=1;continue}const t=i+r.text.length;if(n>=i&&n<t)return r.marks;if(n===i&&0===r.text.length)return r.marks;i=t}for(let o=e.length-1;o>=0;o--){const t=e[o];if(t&&r(t))return t.marks}return[]}function k(t,n){return t.length===n.length&&t.every(t=>n.some(n=>function(t,n){if(t.type!==n.type)return!1;const e=t.attrs,r=n.attrs;if(!e&&!r)return!0;if(!e||!r)return!1;const o=Object.keys(e),i=Object.keys(r);return o.length===i.length&&o.every(t=>e[t]===r[t])}(t,n)))}function d(t,n){return t.some(t=>t.type===n)}function b(t,n){return d(t,n.type)?t:[...t,n]}function j(t,n){return t.filter(t=>t.type!==n)}function v(t){if(0===t.length)return[g("")];if(t.every(t=>r(t)))return function(t){if(0===t.length)return[g("")];const n=[];for(const e of t){const t=n[n.length-1];t&&k(t.marks,e.marks)?n[n.length-1]=g(t.text+e.text,t.marks):(e.text.length>0||0===n.length)&&n.push(e)}return 0===n.length?[g("")]:n}(t);const n=[];for(const i of t){if(o(i)){n.push(i);continue}const t=n[n.length-1];t&&r(t)&&k(t.marks,i.marks)?n[n.length-1]=g(t.text+i.text,t.marks):(i.text.length>0||0===n.length)&&n.push(i)}const e=n.filter((t,e)=>{if(o(t))return!0;if(t.text.length>0)return!0;if(1===n.length)return!0;const r=n[e-1],i=n[e+1];return!(r&&o(r)||i&&o(i))});return 0===e.length?[g("")]:e.some(t=>r(t))?e:[g(""),...e]}function T(t,n){const e=f(t);let r=0,i=0;for(const s of e)if(o(s)){if(r>=n)return i;r+=1}else{if(r+s.text.length>=n)return i+(n-r);r+=s.text.length,i+=s.text.length}return i}function I(t,n){const e=f(t);for(const{child:r,from:i}of function*(t){let n=0;for(const e of t){const t=o(e)?1:e.text.length;yield{child:e,from:n,to:n+t},n+=t}}(e)){if(o(r)){if(n===i)return{kind:"inline",node:r};continue}const t=n-i;if(t>=0&&t<r.text.length)return{kind:"text",char:r.text[t]??"",marks:r.marks}}return null}export{a,T as b,h as c,x as d,g as e,y as f,c as g,m as h,p as i,I as j,f as k,u as l,d as m,i as n,o,s as p,r as q,k as r,l as s,b as t,j as u,v,t as w,n as x};
2
+ //# sourceMappingURL=Document-3pNX7ear.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Document-3pNX7ear.mjs","sources":["../../src/model/Document.ts"],"sourcesContent":["/**\n * Core document model types for the Notectl editor.\n * All types are deeply readonly — mutations create new instances.\n */\n\nimport type { BlockId, InlineTypeName, MarkTypeName, NodeTypeName } from './TypeBrands.js';\n\n// --- Mark Types ---\n\nexport interface Mark {\n\treadonly type: MarkTypeName;\n\treadonly attrs?: Readonly<Record<string, string | number | boolean>>;\n}\n\nexport interface BoldMark extends Mark {\n\treadonly type: MarkTypeName & 'bold';\n}\n\nexport interface ItalicMark extends Mark {\n\treadonly type: MarkTypeName & 'italic';\n}\n\nexport interface UnderlineMark extends Mark {\n\treadonly type: MarkTypeName & 'underline';\n}\n\n// --- Node Types ---\n\nexport interface BlockAttrs {\n\treadonly [key: string]: string | number | boolean;\n}\n\nexport interface TextNode {\n\treadonly type: 'text';\n\treadonly text: string;\n\treadonly marks: readonly Mark[];\n}\n\n/** Atomic inline element (width 1 in offset space). */\nexport interface InlineNode {\n\treadonly type: 'inline';\n\treadonly inlineType: InlineTypeName;\n\treadonly attrs: Readonly<Record<string, string | number | boolean>>;\n}\n\n/** A child of a BlockNode: text, inline element, or nested block. */\nexport type ChildNode = TextNode | InlineNode | BlockNode;\n\nexport interface BlockNode {\n\treadonly id: BlockId;\n\treadonly type: NodeTypeName;\n\treadonly attrs?: BlockAttrs;\n\treadonly children: readonly ChildNode[];\n}\n\nexport interface Document {\n\treadonly children: readonly BlockNode[];\n}\n\n// --- Text Segment (for mark-preserving undo) ---\n\nexport interface TextSegment {\n\treadonly text: string;\n\treadonly marks: readonly Mark[];\n}\n\n/** A content segment: either text (with marks) or an inline node. */\nexport type ContentSegment =\n\t| { readonly kind: 'text'; readonly text: string; readonly marks: readonly Mark[] }\n\t| { readonly kind: 'inline'; readonly node: InlineNode };\n\n/** Extracts TextNode segments within a block for the given offset range. */\nexport function getBlockSegmentsInRange(\n\tblock: BlockNode,\n\tfrom: number,\n\tto: number,\n): readonly TextSegment[] {\n\tconst segments: TextSegment[] = [];\n\twalkBlockRange(block, from, to, {\n\t\tonText(text: string, marks: readonly Mark[]): void {\n\t\t\tsegments.push({ text, marks });\n\t\t},\n\t});\n\treturn segments;\n}\n\n/** Returns content segments (text and inline) for a block range. */\nexport function getBlockContentSegmentsInRange(\n\tblock: BlockNode,\n\tfrom: number,\n\tto: number,\n): readonly ContentSegment[] {\n\tconst segments: ContentSegment[] = [];\n\twalkBlockRange(block, from, to, {\n\t\tonText(text: string, marks: readonly Mark[]): void {\n\t\t\tsegments.push({ kind: 'text', text, marks });\n\t\t},\n\t\tonInline(node: InlineNode): void {\n\t\t\tsegments.push({ kind: 'inline', node });\n\t\t},\n\t});\n\treturn segments;\n}\n\ninterface BlockRangeVisitor {\n\treadonly onText: (text: string, marks: readonly Mark[]) => void;\n\treadonly onInline?: (node: InlineNode) => void;\n}\n\n/** Walks inline children within [from, to) and calls visitor callbacks for each relevant child. */\nfunction walkBlockRange(\n\tblock: BlockNode,\n\tfrom: number,\n\tto: number,\n\tvisitor: BlockRangeVisitor,\n): void {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet pos = 0;\n\n\tfor (const child of inlineChildren) {\n\t\tconst childWidth: number = isInlineNode(child) ? 1 : child.text.length;\n\t\tconst childEnd: number = pos + childWidth;\n\n\t\tif (childEnd <= from || pos >= to) {\n\t\t\tpos = childEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (isInlineNode(child)) {\n\t\t\tvisitor.onInline?.(child);\n\t\t} else {\n\t\t\tconst sliceFrom: number = Math.max(0, from - pos);\n\t\t\tconst sliceTo: number = Math.min(child.text.length, to - pos);\n\t\t\tconst text: string = child.text.slice(sliceFrom, sliceTo);\n\t\t\tif (text.length > 0) {\n\t\t\t\tvisitor.onText(text, child.marks);\n\t\t\t}\n\t\t}\n\n\t\tpos = childEnd;\n\t}\n}\n\n// --- Type Guards ---\n\n/** Checks whether a value is a {@link TextNode}. */\nexport function isTextNode(node: unknown): node is TextNode {\n\treturn (\n\t\ttypeof node === 'object' &&\n\t\tnode !== null &&\n\t\t(node as TextNode).type === 'text' &&\n\t\ttypeof (node as TextNode).text === 'string'\n\t);\n}\n\n/** Checks whether a value is an {@link InlineNode}. */\nexport function isInlineNode(node: unknown): node is InlineNode {\n\treturn (\n\t\ttypeof node === 'object' &&\n\t\tnode !== null &&\n\t\t(node as InlineNode).type === 'inline' &&\n\t\ttypeof (node as InlineNode).inlineType === 'string'\n\t);\n}\n\n/** Checks whether a value is a {@link BlockNode}. */\nexport function isBlockNode(node: unknown): node is BlockNode {\n\treturn (\n\t\ttypeof node === 'object' &&\n\t\tnode !== null &&\n\t\ttypeof (node as BlockNode).id === 'string' &&\n\t\ttypeof (node as BlockNode).type === 'string' &&\n\t\t(node as BlockNode).type !== ('text' as string) &&\n\t\t(node as BlockNode).type !== ('inline' as string) &&\n\t\tArray.isArray((node as BlockNode).children)\n\t);\n}\n\n// --- Child Node Helpers ---\n\n/** Returns true if a block has only inline content (TextNodes and InlineNodes). */\nexport function isLeafBlock(node: BlockNode): boolean {\n\treturn node.children.every((c) => isTextNode(c) || isInlineNode(c));\n}\n\n/** Returns only the TextNode children of a block. */\nexport function getTextChildren(node: BlockNode): readonly TextNode[] {\n\treturn node.children.filter((c): c is TextNode => isTextNode(c));\n}\n\n/** Returns the inline content children (TextNode | InlineNode) of a block. */\nexport function getInlineChildren(node: BlockNode): readonly (TextNode | InlineNode)[] {\n\treturn node.children.filter((c): c is TextNode | InlineNode => isTextNode(c) || isInlineNode(c));\n}\n\n/** Returns only the BlockNode children of a block. */\nexport function getBlockChildren(node: BlockNode): readonly BlockNode[] {\n\treturn node.children.filter((c): c is BlockNode => isBlockNode(c));\n}\n\n// --- Factory Functions ---\n\n/** Generates a unique block ID using crypto.randomUUID(). */\nexport function generateBlockId(): BlockId {\n\treturn `block-${crypto.randomUUID()}` as BlockId;\n}\n\n/** Creates a new empty {@link Document} with a single empty paragraph. */\nexport function createDocument(children?: readonly BlockNode[]): Document {\n\treturn {\n\t\tchildren: children ?? [createBlockNode('paragraph' as NodeTypeName)],\n\t};\n}\n\n/** Creates a new {@link BlockNode}. */\nexport function createBlockNode(\n\ttype: NodeTypeName,\n\tchildren?: readonly ChildNode[],\n\tid?: BlockId,\n\tattrs?: BlockAttrs,\n): BlockNode {\n\treturn {\n\t\tid: id ?? generateBlockId(),\n\t\ttype,\n\t\t...(attrs ? { attrs } : {}),\n\t\tchildren: children ?? [createTextNode('')],\n\t};\n}\n\n/** Creates a new {@link TextNode}. */\nexport function createTextNode(text: string, marks?: readonly Mark[]): TextNode {\n\treturn {\n\t\ttype: 'text',\n\t\ttext,\n\t\tmarks: marks ?? [],\n\t};\n}\n\n/** Creates a new {@link InlineNode}. */\nexport function createInlineNode(\n\tinlineType: InlineTypeName,\n\tattrs?: Readonly<Record<string, string | number | boolean>>,\n): InlineNode {\n\treturn {\n\t\ttype: 'inline',\n\t\tinlineType,\n\t\tattrs: attrs ?? {},\n\t};\n}\n\n// --- Utility Functions ---\n\n/** Extracts plain text from a block (InlineNodes are skipped). */\nexport function getBlockText(block: BlockNode): string {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet text = '';\n\tfor (const child of inlineChildren) {\n\t\tif (isTextNode(child)) {\n\t\t\ttext += child.text;\n\t\t}\n\t}\n\treturn text;\n}\n\n/** Returns the length of a block's inline content (InlineNodes count as 1). */\nexport function getBlockLength(block: BlockNode): number {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet len = 0;\n\tfor (const child of inlineChildren) {\n\t\tlen += isInlineNode(child) ? 1 : child.text.length;\n\t}\n\treturn len;\n}\n\n/** Returns the marks active at the given offset (empty for InlineNode offsets). */\nexport function getBlockMarksAtOffset(block: BlockNode, offset: number): readonly Mark[] {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet pos = 0;\n\n\tfor (const child of inlineChildren) {\n\t\tif (isInlineNode(child)) {\n\t\t\tif (offset === pos) return [];\n\t\t\tpos += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst end: number = pos + child.text.length;\n\t\tif (offset >= pos && offset < end) {\n\t\t\treturn child.marks;\n\t\t}\n\t\tif (offset === pos && child.text.length === 0) {\n\t\t\treturn child.marks;\n\t\t}\n\t\tpos = end;\n\t}\n\n\t// Fall back to last text child's marks\n\tfor (let i: number = inlineChildren.length - 1; i >= 0; i--) {\n\t\tconst child: TextNode | InlineNode | undefined = inlineChildren[i];\n\t\tif (child && isTextNode(child)) {\n\t\t\treturn child.marks;\n\t\t}\n\t}\n\treturn [];\n}\n\n/** Checks whether two marks are equal by type and attrs. */\nexport function marksEqual(a: Mark, b: Mark): boolean {\n\tif (a.type !== b.type) return false;\n\tconst aAttrs = a.attrs;\n\tconst bAttrs = b.attrs;\n\tif (!aAttrs && !bAttrs) return true;\n\tif (!aAttrs || !bAttrs) return false;\n\tconst aKeys = Object.keys(aAttrs);\n\tconst bKeys = Object.keys(bAttrs);\n\tif (aKeys.length !== bKeys.length) return false;\n\treturn aKeys.every((key) => aAttrs[key] === bAttrs[key]);\n}\n\n/** Checks whether two mark arrays contain the same marks (order-independent). */\nexport function markSetsEqual(a: readonly Mark[], b: readonly Mark[]): boolean {\n\tif (a.length !== b.length) return false;\n\treturn a.every((markA) => b.some((markB) => marksEqual(markA, markB)));\n}\n\n/** Returns true if the mark set contains a mark of the given type. */\nexport function hasMark(marks: readonly Mark[], markType: MarkTypeName): boolean {\n\treturn marks.some((m) => m.type === markType);\n}\n\n/** Adds a mark to a mark set (no duplicates). */\nexport function addMarkToSet(marks: readonly Mark[], mark: Mark): readonly Mark[] {\n\tif (hasMark(marks, mark.type)) return marks;\n\treturn [...marks, mark];\n}\n\n/** Removes a mark type from a mark set. */\nexport function removeMarkFromSet(marks: readonly Mark[], markType: MarkTypeName): readonly Mark[] {\n\treturn marks.filter((m) => m.type !== markType);\n}\n\n/**\n * Normalizes text nodes within a block: merges adjacent nodes with identical marks,\n * removes empty text nodes (keeping at least one).\n */\nexport function normalizeTextNodes(nodes: readonly TextNode[]): readonly TextNode[] {\n\tif (nodes.length === 0) return [createTextNode('')];\n\n\tconst result: TextNode[] = [];\n\tfor (const node of nodes) {\n\t\tconst prev: TextNode | undefined = result[result.length - 1];\n\t\tif (prev && markSetsEqual(prev.marks, node.marks)) {\n\t\t\tresult[result.length - 1] = createTextNode(prev.text + node.text, prev.marks);\n\t\t} else if (node.text.length > 0 || result.length === 0) {\n\t\t\tresult.push(node);\n\t\t}\n\t}\n\n\treturn result.length === 0 ? [createTextNode('')] : result;\n}\n\n/**\n * Normalizes mixed inline content: merges adjacent TextNodes with same marks,\n * removes empty TextNodes adjacent to InlineNodes, preserves InlineNodes as-is.\n * Guarantees at least one TextNode exists if all text is empty.\n */\nexport function normalizeInlineContent(\n\tnodes: readonly (TextNode | InlineNode)[],\n): readonly (TextNode | InlineNode)[] {\n\tif (nodes.length === 0) return [createTextNode('')];\n\n\t// Fast path: no InlineNodes, delegate to normalizeTextNodes\n\tif (nodes.every((n): n is TextNode => isTextNode(n))) {\n\t\treturn normalizeTextNodes(nodes);\n\t}\n\n\tconst result: (TextNode | InlineNode)[] = [];\n\n\tfor (const node of nodes) {\n\t\tif (isInlineNode(node)) {\n\t\t\tresult.push(node);\n\t\t\tcontinue;\n\t\t}\n\t\t// TextNode: try to merge with previous TextNode\n\t\tconst prev: TextNode | InlineNode | undefined = result[result.length - 1];\n\t\tif (prev && isTextNode(prev) && markSetsEqual(prev.marks, node.marks)) {\n\t\t\tresult[result.length - 1] = createTextNode(prev.text + node.text, prev.marks);\n\t\t} else if (node.text.length > 0 || result.length === 0) {\n\t\t\tresult.push(node);\n\t\t}\n\t}\n\n\t// Remove empty TextNodes that are adjacent to InlineNodes\n\tconst cleaned: (TextNode | InlineNode)[] = result.filter((node, i) => {\n\t\tif (isInlineNode(node)) return true;\n\t\tif (node.text.length > 0) return true;\n\t\t// Keep if it's the only node\n\t\tif (result.length === 1) return true;\n\t\t// Remove empty TextNode if adjacent to InlineNode\n\t\tconst prev: TextNode | InlineNode | undefined = result[i - 1];\n\t\tconst next: TextNode | InlineNode | undefined = result[i + 1];\n\t\tif ((prev && isInlineNode(prev)) || (next && isInlineNode(next))) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t});\n\n\t// Ensure at least one TextNode exists\n\tif (cleaned.length === 0) return [createTextNode('')];\n\tif (!cleaned.some((n) => isTextNode(n))) {\n\t\treturn [createTextNode(''), ...cleaned];\n\t}\n\n\treturn cleaned;\n}\n\n/** Yields each inline child with its offset range. InlineNodes have width 1. */\nexport function* walkInlineContent(children: readonly (TextNode | InlineNode)[]): Generator<{\n\treadonly child: TextNode | InlineNode;\n\treadonly from: number;\n\treadonly to: number;\n}> {\n\tlet pos = 0;\n\tfor (const child of children) {\n\t\tconst width: number = isInlineNode(child) ? 1 : child.text.length;\n\t\tyield { child, from: pos, to: pos + width };\n\t\tpos += width;\n\t}\n}\n\n/**\n * Converts a block-space offset to a text-space offset.\n *\n * Block-space counts InlineNodes as width 1, but `getBlockText()` skips them.\n * This function maps a block offset to the equivalent position in the\n * text-only string returned by `getBlockText()`.\n */\nexport function blockOffsetToTextOffset(block: BlockNode, blockOffset: number): number {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\tlet blockPos = 0;\n\tlet textPos = 0;\n\n\tfor (const child of inlineChildren) {\n\t\tif (isInlineNode(child)) {\n\t\t\tif (blockPos >= blockOffset) return textPos;\n\t\t\tblockPos += 1;\n\t\t} else {\n\t\t\tif (blockPos + child.text.length >= blockOffset) {\n\t\t\t\treturn textPos + (blockOffset - blockPos);\n\t\t\t}\n\t\t\tblockPos += child.text.length;\n\t\t\ttextPos += child.text.length;\n\t\t}\n\t}\n\n\treturn textPos;\n}\n\n/** Returns the content at a specific offset: text char, inline node, or null. */\nexport function getContentAtOffset(\n\tblock: BlockNode,\n\toffset: number,\n):\n\t| { readonly kind: 'text'; readonly char: string; readonly marks: readonly Mark[] }\n\t| { readonly kind: 'inline'; readonly node: InlineNode }\n\t| null {\n\tconst inlineChildren: readonly (TextNode | InlineNode)[] = getInlineChildren(block);\n\n\tfor (const { child, from } of walkInlineContent(inlineChildren)) {\n\t\tif (isInlineNode(child)) {\n\t\t\tif (offset === from) return { kind: 'inline', node: child };\n\t\t\tcontinue;\n\t\t}\n\t\tconst localOffset: number = offset - from;\n\t\tif (localOffset >= 0 && localOffset < child.text.length) {\n\t\t\treturn {\n\t\t\t\tkind: 'text',\n\t\t\t\tchar: child.text[localOffset] ?? '',\n\t\t\t\tmarks: child.marks,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn null;\n}\n"],"names":["getBlockSegmentsInRange","block","from","to","segments","walkBlockRange","onText","text","marks","push","getBlockContentSegmentsInRange","kind","onInline","node","visitor","inlineChildren","getInlineChildren","pos","child","childEnd","isInlineNode","length","sliceFrom","Math","max","sliceTo","min","slice","isTextNode","type","inlineType","isBlockNode","id","Array","isArray","children","isLeafBlock","every","c","getTextChildren","filter","getBlockChildren","generateBlockId","crypto","randomUUID","createDocument","createBlockNode","attrs","createTextNode","createInlineNode","getBlockText","getBlockLength","len","getBlockMarksAtOffset","offset","end","i","markSetsEqual","a","b","markA","some","markB","aAttrs","bAttrs","aKeys","Object","keys","bKeys","key","marksEqual","hasMark","markType","m","addMarkToSet","mark","removeMarkFromSet","normalizeInlineContent","nodes","n","result","prev","normalizeTextNodes","cleaned","next","blockOffsetToTextOffset","blockOffset","blockPos","textPos","getContentAtOffset","width","walkInlineContent","localOffset","char"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import t from"dompurify";import{p as e,g as s,k as n,o,q as r,r as i,a as c,e as l,c as a,d as u}from"./Document-3pNX7ear.mjs";import{a as f,S as p,e as g}from"./HTMLUtils-Cxy99Ak2.mjs";import{n as d,i as h,m as y}from"./TypeBrands-Bp_Z_o5Y.mjs";import{b as m}from"./AttrRegistry-iNpjvcSG.mjs";function A(t){let e=2166136261;for(let s=0;s<t.length;s++)e^=t.charCodeAt(s),e=Math.imul(e,16777619);return(e>>>0).toString(36).padStart(6,"0")}class L{classMap=/* @__PURE__ */new Map;usedHashes=/* @__PURE__ */new Set;getClassName(t){const e=function(t){return t.split(";").map(t=>t.trim()).filter(t=>t.length>0).sort().join("; ")}(t),s=this.classMap.get(e);if(s)return s;let n=A(e),o=0;for(;this.usedHashes.has(n);)o++,n=A(e+String(o));const r=`notectl-s-${n}`;return this.usedHashes.add(n),this.classMap.set(e,r),r}getAlignmentClassName(t){const e=`text-align: ${t}`,s=this.classMap.get(e);if(s)return s;const n=`notectl-align-${t}`;return this.classMap.set(e,n),n}toCSS(){if(0===this.classMap.size)return"";const t=[];for(const[e,s]of this.classMap)t.push(`.${s} { ${e}; }`);return t.join("\n")}toStyleMap(){const t=/* @__PURE__ */new Map;for(const[e,s]of this.classMap)t.set(s,e);return t}}function T(t){const e=t.getMarkTypes(),s=/* @__PURE__ */new Map;for(const n of e){const e=t.getMarkSpec(n);e&&s.set(n,e.rank??99)}return s}function b(t,e,s,n,o){if(""===t)return"";let r=f(t);if(0===e.length)return r;const i=n??T(s),c=[...e].sort((t,e)=>(i.get(t.type)??99)-(i.get(e.type)??99)),l=[],a=[];for(const u of c){const t=s.getMarkSpec(u.type);if(t?.toHTMLStyle){const e=t.toHTMLStyle(u);e&&l.push(e)}else a.push(u)}if(l.length>0){const t=l.join("; "),e=o?o.styleAttr(t):` style="${t}"`;e&&(r=`<span${e}>${r}</span>`)}for(const u of a){const t=s.getMarkSpec(u.type);t?.toHTMLString&&(r=t.toHTMLString(u,r,o))}return r}function M(t,e,s,n,o,r){if(""===t)return"";let i=f(t);if(0===e.length)return i;const c=o??T(s),l=[...e].sort((t,e)=>(c.get(t.type)??99)-(c.get(e.type)??99)),a=[],u=[];for(const f of l){const t=s.getMarkSpec(f.type);if(t?.toHTMLStyle){const e=t.toHTMLStyle(f);e&&a.push(e)}else u.push(f)}if(a.length>0){const t=a.join("; ");i=`<span class="${n.getClassName(t)}">${i}</span>`}for(const f of u){const t=s.getMarkSpec(f.type);t?.toHTMLString&&(i=t.toHTMLString(f,i,r))}return i}const S=/* @__PURE__ */new Set(["start","center","end","justify"]),$={left:"start",right:"end"},N=/* @__PURE__ */new Set(["ltr","rtl"]);function x(t,e,s){const n=function(t){let e=t.indexOf("<");for(;e>=0;){const s=t[e+1];if(s&&/[A-Za-z]/.test(s)){let s;for(let n=e+2;n<t.length;n++){const o=t[n]??"";if(s)o===s&&(s=void 0);else if('"'!==o&&"'"!==o){if(">"===o)return{start:e,end:n}}else s=o}return}e=t.indexOf("<",e+1)}}(t);if(!n)return t;const o=t.slice(n.start,n.end+1),r=new RegExp(`\\s${e}\\s*=\\s*("([^"]*)"|'([^']*)')`),i=o.match(r);if(i){const c=i[2]??i[3]??"";if("style"===e&&/(?:^|;)\s*text-align\s*:/i.test(c))return t;const l=` ${e}="${c}${"style"===e?"; ":" "}${s}"`,a=o.replace(r,l);return`${t.slice(0,n.start)}${a}${t.slice(n.end+1)}`}const c=o.endsWith("/>")?`${o.slice(0,-2)} ${e}="${s}"/>`:`${o.slice(0,-1)} ${e}="${s}">`;return`${t.slice(0,n.start)}${c}${t.slice(n.end+1)}`}function k(e,s){const n={registry:s,exportCtx:{styleAttr:t=>t?` style="${t}"`:""}},o=_(e.children,n),r=s?s.getAllowedTags():["p","br","div","span"],i=s?s.getAllowedAttrs():["style","dir"];return t.sanitize(o,{ALLOWED_TAGS:r,ALLOWED_ATTR:i,ALLOWED_URI_REGEXP:p})}function E(e,s){const n=new L,o=function(t){return{styleAttr:e=>e?` class="${t.getClassName(e)}"`:""}}(n),r={registry:s,collector:n,exportCtx:o},i=_(e.children,r),c=s?s.getAllowedTags():["p","br","div","span"],l=s?s.getAllowedAttrs():["style","class","dir"];l.includes("class")||l.push("class");const a=l.filter(t=>"style"!==t);return{html:t.sanitize(i,{ALLOWED_TAGS:c,ALLOWED_ATTR:a,ALLOWED_URI_REGEXP:p}),css:n.toCSS(),styleMap:n.toStyleMap()}}function _(t,e){const s=[];let n=0;for(;n<t.length;){const o=t[n];if(o)if(m(o,"list_item")){const o=[];for(;n<t.length;){const e=t[n];if(!e||!m(e,"list_item"))break;o.push(e),n++}s.push(v(o,e))}else s.push(C(o,e)),n++;else n++}return s.join("")}function v(t,e){const s=[],n=[];for(let o=0;o<t.length;o++){const r=t[o];if(!r)continue;const i=r.attrs?.listType??"bullet",c=r.attrs?.indent??0,l="ordered"===i?"ol":"ul";for(;n.length>0;){const t=n[n.length-1];if(!t)break;if(t.indent>c)s.push(`</${t.tag}></li>`),n.pop();else{if(t.indent!==c||t.tag===l)break;s.push(`</${t.tag}></li>`),n.pop()}}if(0===n.length)s.push(`<${l}>`),n.push({tag:l,indent:c});else{const t=n[n.length-1];t&&c>t.indent&&(s.push(`<${l}>`),n.push({tag:l,indent:c}))}const a=C(r,e),u=t[o+1],f=u?u.attrs?.indent??0:void 0;void 0!==f&&f>c?s.push(w(a)):s.push(a)}for(;n.length>0;){const t=n.pop();if(!t)break;s.push(`</${t.tag}>`),n.length>0&&s.push("</li>")}return s.join("")}function w(t){return t.endsWith("</li>")?t.slice(0,-5):t}function C(t,c){const l=e(t)?function(t,e){const s=function(t){if(t.length<=1)return t;const e=[];for(const s of t){if(o(s)){e.push(s);continue}const t=e[e.length-1];t&&r(t)&&i(t.marks,s.marks)?e[e.length-1]={type:"text",text:t.text+s.text,marks:t.marks}:e.push(s)}return e}(n(t)),c=[],l=e.registry?T(e.registry):void 0;for(const n of s)if(o(n)){const t=e.registry?.getInlineNodeSpec(n.inlineType);t?.toHTMLString&&c.push(t.toHTMLString(n))}else e.registry&&e.collector?c.push(M(n.text,n.marks,e.registry,e.collector,l,e.exportCtx)):e.registry?c.push(b(n.text,n.marks,e.registry,l,e.exportCtx)):""!==n.text&&c.push(f(n.text));return c.join("")}(t,c):_(s(t),c),a=c.registry?.getNodeSpec(t.type);let u;u=a?.toHTML?a.toHTML(t,l,c.exportCtx):`<p>${l||"<br>"}</p>`;const p=t.attrs?.align,d=p?$[p]??p:void 0;if(d&&"start"!==d&&S.has(d)){const t=g(d);if(c.collector){const t=c.collector.getAlignmentClassName(d);u=x(u,"class",g(t))}else u=x(u,"style",`text-align: ${t}`)}const h=t.attrs?.dir;if(h&&N.has(h)){const t=u.indexOf(">");u.slice(0,t+1).includes(" dir=")||(u=x(u,"dir",g(h)))}return u}const O=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,VALID_ALIGNMENTS:S,VALID_DIRECTIONS:N,serializeDocumentToCSS:E,serializeDocumentToHTML:k},Symbol.toStringTag,{value:"Module"}));function j(e,s,n){const o=s?s.getAllowedTags():["p","br","div","span"],r=s?s.getAllowedAttrs():["style","dir"];n?.styleMap&&!r.includes("class")&&r.push("class");const i=document.createElement("template");i.innerHTML=t.sanitize(e,{ALLOWED_TAGS:o,ALLOWED_ATTR:r,ALLOWED_URI_REGEXP:p});const l=i.content;n?.styleMap&&function(t,e){const s=t.querySelectorAll("[class]");for(const n of Array.from(s)){const t=n,s=Array.from(t.classList),o=[];for(const n of s){const s=e.get(n);if(s){const e=t.getAttribute("style")??"",r=e&&!e.endsWith(";")?"; ":"";t.setAttribute("style",e+r+s),o.push(n)}}for(const e of o)t.classList.remove(e)}}(l,n.styleMap);const a=s?.getBlockParseRules()??[],u=[];for(const t of Array.from(l.childNodes))D(t,u,a,s);return 0===u.length?c():c(u)}function D(t,e,s,n){if(t.nodeType===Node.ELEMENT_NODE){const o=t,r=o.tagName.toLowerCase();if("ul"===r||"ol"===r){const t="ol"===r?"ordered":"bullet",s=o.getAttribute("dir");return void H(o,t,0,e,n,s&&N.has(s)?s:void 0)}if("table"===r)return void function(t,e,s){const n=[],o=function(t){const e=[];for(const s of Array.from(t.children)){const t=s.tagName.toLowerCase();if("tr"===t)e.push(s);else if("thead"===t||"tbody"===t||"tfoot"===t)for(const n of Array.from(s.children))"tr"===n.tagName.toLowerCase()&&e.push(n)}return e}(t);for(const r of o){const t=[];for(const e of Array.from(r.children)){const n=e.tagName.toLowerCase();if("td"!==n&&"th"!==n)continue;const o=e,r=W(o,s),i={};I(o,i);const c=a(d("table_cell"),r,void 0,Object.keys(i).length>0?i:void 0);t.push(c)}t.length>0&&n.push(a(d("table_row"),t))}if(n.length>0){const s={};!function(t,e){const s=t.getAttribute("style")??"",n=R.exec(s);n?.[1]&&(e.borderColor="transparent"===n[1]?"none":n[1])}(t,s),e.push(a(d("table"),n,void 0,Object.keys(s).length>0?s:void 0))}}(o,e,n);const i=function(t,e){const s=t.tagName.toLowerCase();for(const n of e)if(n.rule.tag===s){if(n.rule.getAttrs){const e=n.rule.getAttrs(t);if(!1===e)continue;return{type:n.type,attrs:e}}return{type:n.type}}return null}(o,s);if(i){const t=n?.getNodeSpec(i.type),s=t?.isVoid?[l("")]:z(o,n),r={...i.attrs};return t?.attrs?.align&&U(o,r),t?.attrs?.dir&&G(o,r),void e.push(a(d(i.type),s,void 0,Object.keys(r).length>0?r:void 0))}const c=z(o,n),u={};U(o,u),G(o,u),e.push(a(d("paragraph"),c,void 0,Object.keys(u).length>0?u:void 0))}else t.nodeType===Node.TEXT_NODE&&t.textContent?.trim()&&e.push(a(d("paragraph"),[l(t.textContent.trim())]))}function H(t,e,s,n,o,r){for(const i of Array.from(t.children)){const t=i.tagName.toLowerCase();if("li"===t){const t=i,c=t.querySelector(':scope > input[type="checkbox"]'),l=null!==c,u=c?.hasAttribute("checked")??!1,f=l?"checklist":e,p=z(t,o,!0),g={listType:f,indent:s,checked:u},h=t.getAttribute("dir"),y=h&&N.has(h)?h:r;y&&(g.dir=y),n.push(a(d("list_item"),p,void 0,g));for(const e of Array.from(t.children)){const t=e.tagName.toLowerCase();if("ul"===t||"ol"===t){const r="ol"===t?"ordered":"bullet",i=e.getAttribute("dir");H(e,r,s+1,n,o,i&&N.has(i)?i:y)}}}else if("ul"===t||"ol"===t){const e="ol"===t?"ordered":"bullet",c=i.getAttribute("dir");H(i,e,s+1,n,o,c&&N.has(c)?c:r)}}}const R=/--ntbl-bc:\s*(#[0-9a-fA-F]{3,8}|transparent)/;function I(t,e){const s=t.getAttribute("colspan");if(s){const t=Number.parseInt(s,10);t>1&&(e.colspan=t)}const n=t.getAttribute("rowspan");if(n){const t=Number.parseInt(n,10);t>1&&(e.rowspan=t)}}function W(t,e){const s=e?.getBlockParseRules()??[],n=[];for(const o of Array.from(t.childNodes))D(o,n,s,e);if(0===n.length){const s=z(t,e);n.push(a(d("paragraph"),s))}return n}function z(t,e,s){const n=[];return P(t,[],n,e?.getMarkParseRules()??[],e?.getInlineParseRules()??[],s),n.length>0?n:[l("")]}function P(t,e,s,n,o,r){if(t.nodeType===Node.TEXT_NODE){const n=t.textContent??"";return void(n&&s.push(l(n,[...e])))}if(t.nodeType!==Node.ELEMENT_NODE)return;const i=t,c=i.tagName.toLowerCase();if(r&&("ul"===c||"ol"===c))return;if(r&&"input"===c&&"checkbox"===i.getAttribute("type"))return;for(const l of o)if(l.rule.tag===c){if(l.rule.getAttrs){const t=l.rule.getAttrs(i);if(!1===t)continue;return void s.push(u(h(l.type),t))}return void s.push(u(h(l.type)))}const a=[...e],f=/* @__PURE__ */new Set;for(const l of n)if(l.rule.tag===c&&!f.has(l.type))if(l.rule.getAttrs){const t=l.rule.getAttrs(i);if(!1===t)continue;a.some(t=>t.type===l.type)||(a.push({type:y(l.type),...Object.keys(t).length>0?{attrs:t}:{}}),f.add(l.type))}else a.some(t=>t.type===l.type)||(a.push({type:y(l.type)}),f.add(l.type));for(const l of Array.from(i.childNodes))P(l,a,s,n,o,r)}function G(t,e){const s=t.getAttribute("dir");if(s&&N.has(s))return void(e.dir=s);const n=t.style?.direction??"";n&&N.has(n)&&(e.dir=n)}const X={left:"start",right:"end"};function U(t,e){let s=t.style?.textAlign??"";const n=X[s];if(n&&(s=n),s&&S.has(s))e.align=s;else for(const o of Array.from(t.classList)){const t=o.match(/^notectl-align-(\w+)$/);let s=t?.[1];const n=X[s??""];if(n&&(s=n),s&&S.has(s))return void(e.align=s)}}const V=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,parseHTMLToDocument:j},Symbol.toStringTag,{value:"Module"}));export{O as D,S as V,N as a,k as b,T as c,b as d,V as e,j as p,E as s};
2
+ //# sourceMappingURL=DocumentParser-LvzDQOd1.mjs.map