@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
@@ -1,2 +1,2 @@
1
- import{i as t,a as e,r as n}from"../chunks/AttributedMarkCommands-BB7lzFct.mjs";import{a as r}from"../chunks/LocaleService-B6Z-wyAF.mjs";import{m as s}from"../chunks/Document-BFYAonMF.mjs";import{e as o}from"../chunks/HTMLUtils-CCvQ5f83.mjs";import{i,h as a,g as l}from"../chunks/Selection-6-W6Flxc.mjs";import{m as c}from"../chunks/TypeBrands-Bp_Z_o5Y.mjs";import{f as p}from"../chunks/ShortcutFormatting-BLKS0Gys.mjs";const m={label:"Link",tooltip:t=>`Insert Link (${t})`,removeLink:"Remove Link",removeLinkAria:"Remove link",urlPlaceholder:"https://...",urlAria:"Link URL",apply:"Apply",applyAria:"Apply link"},u=/* @__PURE__ */Object.assign({"./locales/ar.ts":()=>import("../chunks/ar-Deibepjm.mjs"),"./locales/de.ts":()=>import("../chunks/de-B5fcZ0FQ.mjs"),"./locales/es.ts":()=>import("../chunks/es-BbGOZGS_.mjs"),"./locales/fr.ts":()=>import("../chunks/fr-_Oxf0k66.mjs"),"./locales/hi.ts":()=>import("../chunks/hi-B2m69ZCq.mjs"),"./locales/pt.ts":()=>import("../chunks/pt-DsBJpgpe.mjs"),"./locales/ru.ts":()=>import("../chunks/ru-DdHqb4Mh.mjs"),"./locales/zh.ts":()=>import("../chunks/zh-v9NmlEIN.mjs")});async function h(t){if("en"===t)return m;const e=u[`./locales/${t}.ts`];if(!e)return m;try{return(await e()).default}catch{return m}}const k={openInNewTab:!0};class d{id="link";name="Link";priority=25;config;locale;constructor(t){this.config={...k,...t}}async init(t){if(this.config.locale)this.locale=this.config.locale;else{const e=t.getService(r),n=e?.getLocale()??"en";this.locale="en"===n?m:await h(n)}this.registerMarkSpec(t),this.registerCommands(t),this.registerKeymap(t),this.registerToolbarItem(t)}registerMarkSpec(t){const e=this.config.openInNewTab;t.registerMarkSpec({type:"link",rank:10,attrs:{href:{default:""}},toDOM(t){const n=document.createElement("a"),r=t.attrs?.href??"";return n.setAttribute("href",r),e&&(n.setAttribute("target","_blank"),n.setAttribute("rel","noopener noreferrer")),n},toHTMLString:(t,n)=>{const r=o(String(t.attrs?.href??""));return e?`<a href="${r}" target="_blank" rel="noopener noreferrer">${n}</a>`:`<a href="${r}">${n}</a>`},parseHTML:[{tag:"a",getAttrs:t=>({href:t.getAttribute("href")??""})}],sanitize:{tags:["a"],attrs:["href","target","rel"]}})}registerCommands(t){t.registerCommand("toggleLink",()=>{const e=t.getState();return this.toggleLink(t,e)}),t.registerCommand("setLink",()=>!1),t.registerCommand("removeLink",()=>{const e=t.getState();return this.removeLink(t,e)})}registerKeymap(t){t.registerKeymap({"Mod-K":()=>t.executeCommand("toggleLink")})}registerToolbarItem(t){t.registerToolbarItem({id:"link",group:"insert",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></svg>',label:this.locale.label,tooltip:this.locale.tooltip(p("Mod-K")),command:"toggleLink",popupType:"custom",renderPopup:(t,e,n)=>{this.renderLinkPopup(t,e,n)},isActive:t=>this.isLinkActive(t),isEnabled:t=>!i(t.selection)})}isLinkActive(e){return t(e,"link")}toggleLink(t,e){return!!this.isLinkActive(e)&&this.removeLink(t,e)}addLink(t,n,r){const s=n.selection;if(a(s)||l(s))return!1;if(i(s))return!1;const o={type:c("link"),attrs:{href:r}},p=e(n,o);return!!p&&(t.dispatch(p),!0)}removeLink(t,e){const r=e.selection;if(a(r)||l(r))return!1;if(i(r)){const n=e.getBlock(r.anchor.blockId);if(!n)return!1;const o=[];let i=0;for(const t of n.children){if(!("text"in t))continue;const e=i+t.text.length;o.push({pos:i,end:e,hasLink:s(t.marks,c("link"))}),i=e}const a=o.findIndex(t=>r.anchor.offset>=t.pos&&r.anchor.offset<=t.end),l=a>=0?o[a]:void 0;if(-1===a||!l?.hasLink)return!1;let p=a;for(;p>0&&o[p-1]?.hasLink;)p--;let m=a;for(;m<o.length-1&&o[m+1]?.hasLink;)m++;const u=o[p],h=o[m];if(!u||!h)return!1;const k=u.pos,d=h.end,g=e.transaction("command");return g.removeMark(r.anchor.blockId,k,d,{type:c("link")}),g.setSelection(r),t.dispatch(g.build()),!0}const o=n(e,c("link"));return!!o&&(t.dispatch(o),!0)}renderLinkPopup(t,e,n){t.classList.add("notectl-link-popup");const r=e.getState();if(this.isLinkActive(r)){const r=document.createElement("button");r.type="button",r.className="notectl-link-popup__button",r.textContent=this.locale.removeLink,r.setAttribute("aria-label",this.locale.removeLinkAria),r.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation(),e.executeCommand("removeLink"),n(),e.getContainer().focus()}),t.appendChild(r)}else{const r=document.createElement("input");r.type="url",r.className="notectl-link-popup__input",r.placeholder=this.locale.urlPlaceholder,r.setAttribute("aria-label",this.locale.urlAria);const s=document.createElement("button");s.type="button",s.className="notectl-link-popup__button notectl-link-popup__button--apply",s.textContent=this.locale.apply,s.setAttribute("aria-label",this.locale.applyAria);const o=()=>{const t=r.value.trim();t&&(this.addLink(e,e.getState(),t),n(),e.getContainer().focus())};s.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation(),o()}),r.addEventListener("keydown",t=>{"Enter"===t.key&&(t.preventDefault(),o())}),t.appendChild(r),t.appendChild(s),requestAnimationFrame(()=>r.focus())}}}export{m as LINK_LOCALE_EN,d as LinkPlugin,h as loadLinkLocale};
1
+ import{i as t,a as e,r as n}from"../chunks/AttributedMarkCommands-BY1BSYWM.mjs";import{m as r}from"../chunks/Document-3pNX7ear.mjs";import{a as s}from"../chunks/HTMLUtils-Cxy99Ak2.mjs";import{i as o,j as i}from"../chunks/Selection-DhbizDM4.mjs";import{m as a}from"../chunks/TypeBrands-Bp_Z_o5Y.mjs";import{r as l}from"../chunks/PluginHelpers-CdPR0MuT.mjs";import{f as c}from"../chunks/ShortcutFormatting-BLKS0Gys.mjs";const p={label:"Link",tooltip:t=>`Insert Link (${t})`,removeLink:"Remove Link",removeLinkAria:"Remove link",urlPlaceholder:"https://...",urlAria:"Link URL",apply:"Apply",applyAria:"Apply link"},m=/* @__PURE__ */Object.assign({"./locales/ar.ts":()=>import("../chunks/ar-Deibepjm.mjs"),"./locales/de.ts":()=>import("../chunks/de-B5fcZ0FQ.mjs"),"./locales/es.ts":()=>import("../chunks/es-BbGOZGS_.mjs"),"./locales/fr.ts":()=>import("../chunks/fr-_Oxf0k66.mjs"),"./locales/hi.ts":()=>import("../chunks/hi-B2m69ZCq.mjs"),"./locales/pt.ts":()=>import("../chunks/pt-DsBJpgpe.mjs"),"./locales/ru.ts":()=>import("../chunks/ru-DdHqb4Mh.mjs"),"./locales/zh.ts":()=>import("../chunks/zh-v9NmlEIN.mjs")});async function u(t){if("en"===t)return p;const e=m[`./locales/${t}.ts`];if(!e)return p;try{return(await e()).default}catch{return p}}const h={openInNewTab:!0};class k{id="link";name="Link";priority=25;config;locale;constructor(t){this.config={...h,...t}}async init(t){this.locale=await l(t,this.config.locale,p,u),this.registerMarkSpec(t),this.registerCommands(t),this.registerKeymap(t),this.registerToolbarItem(t)}registerMarkSpec(t){const e=this.config.openInNewTab;t.registerMarkSpec({type:"link",rank:10,attrs:{href:{default:""}},toDOM(t){const n=document.createElement("a"),r=t.attrs?.href??"";return n.setAttribute("href",r),e&&(n.setAttribute("target","_blank"),n.setAttribute("rel","noopener noreferrer")),n},toHTMLString:(t,n)=>{const r=s(String(t.attrs?.href??""));return e?`<a href="${r}" target="_blank" rel="noopener noreferrer">${n}</a>`:`<a href="${r}">${n}</a>`},parseHTML:[{tag:"a",getAttrs:t=>({href:t.getAttribute("href")??""})}],sanitize:{tags:["a"],attrs:["href","target","rel"]}})}registerCommands(t){t.registerCommand("toggleLink",()=>{const e=t.getState();return this.toggleLink(t,e)}),t.registerCommand("setLink",()=>!1),t.registerCommand("removeLink",()=>{const e=t.getState();return this.removeLink(t,e)})}registerKeymap(t){t.registerKeymap({"Mod-K":()=>t.executeCommand("toggleLink")})}registerToolbarItem(t){t.registerToolbarItem({id:"link",group:"insert",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></svg>',label:this.locale.label,tooltip:this.locale.tooltip(c("Mod-K")),command:"toggleLink",popupType:"custom",renderPopup:(t,e,n)=>{this.renderLinkPopup(t,e,n)},isActive:t=>this.isLinkActive(t),isEnabled:t=>!o(t.selection)})}isLinkActive(e){return t(e,"link")}toggleLink(t,e){return!!this.isLinkActive(e)&&this.removeLink(t,e)}addLink(t,n,r){const s=n.selection;if(!i(s))return!1;if(o(s))return!1;const l={type:a("link"),attrs:{href:r}},c=e(n,l);return!!c&&(t.dispatch(c),!0)}removeLink(t,e){const s=e.selection;if(!i(s))return!1;if(o(s)){const n=e.getBlock(s.anchor.blockId);if(!n)return!1;const o=[];let i=0;for(const t of n.children){if(!("text"in t))continue;const e=i+t.text.length;o.push({pos:i,end:e,hasLink:r(t.marks,a("link"))}),i=e}const l=o.findIndex(t=>s.anchor.offset>=t.pos&&s.anchor.offset<=t.end),c=l>=0?o[l]:void 0;if(-1===l||!c?.hasLink)return!1;let p=l;for(;p>0&&o[p-1]?.hasLink;)p--;let m=l;for(;m<o.length-1&&o[m+1]?.hasLink;)m++;const u=o[p],h=o[m];if(!u||!h)return!1;const k=u.pos,d=h.end,g=e.transaction("command");return g.removeMark(s.anchor.blockId,k,d,{type:a("link")}),g.setSelection(s),t.dispatch(g.build()),!0}const l=n(e,a("link"));return!!l&&(t.dispatch(l),!0)}renderLinkPopup(t,e,n){t.classList.add("notectl-link-popup");const r=e.getState();if(this.isLinkActive(r)){const r=document.createElement("button");r.type="button",r.className="notectl-link-popup__button",r.textContent=this.locale.removeLink,r.setAttribute("aria-label",this.locale.removeLinkAria),r.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation(),e.executeCommand("removeLink"),n(),e.getContainer().focus()}),t.appendChild(r)}else{const r=document.createElement("input");r.type="url",r.className="notectl-link-popup__input",r.placeholder=this.locale.urlPlaceholder,r.setAttribute("aria-label",this.locale.urlAria);const s=document.createElement("button");s.type="button",s.className="notectl-link-popup__button notectl-link-popup__button--apply",s.textContent=this.locale.apply,s.setAttribute("aria-label",this.locale.applyAria);const o=()=>{const t=r.value.trim();t&&(this.addLink(e,e.getState(),t),n(),e.getContainer().focus())};s.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation(),o()}),r.addEventListener("keydown",t=>{"Enter"===t.key&&(t.preventDefault(),o())}),t.appendChild(r),t.appendChild(s),requestAnimationFrame(()=>r.focus())}}}export{p as LINK_LOCALE_EN,k as LinkPlugin,u as loadLinkLocale};
2
2
  //# sourceMappingURL=link.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"link.mjs","sources":["../../src/plugins/link/LinkLocale.ts","../../src/plugins/link/LinkPlugin.ts"],"sourcesContent":["/**\n * Locale interface and default English locale for the LinkPlugin.\n */\n\n// --- Locale Interface ---\n\nexport interface LinkLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n\treadonly removeLink: string;\n\treadonly removeLinkAria: string;\n\treadonly urlPlaceholder: string;\n\treadonly urlAria: string;\n\treadonly apply: string;\n\treadonly applyAria: string;\n}\n\n// --- Default English Locale ---\n\nexport const LINK_LOCALE_EN: LinkLocale = {\n\tlabel: 'Link',\n\ttooltip: (shortcut: string) => `Insert Link (${shortcut})`,\n\tremoveLink: 'Remove Link',\n\tremoveLinkAria: 'Remove link',\n\turlPlaceholder: 'https://...',\n\turlAria: 'Link URL',\n\tapply: 'Apply',\n\tapplyAria: 'Apply link',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: LinkLocale }>> = import.meta.glob<{\n\tdefault: LinkLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadLinkLocale(lang: string): Promise<LinkLocale> {\n\tif (lang === 'en') return LINK_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return LINK_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn LINK_LOCALE_EN;\n\t}\n}\n","/**\n * LinkPlugin: registers a link mark type with href attribute,\n * toggle command, keyboard shortcut (Mod-K), and toolbar button\n * with a URL input popup.\n */\n\nimport {\n\tapplyAttributedMark,\n\tisAttributedMarkActive,\n\tremoveAttributedMark,\n} from '../../commands/AttributedMarkCommands.js';\nimport { LocaleServiceKey } from '../../i18n/LocaleService.js';\nimport { hasMark } from '../../model/Document.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { isCollapsed, isGapCursor, isNodeSelection } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { LINK_LOCALE_EN, type LinkLocale, loadLinkLocale } from './LinkLocale.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tlink: { href: string };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface LinkConfig {\n\t/** Whether to add rel=\"noopener noreferrer\" and target=\"_blank\" by default. */\n\treadonly openInNewTab: boolean;\n\treadonly locale?: LinkLocale;\n}\n\nconst DEFAULT_CONFIG: LinkConfig = {\n\topenInNewTab: true,\n};\n\n// --- Plugin ---\n\nexport class LinkPlugin implements Plugin {\n\treadonly id = 'link';\n\treadonly name = 'Link';\n\treadonly priority = 25;\n\n\tprivate readonly config: LinkConfig;\n\tprivate locale!: LinkLocale;\n\n\tconstructor(config?: Partial<LinkConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tif (this.config.locale) {\n\t\t\tthis.locale = this.config.locale;\n\t\t} else {\n\t\t\tconst service = context.getService(LocaleServiceKey);\n\t\t\tconst lang: string = service?.getLocale() ?? 'en';\n\t\t\tthis.locale = lang === 'en' ? LINK_LOCALE_EN : await loadLinkLocale(lang);\n\t\t}\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tconst openInNewTab = this.config.openInNewTab;\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'link',\n\t\t\trank: 10,\n\t\t\tattrs: {\n\t\t\t\thref: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst a = document.createElement('a');\n\t\t\t\tconst href = mark.attrs?.href ?? '';\n\t\t\t\ta.setAttribute('href', href);\n\t\t\t\tif (openInNewTab) {\n\t\t\t\t\ta.setAttribute('target', '_blank');\n\t\t\t\t\ta.setAttribute('rel', 'noopener noreferrer');\n\t\t\t\t}\n\t\t\t\treturn a;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst href: string = escapeHTML(String(mark.attrs?.href ?? ''));\n\t\t\t\tif (openInNewTab) {\n\t\t\t\t\treturn `<a href=\"${href}\" target=\"_blank\" rel=\"noopener noreferrer\">${content}</a>`;\n\t\t\t\t}\n\t\t\t\treturn `<a href=\"${href}\">${content}</a>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'a',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst href: string = el.getAttribute('href') ?? '';\n\t\t\t\t\t\treturn { href };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['a'], attrs: ['href', 'target', 'rel'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleLink', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.toggleLink(context, state);\n\t\t});\n\n\t\tcontext.registerCommand('setLink', () => {\n\t\t\t// setLink is called by the popup after URL input\n\t\t\t// The actual URL is set via the popup's custom render\n\t\t\treturn false;\n\t\t});\n\n\t\tcontext.registerCommand('removeLink', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.removeLink(context, state);\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-K': () => context.executeCommand('toggleLink'),\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'link',\n\t\t\tgroup: 'insert',\n\t\t\ticon,\n\t\t\tlabel: this.locale.label,\n\t\t\ttooltip: this.locale.tooltip(formatShortcut('Mod-K')),\n\t\t\tcommand: 'toggleLink',\n\t\t\tpopupType: 'custom',\n\t\t\trenderPopup: (container, ctx, onClose) => {\n\t\t\t\tthis.renderLinkPopup(container, ctx, onClose);\n\t\t\t},\n\t\t\tisActive: (state) => this.isLinkActive(state),\n\t\t\tisEnabled: (state) => !isCollapsed(state.selection),\n\t\t});\n\t}\n\n\tprivate isLinkActive(state: EditorState): boolean {\n\t\treturn isAttributedMarkActive(state, 'link');\n\t}\n\n\tprivate toggleLink(context: PluginContext, state: EditorState): boolean {\n\t\tif (this.isLinkActive(state)) {\n\t\t\treturn this.removeLink(context, state);\n\t\t}\n\t\t// Adding links requires the toolbar popup for URL input\n\t\treturn false;\n\t}\n\n\tprivate addLink(context: PluginContext, state: EditorState, href: string): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return false;\n\t\tif (isCollapsed(sel)) return false;\n\n\t\tconst mark = { type: markType('link'), attrs: { href } };\n\t\tconst tr = applyAttributedMark(state, mark);\n\t\tif (!tr) return false;\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate removeLink(context: PluginContext, state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\t// Remove link from entire link span around cursor (plugin-specific extent scan)\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return false;\n\n\t\t\tconst textChildren: { pos: number; end: number; hasLink: boolean }[] = [];\n\t\t\tlet pos = 0;\n\t\t\tfor (const child of block.children) {\n\t\t\t\tif (!('text' in child)) continue;\n\t\t\t\tconst end = pos + child.text.length;\n\t\t\t\ttextChildren.push({ pos, end, hasLink: hasMark(child.marks, markType('link')) });\n\t\t\t\tpos = end;\n\t\t\t}\n\n\t\t\tconst cursorIdx = textChildren.findIndex(\n\t\t\t\t(c) => sel.anchor.offset >= c.pos && sel.anchor.offset <= c.end,\n\t\t\t);\n\t\t\tconst cursorEntry = cursorIdx >= 0 ? textChildren[cursorIdx] : undefined;\n\t\t\tif (cursorIdx === -1 || !cursorEntry?.hasLink) return false;\n\n\t\t\tlet startIdx = cursorIdx;\n\t\t\twhile (startIdx > 0 && textChildren[startIdx - 1]?.hasLink) {\n\t\t\t\tstartIdx--;\n\t\t\t}\n\n\t\t\tlet endIdx = cursorIdx;\n\t\t\twhile (endIdx < textChildren.length - 1 && textChildren[endIdx + 1]?.hasLink) {\n\t\t\t\tendIdx++;\n\t\t\t}\n\n\t\t\tconst startEntry = textChildren[startIdx];\n\t\t\tconst endEntry = textChildren[endIdx];\n\t\t\tif (!startEntry || !endEntry) return false;\n\n\t\t\tconst linkStart = startEntry.pos;\n\t\t\tconst linkEnd = endEntry.end;\n\n\t\t\tconst builder = state.transaction('command');\n\t\t\tbuilder.removeMark(sel.anchor.blockId, linkStart, linkEnd, { type: markType('link') });\n\t\t\tbuilder.setSelection(sel);\n\t\t\tcontext.dispatch(builder.build());\n\t\t\treturn true;\n\t\t}\n\n\t\t// Range selection: delegate to shared helper\n\t\tconst tr = removeAttributedMark(state, markType('link'));\n\t\tif (!tr) return false;\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate renderLinkPopup(\n\t\tcontainer: HTMLElement,\n\t\tcontext: PluginContext,\n\t\tonClose: () => void,\n\t): void {\n\t\tcontainer.classList.add('notectl-link-popup');\n\n\t\tconst state = context.getState();\n\t\tconst isActive = this.isLinkActive(state);\n\n\t\tif (isActive) {\n\t\t\t// Show remove link button\n\t\t\tconst removeBtn = document.createElement('button');\n\t\t\tremoveBtn.type = 'button';\n\t\t\tremoveBtn.className = 'notectl-link-popup__button';\n\t\t\tremoveBtn.textContent = this.locale.removeLink;\n\t\t\tremoveBtn.setAttribute('aria-label', this.locale.removeLinkAria);\n\t\t\tremoveBtn.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tcontext.executeCommand('removeLink');\n\t\t\t\tonClose();\n\t\t\t\tcontext.getContainer().focus();\n\t\t\t});\n\t\t\tcontainer.appendChild(removeBtn);\n\t\t} else {\n\t\t\t// Show URL input\n\t\t\tconst input = document.createElement('input');\n\t\t\tinput.type = 'url';\n\t\t\tinput.className = 'notectl-link-popup__input';\n\t\t\tinput.placeholder = this.locale.urlPlaceholder;\n\t\t\tinput.setAttribute('aria-label', this.locale.urlAria);\n\n\t\t\tconst applyBtn = document.createElement('button');\n\t\t\tapplyBtn.type = 'button';\n\t\t\tapplyBtn.className = 'notectl-link-popup__button notectl-link-popup__button--apply';\n\t\t\tapplyBtn.textContent = this.locale.apply;\n\t\t\tapplyBtn.setAttribute('aria-label', this.locale.applyAria);\n\n\t\t\tconst applyLink = (): void => {\n\t\t\t\tconst href = input.value.trim();\n\t\t\t\tif (href) {\n\t\t\t\t\tthis.addLink(context, context.getState(), href);\n\t\t\t\t\tonClose();\n\t\t\t\t\tcontext.getContainer().focus();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tapplyBtn.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tapplyLink();\n\t\t\t});\n\n\t\t\tinput.addEventListener('keydown', (e) => {\n\t\t\t\tif (e.key === 'Enter') {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tapplyLink();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tcontainer.appendChild(input);\n\t\t\tcontainer.appendChild(applyBtn);\n\n\t\t\t// Auto-focus input\n\t\t\trequestAnimationFrame(() => input.focus());\n\t\t}\n\t}\n}\n"],"names":["LINK_LOCALE_EN","label","tooltip","shortcut","removeLink","removeLinkAria","urlPlaceholder","urlAria","apply","applyAria","localeModules","assign","import","async","loadLinkLocale","lang","loader","default","DEFAULT_CONFIG","openInNewTab","LinkPlugin","id","name","priority","config","locale","constructor","this","init","context","service","getService","LocaleServiceKey","getLocale","registerMarkSpec","registerCommands","registerKeymap","registerToolbarItem","type","rank","attrs","href","toDOM","mark","a","document","createElement","setAttribute","toHTMLString","content","escapeHTML","String","parseHTML","tag","getAttrs","el","getAttribute","sanitize","tags","registerCommand","state","getState","toggleLink","executeCommand","group","icon","formatShortcut","command","popupType","renderPopup","container","ctx","onClose","renderLinkPopup","isActive","isLinkActive","isEnabled","isCollapsed","selection","isAttributedMarkActive","addLink","sel","isNodeSelection","isGapCursor","markType","tr","applyAttributedMark","dispatch","block","getBlock","anchor","blockId","textChildren","pos","child","children","end","text","length","push","hasLink","hasMark","marks","cursorIdx","findIndex","c","offset","cursorEntry","startIdx","endIdx","startEntry","endEntry","linkStart","linkEnd","builder","transaction","removeMark","setSelection","build","removeAttributedMark","classList","add","removeBtn","className","textContent","addEventListener","e","preventDefault","stopPropagation","getContainer","focus","appendChild","input","placeholder","applyBtn","applyLink","value","trim","key","requestAnimationFrame"],"mappings":"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"}
1
+ {"version":3,"file":"link.mjs","sources":["../../src/plugins/link/LinkLocale.ts","../../src/plugins/link/LinkPlugin.ts"],"sourcesContent":["/**\n * Locale interface and default English locale for the LinkPlugin.\n */\n\n// --- Locale Interface ---\n\nexport interface LinkLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n\treadonly removeLink: string;\n\treadonly removeLinkAria: string;\n\treadonly urlPlaceholder: string;\n\treadonly urlAria: string;\n\treadonly apply: string;\n\treadonly applyAria: string;\n}\n\n// --- Default English Locale ---\n\nexport const LINK_LOCALE_EN: LinkLocale = {\n\tlabel: 'Link',\n\ttooltip: (shortcut: string) => `Insert Link (${shortcut})`,\n\tremoveLink: 'Remove Link',\n\tremoveLinkAria: 'Remove link',\n\turlPlaceholder: 'https://...',\n\turlAria: 'Link URL',\n\tapply: 'Apply',\n\tapplyAria: 'Apply link',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: LinkLocale }>> = import.meta.glob<{\n\tdefault: LinkLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadLinkLocale(lang: string): Promise<LinkLocale> {\n\tif (lang === 'en') return LINK_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return LINK_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn LINK_LOCALE_EN;\n\t}\n}\n","/**\n * LinkPlugin: registers a link mark type with href attribute,\n * toggle command, keyboard shortcut (Mod-K), and toolbar button\n * with a URL input popup.\n */\n\nimport {\n\tapplyAttributedMark,\n\tisAttributedMarkActive,\n\tremoveAttributedMark,\n} from '../../commands/AttributedMarkCommands.js';\nimport { hasMark } from '../../model/Document.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { LINK_LOCALE_EN, type LinkLocale, loadLinkLocale } from './LinkLocale.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tlink: { href: string };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface LinkConfig {\n\t/** Whether to add rel=\"noopener noreferrer\" and target=\"_blank\" by default. */\n\treadonly openInNewTab: boolean;\n\treadonly locale?: LinkLocale;\n}\n\nconst DEFAULT_CONFIG: LinkConfig = {\n\topenInNewTab: true,\n};\n\n// --- Plugin ---\n\nexport class LinkPlugin implements Plugin {\n\treadonly id = 'link';\n\treadonly name = 'Link';\n\treadonly priority = 25;\n\n\tprivate readonly config: LinkConfig;\n\tprivate locale!: LinkLocale;\n\n\tconstructor(config?: Partial<LinkConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(context, this.config.locale, LINK_LOCALE_EN, loadLinkLocale);\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tconst openInNewTab = this.config.openInNewTab;\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'link',\n\t\t\trank: 10,\n\t\t\tattrs: {\n\t\t\t\thref: { default: '' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst a = document.createElement('a');\n\t\t\t\tconst href = mark.attrs?.href ?? '';\n\t\t\t\ta.setAttribute('href', href);\n\t\t\t\tif (openInNewTab) {\n\t\t\t\t\ta.setAttribute('target', '_blank');\n\t\t\t\t\ta.setAttribute('rel', 'noopener noreferrer');\n\t\t\t\t}\n\t\t\t\treturn a;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst href: string = escapeHTML(String(mark.attrs?.href ?? ''));\n\t\t\t\tif (openInNewTab) {\n\t\t\t\t\treturn `<a href=\"${href}\" target=\"_blank\" rel=\"noopener noreferrer\">${content}</a>`;\n\t\t\t\t}\n\t\t\t\treturn `<a href=\"${href}\">${content}</a>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'a',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst href: string = el.getAttribute('href') ?? '';\n\t\t\t\t\t\treturn { href };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['a'], attrs: ['href', 'target', 'rel'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleLink', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.toggleLink(context, state);\n\t\t});\n\n\t\tcontext.registerCommand('setLink', () => {\n\t\t\t// setLink is called by the popup after URL input\n\t\t\t// The actual URL is set via the popup's custom render\n\t\t\treturn false;\n\t\t});\n\n\t\tcontext.registerCommand('removeLink', () => {\n\t\t\tconst state = context.getState();\n\t\t\treturn this.removeLink(context, state);\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-K': () => context.executeCommand('toggleLink'),\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'link',\n\t\t\tgroup: 'insert',\n\t\t\ticon,\n\t\t\tlabel: this.locale.label,\n\t\t\ttooltip: this.locale.tooltip(formatShortcut('Mod-K')),\n\t\t\tcommand: 'toggleLink',\n\t\t\tpopupType: 'custom',\n\t\t\trenderPopup: (container, ctx, onClose) => {\n\t\t\t\tthis.renderLinkPopup(container, ctx, onClose);\n\t\t\t},\n\t\t\tisActive: (state) => this.isLinkActive(state),\n\t\t\tisEnabled: (state) => !isCollapsed(state.selection),\n\t\t});\n\t}\n\n\tprivate isLinkActive(state: EditorState): boolean {\n\t\treturn isAttributedMarkActive(state, 'link');\n\t}\n\n\tprivate toggleLink(context: PluginContext, state: EditorState): boolean {\n\t\tif (this.isLinkActive(state)) {\n\t\t\treturn this.removeLink(context, state);\n\t\t}\n\t\t// Adding links requires the toolbar popup for URL input\n\t\treturn false;\n\t}\n\n\tprivate addLink(context: PluginContext, state: EditorState, href: string): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tif (isCollapsed(sel)) return false;\n\n\t\tconst mark = { type: markType('link'), attrs: { href } };\n\t\tconst tr = applyAttributedMark(state, mark);\n\t\tif (!tr) return false;\n\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate removeLink(context: PluginContext, state: EditorState): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\n\t\tif (isCollapsed(sel)) {\n\t\t\t// Remove link from entire link span around cursor (plugin-specific extent scan)\n\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\tif (!block) return false;\n\n\t\t\tconst textChildren: { pos: number; end: number; hasLink: boolean }[] = [];\n\t\t\tlet pos = 0;\n\t\t\tfor (const child of block.children) {\n\t\t\t\tif (!('text' in child)) continue;\n\t\t\t\tconst end = pos + child.text.length;\n\t\t\t\ttextChildren.push({ pos, end, hasLink: hasMark(child.marks, markType('link')) });\n\t\t\t\tpos = end;\n\t\t\t}\n\n\t\t\tconst cursorIdx = textChildren.findIndex(\n\t\t\t\t(c) => sel.anchor.offset >= c.pos && sel.anchor.offset <= c.end,\n\t\t\t);\n\t\t\tconst cursorEntry = cursorIdx >= 0 ? textChildren[cursorIdx] : undefined;\n\t\t\tif (cursorIdx === -1 || !cursorEntry?.hasLink) return false;\n\n\t\t\tlet startIdx = cursorIdx;\n\t\t\twhile (startIdx > 0 && textChildren[startIdx - 1]?.hasLink) {\n\t\t\t\tstartIdx--;\n\t\t\t}\n\n\t\t\tlet endIdx = cursorIdx;\n\t\t\twhile (endIdx < textChildren.length - 1 && textChildren[endIdx + 1]?.hasLink) {\n\t\t\t\tendIdx++;\n\t\t\t}\n\n\t\t\tconst startEntry = textChildren[startIdx];\n\t\t\tconst endEntry = textChildren[endIdx];\n\t\t\tif (!startEntry || !endEntry) return false;\n\n\t\t\tconst linkStart = startEntry.pos;\n\t\t\tconst linkEnd = endEntry.end;\n\n\t\t\tconst builder = state.transaction('command');\n\t\t\tbuilder.removeMark(sel.anchor.blockId, linkStart, linkEnd, { type: markType('link') });\n\t\t\tbuilder.setSelection(sel);\n\t\t\tcontext.dispatch(builder.build());\n\t\t\treturn true;\n\t\t}\n\n\t\t// Range selection: delegate to shared helper\n\t\tconst tr = removeAttributedMark(state, markType('link'));\n\t\tif (!tr) return false;\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate renderLinkPopup(\n\t\tcontainer: HTMLElement,\n\t\tcontext: PluginContext,\n\t\tonClose: () => void,\n\t): void {\n\t\tcontainer.classList.add('notectl-link-popup');\n\n\t\tconst state = context.getState();\n\t\tconst isActive = this.isLinkActive(state);\n\n\t\tif (isActive) {\n\t\t\t// Show remove link button\n\t\t\tconst removeBtn = document.createElement('button');\n\t\t\tremoveBtn.type = 'button';\n\t\t\tremoveBtn.className = 'notectl-link-popup__button';\n\t\t\tremoveBtn.textContent = this.locale.removeLink;\n\t\t\tremoveBtn.setAttribute('aria-label', this.locale.removeLinkAria);\n\t\t\tremoveBtn.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tcontext.executeCommand('removeLink');\n\t\t\t\tonClose();\n\t\t\t\tcontext.getContainer().focus();\n\t\t\t});\n\t\t\tcontainer.appendChild(removeBtn);\n\t\t} else {\n\t\t\t// Show URL input\n\t\t\tconst input = document.createElement('input');\n\t\t\tinput.type = 'url';\n\t\t\tinput.className = 'notectl-link-popup__input';\n\t\t\tinput.placeholder = this.locale.urlPlaceholder;\n\t\t\tinput.setAttribute('aria-label', this.locale.urlAria);\n\n\t\t\tconst applyBtn = document.createElement('button');\n\t\t\tapplyBtn.type = 'button';\n\t\t\tapplyBtn.className = 'notectl-link-popup__button notectl-link-popup__button--apply';\n\t\t\tapplyBtn.textContent = this.locale.apply;\n\t\t\tapplyBtn.setAttribute('aria-label', this.locale.applyAria);\n\n\t\t\tconst applyLink = (): void => {\n\t\t\t\tconst href = input.value.trim();\n\t\t\t\tif (href) {\n\t\t\t\t\tthis.addLink(context, context.getState(), href);\n\t\t\t\t\tonClose();\n\t\t\t\t\tcontext.getContainer().focus();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tapplyBtn.addEventListener('mousedown', (e) => {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tapplyLink();\n\t\t\t});\n\n\t\t\tinput.addEventListener('keydown', (e) => {\n\t\t\t\tif (e.key === 'Enter') {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tapplyLink();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tcontainer.appendChild(input);\n\t\t\tcontainer.appendChild(applyBtn);\n\n\t\t\t// Auto-focus input\n\t\t\trequestAnimationFrame(() => input.focus());\n\t\t}\n\t}\n}\n"],"names":["LINK_LOCALE_EN","label","tooltip","shortcut","removeLink","removeLinkAria","urlPlaceholder","urlAria","apply","applyAria","localeModules","assign","import","async","loadLinkLocale","lang","loader","default","DEFAULT_CONFIG","openInNewTab","LinkPlugin","id","name","priority","config","locale","constructor","this","init","context","resolveLocale","registerMarkSpec","registerCommands","registerKeymap","registerToolbarItem","type","rank","attrs","href","toDOM","mark","a","document","createElement","setAttribute","toHTMLString","content","escapeHTML","String","parseHTML","tag","getAttrs","el","getAttribute","sanitize","tags","registerCommand","state","getState","toggleLink","executeCommand","group","icon","formatShortcut","command","popupType","renderPopup","container","ctx","onClose","renderLinkPopup","isActive","isLinkActive","isEnabled","isCollapsed","selection","isAttributedMarkActive","addLink","sel","isTextSelection","markType","tr","applyAttributedMark","dispatch","block","getBlock","anchor","blockId","textChildren","pos","child","children","end","text","length","push","hasLink","hasMark","marks","cursorIdx","findIndex","c","offset","cursorEntry","startIdx","endIdx","startEntry","endEntry","linkStart","linkEnd","builder","transaction","removeMark","setSelection","build","removeAttributedMark","classList","add","removeBtn","className","textContent","addEventListener","e","preventDefault","stopPropagation","getContainer","focus","appendChild","input","placeholder","applyBtn","applyLink","value","trim","key","requestAnimationFrame"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ListPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/list/ListPlugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgBH,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAkB,KAAK,UAAU,EAAkB,MAAM,iBAAiB,CAAC;AAIlF,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;AAE1D,OAAO,QAAQ,6BAA6B,CAAC;IAC5C,UAAU,gBAAgB;QACzB,SAAS,EAAE;YAAE,QAAQ,EAAE,QAAQ,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC;KACpE;CACD;AAID,MAAM,WAAW,UAAU;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,2CAA2C;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;CAC7B;AA8CD,qBAAa,UAAW,YAAW,MAAM;IACxC,QAAQ,CAAC,EAAE,UAAU;IACrB,QAAQ,CAAC,IAAI,UAAU;IACvB,QAAQ,CAAC,QAAQ,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,oBAAoB,CAA0C;gBAE1D,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC;IAIlC,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBjD,OAAO,IAAI,IAAI;IASf,OAAO,CAAC,gBAAgB;IAmExB,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,UAAU;IAoClB,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,SAAS;IAiBjB,OAAO,CAAC,aAAa;IA4BrB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IA4CnB,OAAO,CAAC,4BAA4B;IA+BpC,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,eAAe;CAGvB"}
1
+ {"version":3,"file":"ListPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/list/ListPlugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,EAAkB,KAAK,UAAU,EAAkB,MAAM,iBAAiB,CAAC;AAIlF,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;AAE1D,OAAO,QAAQ,6BAA6B,CAAC;IAC5C,UAAU,gBAAgB;QACzB,SAAS,EAAE;YAAE,QAAQ,EAAE,QAAQ,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC;KACpE;CACD;AAID,MAAM,WAAW,UAAU;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,2CAA2C;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;CAC7B;AA8CD,qBAAa,UAAW,YAAW,MAAM;IACxC,QAAQ,CAAC,EAAE,UAAU;IACrB,QAAQ,CAAC,IAAI,UAAU;IACvB,QAAQ,CAAC,QAAQ,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,oBAAoB,CAA0C;gBAE1D,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC;IAIlC,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjD,OAAO,IAAI,IAAI;IASf,OAAO,CAAC,gBAAgB;IAmExB,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,UAAU;IAoClB,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,SAAS;IAiBjB,OAAO,CAAC,aAAa;IAyBrB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IA4CnB,OAAO,CAAC,4BAA4B;IA+BpC,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,eAAe;CAGvB"}
@@ -1,2 +1,2 @@
1
- import{a as t}from"../chunks/LocaleService-B6Z-wyAF.mjs";import{b as e}from"../chunks/AttrRegistry-B2AGfTE0.mjs";import{i as n,s as i}from"../chunks/Document-BFYAonMF.mjs";import{h as s,g as c,i as r,c as o}from"../chunks/Selection-6-W6Flxc.mjs";import{n as l,b as a}from"../chunks/TypeBrands-Bp_Z_o5Y.mjs";import{a as d}from"../chunks/StyleRuntime-BmsLoEa8.mjs";import{c as h}from"../chunks/DomUtils-Cdz1eDKM.mjs";const u={bulletList:"Bullet List",numberedList:"Numbered List",checklist:"Checklist"},p=/* @__PURE__ */Object.assign({"./locales/ar.ts":()=>import("../chunks/ar-BtOQ7lro.mjs"),"./locales/de.ts":()=>import("../chunks/de-PZ9-LlBp.mjs"),"./locales/es.ts":()=>import("../chunks/es-C7e35Muh.mjs"),"./locales/fr.ts":()=>import("../chunks/fr-DvneSjCf.mjs"),"./locales/hi.ts":()=>import("../chunks/hi-Zc17M1T-.mjs"),"./locales/pt.ts":()=>import("../chunks/pt-BF72W8M5.mjs"),"./locales/ru.ts":()=>import("../chunks/ru-B6zVAzvI.mjs"),"./locales/zh.ts":()=>import("../chunks/zh-CWdTbUOP.mjs")});async function m(t){if("en"===t)return u;const e=p[`./locales/${t}.ts`];if(!e)return u;try{return(await e()).default}catch{return u}}const g={types:["bullet","ordered","checklist"],maxIndent:4},k=[{type:"bullet",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/></svg>',inputPattern:/^[-*] $/,inputPrefix:"- "},{type:"ordered",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z"/></svg>',inputPattern:/^\d+\. $/,inputPrefix:"1. "},{type:"checklist",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22 7h-9v2h9V7zm0 8h-9v2h9v-2zM5.54 11L2 7.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 11zm0 8L2 15.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 19z"/></svg>',inputPattern:/^\[[ x]] $/,inputPrefix:"[ ] "}];class b{id="list";name="List";priority=35;config;locale;context=null;checkboxClickHandler=null;constructor(t){this.config={...g,...t}}async init(e){if(this.context=e,this.config.locale)this.locale=this.config.locale;else{const n=e.getService(t),i=n?.getLocale()??"en";this.locale="en"===i?u:await m(i)}e.registerStyleSheet("\n/* List Wrappers — suppress native markers, we use ::before pseudo-elements */\n.notectl-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Ordered List — each <ol> wrapper resets the counter */\n.notectl-list--ordered {\n\tcounter-reset: notectl-ordered;\n}\n\n/* List Items */\n.notectl-list-item {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: 24px;\n\tmin-height: 1.6em;\n\tposition: relative;\n}\n\n.notectl-list-item::before {\n\tposition: absolute;\n\tinset-inline-start: 0;\n\tdisplay: inline-block;\n\twidth: 24px;\n\ttext-align: center;\n}\n\n/* Bullet List */\n.notectl-list-item--bullet::before {\n\tcontent: '\\2022';\n\tcolor: var(--notectl-fg);\n}\n\n/* Ordered List — counter increment per item */\n.notectl-list-item--ordered {\n\tcounter-increment: notectl-ordered;\n}\n\n.notectl-list-item--ordered::before {\n\tcontent: counter(notectl-ordered) '.';\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n}\n\n/* Checklist */\n.notectl-list-item--checklist::before {\n\tcontent: '\\2610';\n\tfont-size: 16px;\n\tcolor: var(--notectl-fg-muted);\n\tcursor: pointer;\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"]::before {\n\tcontent: '\\2611';\n\tcolor: var(--notectl-success);\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"] {\n\tcolor: var(--notectl-fg-muted);\n\ttext-decoration: line-through;\n}\n"),this.registerNodeSpec(e),this.registerCommands(e),this.registerKeymaps(e),this.registerInputRules(e),this.registerToolbarItems(e),this.registerCheckboxClickHandler(e)}destroy(){this.checkboxClickHandler&&this.context&&this.context.getContainer().removeEventListener("mousedown",this.checkboxClickHandler),this.checkboxClickHandler=null,this.context=null}registerNodeSpec(t){t.registerNodeSpec({type:"list_item",group:"block",content:{allow:["text"]},attrs:{listType:{default:"bullet"},indent:{default:0},checked:{default:!1}},toDOM(t){const e=t.attrs?.listType??"bullet",n=t.attrs?.indent??0,i=t.attrs?.checked??!1,s=h("li",t.id);return s.setAttribute("role","listitem"),s.setAttribute("data-list-type",e),s.setAttribute("data-indent",String(n)),s.className=`notectl-list-item notectl-list-item--${e}`,n>0&&d(s,"marginLeft",24*n+"px"),"checklist"===e&&(s.setAttribute("data-checked",String(i)),s.setAttribute("aria-checked",String(i))),s.setAttribute("aria-level",String(n+1)),s},wrapper(t){const e=t.attrs?.listType??"bullet";return{tag:"ordered"===e?"ol":"ul",key:`list-${e}`,className:`notectl-list notectl-list--${e}`,attrs:{role:"list"}}},toHTML(t,e){const n=t.attrs?.listType??"bullet",i=t.attrs?.checked??!1;if("checklist"===n){const t=i?" checked":"";return`<li role="checkbox" aria-checked="${String(i)}"><input type="checkbox" disabled${t}>${e||"<br>"}</li>`}return`<li>${e||"<br>"}</li>`},parseHTML:[{tag:"li"}],sanitize:{tags:["ul","ol","li","input"],attrs:["type","disabled","checked","role","aria-checked"]}})}registerCommands(t){const e=this.getEnabledTypes();for(const n of e)t.registerCommand(`toggleList:${n.type}`,()=>this.toggleList(t,n.type));t.registerCommand("indentListItem",()=>this.indent(t)),t.registerCommand("outdentListItem",()=>this.outdent(t)),this.config.types.includes("checklist")&&t.registerCommand("toggleChecklistItem",()=>this.toggleChecked(t),{readonlyAllowed:!0})}registerKeymaps(t){t.registerKeymap({Enter:()=>this.handleEnter(t),Backspace:()=>this.handleBackspace(t),Tab:()=>this.indent(t),"Shift-Tab":()=>this.outdent(t)})}registerInputRules(t){const e=this.getEnabledTypes();for(const n of e)t.registerInputRule({pattern:n.inputPattern,handler:(t,e,i,a)=>{const d=t.selection;if(s(d)||c(d))return null;if(!r(d))return null;const h=t.getBlock(d.anchor.blockId);if(!h||"paragraph"!==h.type)return null;const u=e[0]??"",p=u.length,m={listType:n.type,indent:0};return"checklist"===n.type&&(m.checked=u.includes("[x]")),t.transaction("input").deleteTextAt(d.anchor.blockId,i,i+p).setBlockType(d.anchor.blockId,l("list_item"),m).setSelection(o(d.anchor.blockId,0)).build()}})}getListLabel(t){return{bullet:this.locale.bulletList,ordered:this.locale.numberedList,checklist:this.locale.checklist}[t]}registerToolbarItems(t){const e=this.getEnabledTypes();for(const n of e)t.registerToolbarItem({id:`list-${n.type}`,group:"block",icon:n.icon,label:this.getListLabel(n.type),command:`toggleList:${n.type}`,isActive:t=>this.isListActive(t,n.type)})}toggleList(t,n){const i=t.getState(),r=i.selection;if(s(r)||c(r))return!1;const o=i.getBlock(r.anchor.blockId);if(!o)return!1;if("list_item"===o.type&&o.attrs?.listType===n){const e=i.transaction("command").setBlockType(r.anchor.blockId,l("paragraph")).setSelection(r).build();return t.dispatch(e),!0}const a={listType:n,indent:e(o,"list_item")?o.attrs.indent:0};"checklist"===n&&(a.checked=!1);const d=i.transaction("command").setBlockType(r.anchor.blockId,l("list_item"),a).setSelection(r).build();return t.dispatch(d),!0}indent(t){const n=t.getState();if(s(n.selection)||c(n.selection))return!1;const i=n.getBlock(n.selection.anchor.blockId);return!(!i||!e(i,"list_item"))&&!(i.attrs.indent>=this.config.maxIndent)&&this.setIndent(t,n,i.attrs.indent+1)}outdent(t){const n=t.getState();if(s(n.selection)||c(n.selection))return!1;const i=n.getBlock(n.selection.anchor.blockId);return!(!i||!e(i,"list_item"))&&!(i.attrs.indent<=0)&&this.setIndent(t,n,i.attrs.indent-1)}setIndent(t,e,n){const i=e.selection;if(s(i)||c(i))return!1;const r=e.getBlock(i.anchor.blockId);if(!r)return!1;const o={...r.attrs,indent:n},a=e.transaction("command").setBlockType(i.anchor.blockId,l("list_item"),o).setSelection(i).build();return t.dispatch(a),!0}toggleChecked(t,e){if(t.isReadOnly()&&!this.config.interactiveCheckboxes)return!1;const n=t.getState(),i=e??(s(n.selection)||c(n.selection)?null:n.selection.anchor.blockId);if(!i)return!1;const r=n.getBlock(i);if(!r||"list_item"!==r.type||"checklist"!==r.attrs?.listType)return!1;const o=!r.attrs?.checked,a={...r.attrs,checked:o},d=n.transaction("command").setBlockType(i,l("list_item"),a).setSelection(n.selection).build();return t.dispatch(d),!0}handleBackspace(t){const e=t.getState(),n=e.selection;if(s(n)||c(n))return!1;if(!r(n))return!1;const i=e.getBlock(n.anchor.blockId);if(!i||"list_item"!==i.type)return!1;if(0!==n.anchor.offset)return!1;const o=e.transaction("input").setBlockType(n.anchor.blockId,l("paragraph")).setSelection(n).build();return t.dispatch(o),!0}handleEnter(t){const a=t.getState(),d=a.selection;if(s(d)||c(d))return!1;if(!r(d))return!1;const h=a.getBlock(d.anchor.blockId);if(!h||"list_item"!==h.type)return!1;if(""===n(h)){const e=a.transaction("input").setBlockType(d.anchor.blockId,l("paragraph")).setSelection(d).build();return t.dispatch(e),!0}const u=i(),p={listType:e(h,"list_item")?h.attrs.listType:"bullet",indent:e(h,"list_item")?h.attrs.indent:0};"checklist"===p.listType&&(p.checked=!1);const m=a.transaction("input").splitBlock(d.anchor.blockId,d.anchor.offset,u).setBlockType(u,l("list_item"),p).setSelection(o(u,0)).build();return t.dispatch(m),!0}registerCheckboxClickHandler(t){this.config.types.includes("checklist")&&(this.checkboxClickHandler=e=>{if(t.isReadOnly()&&!this.config.interactiveCheckboxes)return;const n=e.target;if(!(n instanceof HTMLElement))return;const i=n.closest(".notectl-list-item--checklist");if(!i)return;const s=i.getBoundingClientRect();if(("rtl"===getComputedStyle(i).direction?s.right-e.clientX:e.clientX-s.left)>=24)return;e.preventDefault();const c=i.getAttribute("data-block-id");c&&this.toggleChecked(t,a(c))},t.getContainer().addEventListener("mousedown",this.checkboxClickHandler))}isListActive(t,e){if(s(t.selection)||c(t.selection))return!1;const n=t.getBlock(t.selection.anchor.blockId);return"list_item"===n?.type&&n.attrs?.listType===e}getEnabledTypes(){return k.filter(t=>this.config.types.includes(t.type))}}export{u as LIST_LOCALE_EN,b as ListPlugin,m as loadListLocale};
1
+ import{b as t}from"../chunks/AttrRegistry-iNpjvcSG.mjs";import{i as e,s as n}from"../chunks/Document-3pNX7ear.mjs";import{j as i,i as s,c}from"../chunks/Selection-DhbizDM4.mjs";import{n as r,b as o}from"../chunks/TypeBrands-Bp_Z_o5Y.mjs";import{a as l}from"../chunks/StyleRuntime-BmsLoEa8.mjs";import{c as a}from"../chunks/DomUtils-CznMAZZg.mjs";import{r as d}from"../chunks/PluginHelpers-CdPR0MuT.mjs";const h={bulletList:"Bullet List",numberedList:"Numbered List",checklist:"Checklist"},u=/* @__PURE__ */Object.assign({"./locales/ar.ts":()=>import("../chunks/ar-BtOQ7lro.mjs"),"./locales/de.ts":()=>import("../chunks/de-PZ9-LlBp.mjs"),"./locales/es.ts":()=>import("../chunks/es-C7e35Muh.mjs"),"./locales/fr.ts":()=>import("../chunks/fr-DvneSjCf.mjs"),"./locales/hi.ts":()=>import("../chunks/hi-Zc17M1T-.mjs"),"./locales/pt.ts":()=>import("../chunks/pt-BF72W8M5.mjs"),"./locales/ru.ts":()=>import("../chunks/ru-B6zVAzvI.mjs"),"./locales/zh.ts":()=>import("../chunks/zh-CWdTbUOP.mjs")});async function p(t){if("en"===t)return h;const e=u[`./locales/${t}.ts`];if(!e)return h;try{return(await e()).default}catch{return h}}const m={types:["bullet","ordered","checklist"],maxIndent:4},k=[{type:"bullet",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/></svg>',inputPattern:/^[-*] $/,inputPrefix:"- "},{type:"ordered",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z"/></svg>',inputPattern:/^\d+\. $/,inputPrefix:"1. "},{type:"checklist",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22 7h-9v2h9V7zm0 8h-9v2h9v-2zM5.54 11L2 7.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 11zm0 8L2 15.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 19z"/></svg>',inputPattern:/^\[[ x]] $/,inputPrefix:"[ ] "}];class g{id="list";name="List";priority=35;config;locale;context=null;checkboxClickHandler=null;constructor(t){this.config={...m,...t}}async init(t){this.context=t,this.locale=await d(t,this.config.locale,h,p),t.registerStyleSheet("\n/* List Wrappers — suppress native markers, we use ::before pseudo-elements */\n.notectl-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Ordered List — each <ol> wrapper resets the counter */\n.notectl-list--ordered {\n\tcounter-reset: notectl-ordered;\n}\n\n/* List Items */\n.notectl-list-item {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: 24px;\n\tmin-height: 1.6em;\n\tposition: relative;\n}\n\n.notectl-list-item::before {\n\tposition: absolute;\n\tinset-inline-start: 0;\n\tdisplay: inline-block;\n\twidth: 24px;\n\ttext-align: center;\n}\n\n/* Bullet List */\n.notectl-list-item--bullet::before {\n\tcontent: '\\2022';\n\tcolor: var(--notectl-fg);\n}\n\n/* Ordered List — counter increment per item */\n.notectl-list-item--ordered {\n\tcounter-increment: notectl-ordered;\n}\n\n.notectl-list-item--ordered::before {\n\tcontent: counter(notectl-ordered) '.';\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n}\n\n/* Checklist */\n.notectl-list-item--checklist::before {\n\tcontent: '\\2610';\n\tfont-size: 16px;\n\tcolor: var(--notectl-fg-muted);\n\tcursor: pointer;\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"]::before {\n\tcontent: '\\2611';\n\tcolor: var(--notectl-success);\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"] {\n\tcolor: var(--notectl-fg-muted);\n\ttext-decoration: line-through;\n}\n"),this.registerNodeSpec(t),this.registerCommands(t),this.registerKeymaps(t),this.registerInputRules(t),this.registerToolbarItems(t),this.registerCheckboxClickHandler(t)}destroy(){this.checkboxClickHandler&&this.context&&this.context.getContainer().removeEventListener("mousedown",this.checkboxClickHandler),this.checkboxClickHandler=null,this.context=null}registerNodeSpec(t){t.registerNodeSpec({type:"list_item",group:"block",content:{allow:["text"]},attrs:{listType:{default:"bullet"},indent:{default:0},checked:{default:!1}},toDOM(t){const e=t.attrs?.listType??"bullet",n=t.attrs?.indent??0,i=t.attrs?.checked??!1,s=a("li",t.id);return s.setAttribute("role","listitem"),s.setAttribute("data-list-type",e),s.setAttribute("data-indent",String(n)),s.className=`notectl-list-item notectl-list-item--${e}`,n>0&&l(s,"marginLeft",24*n+"px"),"checklist"===e&&(s.setAttribute("data-checked",String(i)),s.setAttribute("aria-checked",String(i))),s.setAttribute("aria-level",String(n+1)),s},wrapper(t){const e=t.attrs?.listType??"bullet";return{tag:"ordered"===e?"ol":"ul",key:`list-${e}`,className:`notectl-list notectl-list--${e}`,attrs:{role:"list"}}},toHTML(t,e){const n=t.attrs?.listType??"bullet",i=t.attrs?.checked??!1;if("checklist"===n){const t=i?" checked":"";return`<li role="checkbox" aria-checked="${String(i)}"><input type="checkbox" disabled${t}>${e||"<br>"}</li>`}return`<li>${e||"<br>"}</li>`},parseHTML:[{tag:"li"}],sanitize:{tags:["ul","ol","li","input"],attrs:["type","disabled","checked","role","aria-checked"]}})}registerCommands(t){const e=this.getEnabledTypes();for(const n of e)t.registerCommand(`toggleList:${n.type}`,()=>this.toggleList(t,n.type));t.registerCommand("indentListItem",()=>this.indent(t)),t.registerCommand("outdentListItem",()=>this.outdent(t)),this.config.types.includes("checklist")&&t.registerCommand("toggleChecklistItem",()=>this.toggleChecked(t),{readonlyAllowed:!0})}registerKeymaps(t){t.registerKeymap({Enter:()=>this.handleEnter(t),Backspace:()=>this.handleBackspace(t),Tab:()=>this.indent(t),"Shift-Tab":()=>this.outdent(t)})}registerInputRules(t){const e=this.getEnabledTypes();for(const n of e)t.registerInputRule({pattern:n.inputPattern,handler:(t,e,o,l)=>{const a=t.selection;if(!i(a))return null;if(!s(a))return null;const d=t.getBlock(a.anchor.blockId);if(!d||"paragraph"!==d.type)return null;const h=e[0]??"",u=h.length,p={listType:n.type,indent:0};return"checklist"===n.type&&(p.checked=h.includes("[x]")),t.transaction("input").deleteTextAt(a.anchor.blockId,o,o+u).setBlockType(a.anchor.blockId,r("list_item"),p).setSelection(c(a.anchor.blockId,0)).build()}})}getListLabel(t){return{bullet:this.locale.bulletList,ordered:this.locale.numberedList,checklist:this.locale.checklist}[t]}registerToolbarItems(t){const e=this.getEnabledTypes();for(const n of e)t.registerToolbarItem({id:`list-${n.type}`,group:"block",icon:n.icon,label:this.getListLabel(n.type),command:`toggleList:${n.type}`,isActive:t=>this.isListActive(t,n.type)})}toggleList(e,n){const s=e.getState(),c=s.selection;if(!i(c))return!1;const o=s.getBlock(c.anchor.blockId);if(!o)return!1;if("list_item"===o.type&&o.attrs?.listType===n){const t=s.transaction("command").setBlockType(c.anchor.blockId,r("paragraph")).setSelection(c).build();return e.dispatch(t),!0}const l={listType:n,indent:t(o,"list_item")?o.attrs.indent:0};"checklist"===n&&(l.checked=!1);const a=s.transaction("command").setBlockType(c.anchor.blockId,r("list_item"),l).setSelection(c).build();return e.dispatch(a),!0}indent(e){const n=e.getState();if(!i(n.selection))return!1;const s=n.getBlock(n.selection.anchor.blockId);return!(!s||!t(s,"list_item"))&&!(s.attrs.indent>=this.config.maxIndent)&&this.setIndent(e,n,s.attrs.indent+1)}outdent(e){const n=e.getState();if(!i(n.selection))return!1;const s=n.getBlock(n.selection.anchor.blockId);return!(!s||!t(s,"list_item"))&&!(s.attrs.indent<=0)&&this.setIndent(e,n,s.attrs.indent-1)}setIndent(t,e,n){const s=e.selection;if(!i(s))return!1;const c=e.getBlock(s.anchor.blockId);if(!c)return!1;const o={...c.attrs,indent:n},l=e.transaction("command").setBlockType(s.anchor.blockId,r("list_item"),o).setSelection(s).build();return t.dispatch(l),!0}toggleChecked(t,e){if(t.isReadOnly()&&!this.config.interactiveCheckboxes)return!1;const n=t.getState(),s=e??(i(n.selection)?n.selection.anchor.blockId:null);if(!s)return!1;const c=n.getBlock(s);if(!c||"list_item"!==c.type||"checklist"!==c.attrs?.listType)return!1;const o=!c.attrs?.checked,l={...c.attrs,checked:o},a=n.transaction("command").setBlockType(s,r("list_item"),l).setSelection(n.selection).build();return t.dispatch(a),!0}handleBackspace(t){const e=t.getState(),n=e.selection;if(!i(n))return!1;if(!s(n))return!1;const c=e.getBlock(n.anchor.blockId);if(!c||"list_item"!==c.type)return!1;if(0!==n.anchor.offset)return!1;const o=e.transaction("input").setBlockType(n.anchor.blockId,r("paragraph")).setSelection(n).build();return t.dispatch(o),!0}handleEnter(o){const l=o.getState(),a=l.selection;if(!i(a))return!1;if(!s(a))return!1;const d=l.getBlock(a.anchor.blockId);if(!d||"list_item"!==d.type)return!1;if(""===e(d)){const t=l.transaction("input").setBlockType(a.anchor.blockId,r("paragraph")).setSelection(a).build();return o.dispatch(t),!0}const h=n(),u={listType:t(d,"list_item")?d.attrs.listType:"bullet",indent:t(d,"list_item")?d.attrs.indent:0};"checklist"===u.listType&&(u.checked=!1);const p=l.transaction("input").splitBlock(a.anchor.blockId,a.anchor.offset,h).setBlockType(h,r("list_item"),u).setSelection(c(h,0)).build();return o.dispatch(p),!0}registerCheckboxClickHandler(t){this.config.types.includes("checklist")&&(this.checkboxClickHandler=e=>{if(t.isReadOnly()&&!this.config.interactiveCheckboxes)return;const n=e.target;if(!(n instanceof HTMLElement))return;const i=n.closest(".notectl-list-item--checklist");if(!i)return;const s=i.getBoundingClientRect();if(("rtl"===getComputedStyle(i).direction?s.right-e.clientX:e.clientX-s.left)>=24)return;e.preventDefault();const c=i.getAttribute("data-block-id");c&&this.toggleChecked(t,o(c))},t.getContainer().addEventListener("mousedown",this.checkboxClickHandler))}isListActive(t,e){if(!i(t.selection))return!1;const n=t.getBlock(t.selection.anchor.blockId);return"list_item"===n?.type&&n.attrs?.listType===e}getEnabledTypes(){return k.filter(t=>this.config.types.includes(t.type))}}export{h as LIST_LOCALE_EN,g as ListPlugin,p as loadListLocale};
2
2
  //# sourceMappingURL=list.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"list.mjs","sources":["../../src/editor/styles/list.ts","../../src/plugins/list/ListLocale.ts","../../src/plugins/list/ListPlugin.ts"],"sourcesContent":["/** Width of the list marker / checkbox area in pixels. */\nexport const LIST_MARKER_WIDTH = 24;\n\n/** List styles — bullet, ordered, checklist items. */\nexport const LIST_CSS = `\n/* List Wrappers — suppress native markers, we use ::before pseudo-elements */\n.notectl-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Ordered List — each <ol> wrapper resets the counter */\n.notectl-list--ordered {\n\tcounter-reset: notectl-ordered;\n}\n\n/* List Items */\n.notectl-list-item {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: ${LIST_MARKER_WIDTH}px;\n\tmin-height: 1.6em;\n\tposition: relative;\n}\n\n.notectl-list-item::before {\n\tposition: absolute;\n\tinset-inline-start: 0;\n\tdisplay: inline-block;\n\twidth: ${LIST_MARKER_WIDTH}px;\n\ttext-align: center;\n}\n\n/* Bullet List */\n.notectl-list-item--bullet::before {\n\tcontent: '\\\\2022';\n\tcolor: var(--notectl-fg);\n}\n\n/* Ordered List — counter increment per item */\n.notectl-list-item--ordered {\n\tcounter-increment: notectl-ordered;\n}\n\n.notectl-list-item--ordered::before {\n\tcontent: counter(notectl-ordered) '.';\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n}\n\n/* Checklist */\n.notectl-list-item--checklist::before {\n\tcontent: '\\\\2610';\n\tfont-size: 16px;\n\tcolor: var(--notectl-fg-muted);\n\tcursor: pointer;\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"]::before {\n\tcontent: '\\\\2611';\n\tcolor: var(--notectl-success);\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"] {\n\tcolor: var(--notectl-fg-muted);\n\ttext-decoration: line-through;\n}\n`;\n","/**\n * Locale interface and default English locale for the ListPlugin.\n */\n\n// --- Locale Interface ---\n\nexport interface ListLocale {\n\treadonly bulletList: string;\n\treadonly numberedList: string;\n\treadonly checklist: string;\n}\n\n// --- Default English Locale ---\n\nexport const LIST_LOCALE_EN: ListLocale = {\n\tbulletList: 'Bullet List',\n\tnumberedList: 'Numbered List',\n\tchecklist: 'Checklist',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: ListLocale }>> = import.meta.glob<{\n\tdefault: ListLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadListLocale(lang: string): Promise<ListLocale> {\n\tif (lang === 'en') return LIST_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return LIST_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn LIST_LOCALE_EN;\n\t}\n}\n","/**\n * ListPlugin: registers ordered, unordered, and checklist block types\n * with NodeSpecs, toggle commands, indent/outdent (Tab/Shift-Tab),\n * input rules, and toolbar buttons.\n *\n * List items are modeled as flat blocks with a `listType` and `indent` attribute,\n * allowing simple nesting representation without deep tree structures.\n */\n\nimport { LIST_CSS, LIST_MARKER_WIDTH } from '../../editor/styles/list.js';\nimport { LocaleServiceKey } from '../../i18n/LocaleService.js';\nimport { isNodeOfType } from '../../model/AttrRegistry.js';\nimport { generateBlockId, getBlockText } from '../../model/Document.js';\nimport {\n\tcreateCollapsedSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../../model/Selection.js';\nimport { type BlockId, blockId, nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport { setStyleProperty } from '../../style/StyleRuntime.js';\nimport { createBlockElement } from '../../view/DomUtils.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { LIST_LOCALE_EN, type ListLocale, loadListLocale } from './ListLocale.js';\n\n// --- Attribute Registry Augmentation ---\n\nexport type ListType = 'bullet' | 'ordered' | 'checklist';\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tlist_item: { listType: ListType; indent: number; checked: boolean };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface ListConfig {\n\t/** Which list types to enable. Defaults to all. */\n\treadonly types: readonly ListType[];\n\t/** Maximum indent depth. Defaults to 4. */\n\treadonly maxIndent: number;\n\t/**\n\t * When true, checklist checkboxes remain interactive even in read-only mode.\n\t * Defaults to false (checkboxes are fully read-only).\n\t */\n\treadonly interactiveCheckboxes?: boolean;\n\treadonly locale?: ListLocale;\n}\n\nconst DEFAULT_CONFIG: ListConfig = {\n\ttypes: ['bullet', 'ordered', 'checklist'],\n\tmaxIndent: 4,\n};\n\n// --- List Type Metadata ---\n\ninterface ListTypeDefinition {\n\treadonly type: ListType;\n\treadonly icon: string;\n\treadonly inputPattern: RegExp;\n\treadonly inputPrefix: string;\n}\n\nconst BULLET_LIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z\"/></svg>';\nconst NUMBERED_LIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z\"/></svg>';\nconst CHECKLIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M22 7h-9v2h9V7zm0 8h-9v2h9v-2zM5.54 11L2 7.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 11zm0 8L2 15.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 19z\"/></svg>';\n\nconst LIST_TYPE_DEFINITIONS: readonly ListTypeDefinition[] = [\n\t{\n\t\ttype: 'bullet',\n\t\ticon: BULLET_LIST_ICON,\n\t\tinputPattern: /^[-*] $/,\n\t\tinputPrefix: '- ',\n\t},\n\t{\n\t\ttype: 'ordered',\n\t\ticon: NUMBERED_LIST_ICON,\n\t\tinputPattern: /^\\d+\\. $/,\n\t\tinputPrefix: '1. ',\n\t},\n\t{\n\t\ttype: 'checklist',\n\t\ticon: CHECKLIST_ICON,\n\t\tinputPattern: /^\\[[ x]] $/,\n\t\tinputPrefix: '[ ] ',\n\t},\n];\n\n// --- Plugin ---\n\nexport class ListPlugin implements Plugin {\n\treadonly id = 'list';\n\treadonly name = 'List';\n\treadonly priority = 35;\n\n\tprivate readonly config: ListConfig;\n\tprivate locale!: ListLocale;\n\tprivate context: PluginContext | null = null;\n\tprivate checkboxClickHandler: ((e: MouseEvent) => void) | null = null;\n\n\tconstructor(config?: Partial<ListConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.context = context;\n\t\tif (this.config.locale) {\n\t\t\tthis.locale = this.config.locale;\n\t\t} else {\n\t\t\tconst service = context.getService(LocaleServiceKey);\n\t\t\tconst lang: string = service?.getLocale() ?? 'en';\n\t\t\tthis.locale = lang === 'en' ? LIST_LOCALE_EN : await loadListLocale(lang);\n\t\t}\n\t\tcontext.registerStyleSheet(LIST_CSS);\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerInputRules(context);\n\t\tthis.registerToolbarItems(context);\n\t\tthis.registerCheckboxClickHandler(context);\n\t}\n\n\tdestroy(): void {\n\t\tif (this.checkboxClickHandler && this.context) {\n\t\t\tconst container: HTMLElement = this.context.getContainer();\n\t\t\tcontainer.removeEventListener('mousedown', this.checkboxClickHandler);\n\t\t}\n\t\tthis.checkboxClickHandler = null;\n\t\tthis.context = null;\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'list_item',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\tattrs: {\n\t\t\t\tlistType: { default: 'bullet' },\n\t\t\t\tindent: { default: 0 },\n\t\t\t\tchecked: { default: false },\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst listType = node.attrs?.listType ?? 'bullet';\n\t\t\t\tconst indent = node.attrs?.indent ?? 0;\n\t\t\t\tconst checked = node.attrs?.checked ?? false;\n\n\t\t\t\tconst li = createBlockElement('li', node.id);\n\t\t\t\tli.setAttribute('role', 'listitem');\n\t\t\t\tli.setAttribute('data-list-type', listType);\n\t\t\t\tli.setAttribute('data-indent', String(indent));\n\t\t\t\tli.className = `notectl-list-item notectl-list-item--${listType}`;\n\n\t\t\t\tif (indent > 0) {\n\t\t\t\t\tsetStyleProperty(li, 'marginLeft', `${indent * LIST_MARKER_WIDTH}px`);\n\t\t\t\t}\n\n\t\t\t\tif (listType === 'checklist') {\n\t\t\t\t\tli.setAttribute('data-checked', String(checked));\n\t\t\t\t\tli.setAttribute('aria-checked', String(checked));\n\t\t\t\t}\n\t\t\t\tli.setAttribute('aria-level', String(indent + 1));\n\n\t\t\t\treturn li;\n\t\t\t},\n\t\t\twrapper(node) {\n\t\t\t\tconst listType = node.attrs?.listType ?? 'bullet';\n\t\t\t\tconst tag = listType === 'ordered' ? 'ol' : 'ul';\n\t\t\t\treturn {\n\t\t\t\t\ttag,\n\t\t\t\t\tkey: `list-${listType}`,\n\t\t\t\t\tclassName: `notectl-list notectl-list--${listType}`,\n\t\t\t\t\tattrs: { role: 'list' },\n\t\t\t\t};\n\t\t\t},\n\t\t\ttoHTML(node, content) {\n\t\t\t\tconst listType: string = (node.attrs?.listType as string) ?? 'bullet';\n\t\t\t\tconst checked: boolean = (node.attrs?.checked as boolean) ?? false;\n\n\t\t\t\tif (listType === 'checklist') {\n\t\t\t\t\tconst checkedAttr: string = checked ? ' checked' : '';\n\t\t\t\t\tconst ariaChecked: string = String(checked);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t`<li role=\"checkbox\" aria-checked=\"${ariaChecked}\">` +\n\t\t\t\t\t\t`<input type=\"checkbox\" disabled${checkedAttr}>` +\n\t\t\t\t\t\t`${content || '<br>'}</li>`\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn `<li>${content || '<br>'}</li>`;\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'li' }],\n\t\t\tsanitize: {\n\t\t\t\ttags: ['ul', 'ol', 'li', 'input'],\n\t\t\t\tattrs: ['type', 'disabled', 'checked', 'role', 'aria-checked'],\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerCommand(`toggleList:${def.type}`, () => {\n\t\t\t\treturn this.toggleList(context, def.type);\n\t\t\t});\n\t\t}\n\n\t\tcontext.registerCommand('indentListItem', () => {\n\t\t\treturn this.indent(context);\n\t\t});\n\n\t\tcontext.registerCommand('outdentListItem', () => {\n\t\t\treturn this.outdent(context);\n\t\t});\n\n\t\tif (this.config.types.includes('checklist')) {\n\t\t\tcontext.registerCommand('toggleChecklistItem', () => this.toggleChecked(context), {\n\t\t\t\treadonlyAllowed: true,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\tEnter: () => this.handleEnter(context),\n\t\t\tBackspace: () => this.handleBackspace(context),\n\t\t\tTab: () => this.indent(context),\n\t\t\t'Shift-Tab': () => this.outdent(context),\n\t\t});\n\t}\n\n\tprivate registerInputRules(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerInputRule({\n\t\t\t\tpattern: def.inputPattern,\n\t\t\t\thandler: (state, match, start, _end) => {\n\t\t\t\t\tconst sel = state.selection;\n\t\t\t\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return null;\n\t\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\t\tconst matchStr = match[0] ?? '';\n\t\t\t\t\tconst matchLen = matchStr.length;\n\t\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t\tlistType: def.type,\n\t\t\t\t\t\tindent: 0,\n\t\t\t\t\t};\n\t\t\t\t\tif (def.type === 'checklist') {\n\t\t\t\t\t\tattrs.checked = matchStr.includes('[x]');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn state\n\t\t\t\t\t\t.transaction('input')\n\t\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + matchLen)\n\t\t\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, 0))\n\t\t\t\t\t\t.build();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate getListLabel(type: ListType): string {\n\t\tconst labels: Record<ListType, string> = {\n\t\t\tbullet: this.locale.bulletList,\n\t\t\tordered: this.locale.numberedList,\n\t\t\tchecklist: this.locale.checklist,\n\t\t};\n\t\treturn labels[type];\n\t}\n\n\tprivate registerToolbarItems(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: `list-${def.type}`,\n\t\t\t\tgroup: 'block',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel: this.getListLabel(def.type),\n\t\t\t\tcommand: `toggleList:${def.type}`,\n\t\t\t\tisActive: (state) => this.isListActive(state, def.type),\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Command Implementations ---\n\n\tprivate toggleList(context: PluginContext, listType: ListType): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\t// If already this list type, convert back to paragraph\n\t\tif (block.type === 'list_item' && block.attrs?.listType === listType) {\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Convert to list item\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlistType,\n\t\t\tindent: isNodeOfType(block, 'list_item') ? block.attrs.indent : 0,\n\t\t};\n\t\tif (listType === 'checklist') {\n\t\t\tattrs.checked = false;\n\t\t}\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate indent(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (isNodeSelection(state.selection) || isGapCursor(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || !isNodeOfType(block, 'list_item')) return false;\n\n\t\tif (block.attrs.indent >= this.config.maxIndent) return false;\n\n\t\treturn this.setIndent(context, state, block.attrs.indent + 1);\n\t}\n\n\tprivate outdent(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (isNodeSelection(state.selection) || isGapCursor(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || !isNodeOfType(block, 'list_item')) return false;\n\n\t\tif (block.attrs.indent <= 0) return false;\n\n\t\treturn this.setIndent(context, state, block.attrs.indent - 1);\n\t}\n\n\tprivate setIndent(context: PluginContext, state: EditorState, indent: number): boolean {\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tconst attrs = { ...block.attrs, indent } as Record<string, string | number | boolean>;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate toggleChecked(context: PluginContext, targetId?: BlockId): boolean {\n\t\tif (context.isReadOnly() && !this.config.interactiveCheckboxes) return false;\n\n\t\tconst state = context.getState();\n\t\tconst bid: BlockId | null =\n\t\t\ttargetId ??\n\t\t\t(isNodeSelection(state.selection) || isGapCursor(state.selection)\n\t\t\t\t? null\n\t\t\t\t: state.selection.anchor.blockId);\n\t\tif (!bid) return false;\n\n\t\tconst block = state.getBlock(bid);\n\t\tif (!block || block.type !== 'list_item' || block.attrs?.listType !== 'checklist') {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst checked: boolean = !block.attrs?.checked;\n\t\tconst attrs = { ...block.attrs, checked } as Record<string, string | number | boolean>;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(bid, nodeType('list_item'), attrs)\n\t\t\t.setSelection(state.selection)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles Backspace at the start of a list item.\n\t * Converts the list item back to a paragraph, preserving text.\n\t */\n\tprivate handleBackspace(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item') return false;\n\t\tif (sel.anchor.offset !== 0) return false;\n\n\t\tconst tr = state\n\t\t\t.transaction('input')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles Enter inside a list item.\n\t * Empty item → exit list (convert to paragraph).\n\t * Non-empty item → split and create a new list item with the same type.\n\t */\n\tprivate handleEnter(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (isNodeSelection(sel) || isGapCursor(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item') return false;\n\n\t\tconst text = getBlockText(block);\n\n\t\tif (text === '') {\n\t\t\t// Empty list item → convert to paragraph (exit list)\n\t\t\tconst tr = state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Non-empty → split block and set new block to same list type\n\t\tconst newBlockId = generateBlockId();\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlistType: isNodeOfType(block, 'list_item') ? block.attrs.listType : 'bullet',\n\t\t\tindent: isNodeOfType(block, 'list_item') ? block.attrs.indent : 0,\n\t\t};\n\t\tif (attrs.listType === 'checklist') {\n\t\t\tattrs.checked = false;\n\t\t}\n\n\t\tconst tr = state\n\t\t\t.transaction('input')\n\t\t\t.splitBlock(sel.anchor.blockId, sel.anchor.offset, newBlockId)\n\t\t\t.setBlockType(newBlockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(createCollapsedSelection(newBlockId, 0))\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t// --- Checkbox Click Handling ---\n\n\tprivate registerCheckboxClickHandler(context: PluginContext): void {\n\t\tif (!this.config.types.includes('checklist')) return;\n\n\t\tthis.checkboxClickHandler = (e: MouseEvent) => {\n\t\t\tif (context.isReadOnly() && !this.config.interactiveCheckboxes) return;\n\n\t\t\tconst target: EventTarget | null = e.target;\n\t\t\tif (!(target instanceof HTMLElement)) return;\n\n\t\t\tconst li: HTMLElement | null = target.closest('.notectl-list-item--checklist');\n\t\t\tif (!li) return;\n\n\t\t\tconst rect: DOMRect = li.getBoundingClientRect();\n\t\t\tconst isRtl: boolean = getComputedStyle(li).direction === 'rtl';\n\t\t\tconst markerDistance: number = isRtl ? rect.right - e.clientX : e.clientX - rect.left;\n\t\t\tif (markerDistance >= LIST_MARKER_WIDTH) return;\n\n\t\t\te.preventDefault();\n\n\t\t\tconst bid: string | null = li.getAttribute('data-block-id');\n\t\t\tif (!bid) return;\n\n\t\t\tthis.toggleChecked(context, blockId(bid));\n\t\t};\n\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tcontainer.addEventListener('mousedown', this.checkboxClickHandler);\n\t}\n\n\t// --- Helpers ---\n\n\tprivate isListActive(state: EditorState, listType: ListType): boolean {\n\t\tif (isNodeSelection(state.selection) || isGapCursor(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\treturn block?.type === 'list_item' && block.attrs?.listType === listType;\n\t}\n\n\tprivate getEnabledTypes(): readonly ListTypeDefinition[] {\n\t\treturn LIST_TYPE_DEFINITIONS.filter((def) => this.config.types.includes(def.type));\n\t}\n}\n"],"names":["LIST_LOCALE_EN","bulletList","numberedList","checklist","localeModules","assign","import","async","loadListLocale","lang","loader","default","DEFAULT_CONFIG","types","maxIndent","LIST_TYPE_DEFINITIONS","type","icon","inputPattern","inputPrefix","ListPlugin","id","name","priority","config","locale","context","checkboxClickHandler","constructor","this","init","service","getService","LocaleServiceKey","getLocale","registerStyleSheet","registerNodeSpec","registerCommands","registerKeymaps","registerInputRules","registerToolbarItems","registerCheckboxClickHandler","destroy","getContainer","removeEventListener","group","content","allow","attrs","listType","indent","checked","toDOM","node","li","createBlockElement","setAttribute","String","className","setStyleProperty","wrapper","tag","key","role","toHTML","checkedAttr","parseHTML","sanitize","tags","enabledTypes","getEnabledTypes","def","registerCommand","toggleList","outdent","includes","toggleChecked","readonlyAllowed","registerKeymap","Enter","handleEnter","Backspace","handleBackspace","Tab","registerInputRule","pattern","handler","state","match","start","_end","sel","selection","isNodeSelection","isGapCursor","isCollapsed","block","getBlock","anchor","blockId","matchStr","matchLen","length","transaction","deleteTextAt","setBlockType","nodeType","setSelection","createCollapsedSelection","build","getListLabel","bullet","ordered","registerToolbarItem","label","command","isActive","isListActive","getState","tr","dispatch","isNodeOfType","setIndent","targetId","isReadOnly","interactiveCheckboxes","bid","offset","getBlockText","newBlockId","generateBlockId","splitBlock","e","target","HTMLElement","closest","rect","getBoundingClientRect","getComputedStyle","direction","right","clientX","left","preventDefault","getAttribute","addEventListener","filter"],"mappings":"+ZACO,MCaMA,EAA6B,CACzCC,WAAY,cACZC,aAAc,gBACdC,UAAW,aAKNC,wBAAwEC,OAAA,CAAA,kBAAA,IAAAC,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,6BAAA,kBAAA,IAAAA,OAAA,+BAI9EC,eAAsBC,EAAeC,GACpC,GAAa,OAATA,EAAe,OAAOT,EAC1B,MAAMU,EAASN,EAAc,aAAaK,QAC1C,IAAKC,EAAQ,OAAOV,EACpB,IAEC,aADkBU,KACPC,OACZ,CAAA,MACC,OAAOX,CACR,CACD,CCeA,MAAMY,EAA6B,CAClCC,MAAO,CAAC,SAAU,UAAW,aAC7BC,UAAW,GAmBNC,EAAuD,CAC5D,CACCC,KAAM,SACNC,KATD,gWAUCC,aAAc,UACdC,YAAa,MAEd,CACCH,KAAM,UACNC,KAbD,2NAcCC,aAAc,WACdC,YAAa,OAEd,CACCH,KAAM,YACNC,KAjBD,4OAkBCC,aAAc,aACdC,YAAa,SAMR,MAAMC,EACHC,GAAK,OACLC,KAAO,OACPC,SAAW,GAEHC,OACTC,OACAC,QAAgC,KAChCC,qBAAyD,KAEjE,WAAAC,CAAYJ,GACXK,KAAKL,OAAS,IAAKZ,KAAmBY,EACvC,CAEA,UAAMM,CAAKJ,GAEV,GADAG,KAAKH,QAAUA,EACXG,KAAKL,OAAOC,OACfI,KAAKJ,OAASI,KAAKL,OAAOC,WACpB,CACN,MAAMM,EAAUL,EAAQM,WAAWC,GAC7BxB,EAAesB,GAASG,aAAe,KAC7CL,KAAKJ,OAAkB,OAAThB,EAAgBT,QAAuBQ,EAAeC,EACrE,CACAiB,EAAQS,mBFlHc,21CEmHtBN,KAAKO,iBAAiBV,GACtBG,KAAKQ,iBAAiBX,GACtBG,KAAKS,gBAAgBZ,GACrBG,KAAKU,mBAAmBb,GACxBG,KAAKW,qBAAqBd,GAC1BG,KAAKY,6BAA6Bf,EACnC,CAEA,OAAAgB,GACKb,KAAKF,sBAAwBE,KAAKH,SACNG,KAAKH,QAAQiB,eAClCC,oBAAoB,YAAaf,KAAKF,sBAEjDE,KAAKF,qBAAuB,KAC5BE,KAAKH,QAAU,IAChB,CAEQ,gBAAAU,CAAiBV,GACxBA,EAAQU,iBAAiB,CACxBpB,KAAM,YACN6B,MAAO,QACPC,QAAS,CAAEC,MAAO,CAAC,SACnBC,MAAO,CACNC,SAAU,CAAEtC,QAAS,UACrBuC,OAAQ,CAAEvC,QAAS,GACnBwC,QAAS,CAAExC,SAAS,IAErB,KAAAyC,CAAMC,GACL,MAAMJ,EAAWI,EAAKL,OAAOC,UAAY,SACnCC,EAASG,EAAKL,OAAOE,QAAU,EAC/BC,EAAUE,EAAKL,OAAOG,UAAW,EAEjCG,EAAKC,EAAmB,KAAMF,EAAKhC,IAgBzC,OAfAiC,EAAGE,aAAa,OAAQ,YACxBF,EAAGE,aAAa,iBAAkBP,GAClCK,EAAGE,aAAa,cAAeC,OAAOP,IACtCI,EAAGI,UAAY,wCAAwCT,IAEnDC,EAAS,GACZS,EAAiBL,EAAI,aF7JO,GE6JUJ,EAAH,MAGnB,cAAbD,IACHK,EAAGE,aAAa,eAAgBC,OAAON,IACvCG,EAAGE,aAAa,eAAgBC,OAAON,KAExCG,EAAGE,aAAa,aAAcC,OAAOP,EAAS,IAEvCI,CACR,EACA,OAAAM,CAAQP,GACP,MAAMJ,EAAWI,EAAKL,OAAOC,UAAY,SAEzC,MAAO,CACNY,IAFwB,YAAbZ,EAAyB,KAAO,KAG3Ca,IAAK,QAAQb,IACbS,UAAW,8BAA8BT,IACzCD,MAAO,CAAEe,KAAM,QAEjB,EACA,MAAAC,CAAOX,EAAMP,GACZ,MAAMG,EAAoBI,EAAKL,OAAOC,UAAuB,SACvDE,EAAoBE,EAAKL,OAAOG,UAAuB,EAE7D,GAAiB,cAAbF,EAA0B,CAC7B,MAAMgB,EAAsBd,EAAU,WAAa,GAEnD,MACC,qCAF2BM,OAAON,sCAGAc,KAC/BnB,GAAW,aAEhB,CAEA,MAAO,OAAOA,GAAW,aAC1B,EACAoB,UAAW,CAAC,CAAEL,IAAK,OACnBM,SAAU,CACTC,KAAM,CAAC,KAAM,KAAM,KAAM,SACzBpB,MAAO,CAAC,OAAQ,WAAY,UAAW,OAAQ,kBAGlD,CAEQ,gBAAAX,CAAiBX,GACxB,MAAM2C,EAAexC,KAAKyC,kBAE1B,IAAA,MAAWC,KAAOF,EACjB3C,EAAQ8C,gBAAgB,cAAcD,EAAIvD,OAAQ,IAC1Ca,KAAK4C,WAAW/C,EAAS6C,EAAIvD,OAItCU,EAAQ8C,gBAAgB,iBAAkB,IAClC3C,KAAKqB,OAAOxB,IAGpBA,EAAQ8C,gBAAgB,kBAAmB,IACnC3C,KAAK6C,QAAQhD,IAGjBG,KAAKL,OAAOX,MAAM8D,SAAS,cAC9BjD,EAAQ8C,gBAAgB,sBAAuB,IAAM3C,KAAK+C,cAAclD,GAAU,CACjFmD,iBAAiB,GAGpB,CAEQ,eAAAvC,CAAgBZ,GACvBA,EAAQoD,eAAe,CACtBC,MAAO,IAAMlD,KAAKmD,YAAYtD,GAC9BuD,UAAW,IAAMpD,KAAKqD,gBAAgBxD,GACtCyD,IAAK,IAAMtD,KAAKqB,OAAOxB,GACvB,YAAa,IAAMG,KAAK6C,QAAQhD,IAElC,CAEQ,kBAAAa,CAAmBb,GAC1B,MAAM2C,EAAexC,KAAKyC,kBAE1B,IAAA,MAAWC,KAAOF,EACjB3C,EAAQ0D,kBAAkB,CACzBC,QAASd,EAAIrD,aACboE,QAAS,CAACC,EAAOC,EAAOC,EAAOC,KAC9B,MAAMC,EAAMJ,EAAMK,UAClB,GAAIC,EAAgBF,IAAQG,EAAYH,GAAM,OAAO,KACrD,IAAKI,EAAYJ,GAAM,OAAO,KAE9B,MAAMK,EAAQT,EAAMU,SAASN,EAAIO,OAAOC,SACxC,IAAKH,GAAwB,cAAfA,EAAMhF,KAAsB,OAAO,KAEjD,MAAMoF,EAAWZ,EAAM,IAAM,GACvBa,EAAWD,EAASE,OACpBtD,EAAmD,CACxDC,SAAUsB,EAAIvD,KACdkC,OAAQ,GAMT,MAJiB,cAAbqB,EAAIvD,OACPgC,EAAMG,QAAUiD,EAASzB,SAAS,QAG5BY,EACLgB,YAAY,SACZC,aAAab,EAAIO,OAAOC,QAASV,EAAOA,EAAQY,GAChDI,aAAad,EAAIO,OAAOC,QAASO,EAAS,aAAc1D,GACxD2D,aAAaC,EAAyBjB,EAAIO,OAAOC,QAAS,IAC1DU,UAIN,CAEQ,YAAAC,CAAa9F,GAMpB,MALyC,CACxC+F,OAAQlF,KAAKJ,OAAOxB,WACpB+G,QAASnF,KAAKJ,OAAOvB,aACrBC,UAAW0B,KAAKJ,OAAOtB,WAEVa,EACf,CAEQ,oBAAAwB,CAAqBd,GAC5B,MAAM2C,EAAexC,KAAKyC,kBAE1B,IAAA,MAAWC,KAAOF,EACjB3C,EAAQuF,oBAAoB,CAC3B5F,GAAI,QAAQkD,EAAIvD,OAChB6B,MAAO,QACP5B,KAAMsD,EAAItD,KACViG,MAAOrF,KAAKiF,aAAavC,EAAIvD,MAC7BmG,QAAS,cAAc5C,EAAIvD,OAC3BoG,SAAW7B,GAAU1D,KAAKwF,aAAa9B,EAAOhB,EAAIvD,OAGrD,CAIQ,UAAAyD,CAAW/C,EAAwBuB,GAC1C,MAAMsC,EAAQ7D,EAAQ4F,WAChB3B,EAAMJ,EAAMK,UAClB,GAAIC,EAAgBF,IAAQG,EAAYH,GAAM,OAAO,EACrD,MAAMK,EAAQT,EAAMU,SAASN,EAAIO,OAAOC,SACxC,IAAKH,EAAO,OAAO,EAGnB,GAAmB,cAAfA,EAAMhF,MAAwBgF,EAAMhD,OAAOC,WAAaA,EAAU,CACrE,MAAMsE,EAAKhC,EACTgB,YAAY,WACZE,aAAad,EAAIO,OAAOC,QAASO,EAAS,cAC1CC,aAAahB,GACbkB,QAEF,OADAnF,EAAQ8F,SAASD,IACV,CACR,CAGA,MAAMvE,EAAmD,CACxDC,WACAC,OAAQuE,EAAazB,EAAO,aAAeA,EAAMhD,MAAME,OAAS,GAEhD,cAAbD,IACHD,EAAMG,SAAU,GAGjB,MAAMoE,EAAKhC,EACTgB,YAAY,WACZE,aAAad,EAAIO,OAAOC,QAASO,EAAS,aAAc1D,GACxD2D,aAAahB,GACbkB,QAEF,OADAnF,EAAQ8F,SAASD,IACV,CACR,CAEQ,MAAArE,CAAOxB,GACd,MAAM6D,EAAQ7D,EAAQ4F,WACtB,GAAIzB,EAAgBN,EAAMK,YAAcE,EAAYP,EAAMK,WAAY,OAAO,EAC7E,MAAMI,EAAQT,EAAMU,SAASV,EAAMK,UAAUM,OAAOC,SACpD,SAAKH,IAAUyB,EAAazB,EAAO,iBAE/BA,EAAMhD,MAAME,QAAUrB,KAAKL,OAAOV,YAE/Be,KAAK6F,UAAUhG,EAAS6D,EAAOS,EAAMhD,MAAME,OAAS,EAC5D,CAEQ,OAAAwB,CAAQhD,GACf,MAAM6D,EAAQ7D,EAAQ4F,WACtB,GAAIzB,EAAgBN,EAAMK,YAAcE,EAAYP,EAAMK,WAAY,OAAO,EAC7E,MAAMI,EAAQT,EAAMU,SAASV,EAAMK,UAAUM,OAAOC,SACpD,SAAKH,IAAUyB,EAAazB,EAAO,iBAE/BA,EAAMhD,MAAME,QAAU,IAEnBrB,KAAK6F,UAAUhG,EAAS6D,EAAOS,EAAMhD,MAAME,OAAS,EAC5D,CAEQ,SAAAwE,CAAUhG,EAAwB6D,EAAoBrC,GAC7D,MAAMyC,EAAMJ,EAAMK,UAClB,GAAIC,EAAgBF,IAAQG,EAAYH,GAAM,OAAO,EACrD,MAAMK,EAAQT,EAAMU,SAASN,EAAIO,OAAOC,SACxC,IAAKH,EAAO,OAAO,EAEnB,MAAMhD,EAAQ,IAAKgD,EAAMhD,MAAOE,UAE1BqE,EAAKhC,EACTgB,YAAY,WACZE,aAAad,EAAIO,OAAOC,QAASO,EAAS,aAAc1D,GACxD2D,aAAahB,GACbkB,QAEF,OADAnF,EAAQ8F,SAASD,IACV,CACR,CAEQ,aAAA3C,CAAclD,EAAwBiG,GAC7C,GAAIjG,EAAQkG,eAAiB/F,KAAKL,OAAOqG,sBAAuB,OAAO,EAEvE,MAAMtC,EAAQ7D,EAAQ4F,WAChBQ,EACLH,IACC9B,EAAgBN,EAAMK,YAAcE,EAAYP,EAAMK,WACpD,KACAL,EAAMK,UAAUM,OAAOC,SAC3B,IAAK2B,EAAK,OAAO,EAEjB,MAAM9B,EAAQT,EAAMU,SAAS6B,GAC7B,IAAK9B,GAAwB,cAAfA,EAAMhF,MAAkD,cAA1BgF,EAAMhD,OAAOC,SACxD,OAAO,EAGR,MAAME,GAAoB6C,EAAMhD,OAAOG,QACjCH,EAAQ,IAAKgD,EAAMhD,MAAOG,WAE1BoE,EAAKhC,EACTgB,YAAY,WACZE,aAAaqB,EAAKpB,EAAS,aAAc1D,GACzC2D,aAAapB,EAAMK,WACnBiB,QAEF,OADAnF,EAAQ8F,SAASD,IACV,CACR,CAMQ,eAAArC,CAAgBxD,GACvB,MAAM6D,EAAQ7D,EAAQ4F,WAChB3B,EAAMJ,EAAMK,UAClB,GAAIC,EAAgBF,IAAQG,EAAYH,GAAM,OAAO,EACrD,IAAKI,EAAYJ,GAAM,OAAO,EAE9B,MAAMK,EAAQT,EAAMU,SAASN,EAAIO,OAAOC,SACxC,IAAKH,GAAwB,cAAfA,EAAMhF,KAAsB,OAAO,EACjD,GAA0B,IAAtB2E,EAAIO,OAAO6B,OAAc,OAAO,EAEpC,MAAMR,EAAKhC,EACTgB,YAAY,SACZE,aAAad,EAAIO,OAAOC,QAASO,EAAS,cAC1CC,aAAahB,GACbkB,QAEF,OADAnF,EAAQ8F,SAASD,IACV,CACR,CAOQ,WAAAvC,CAAYtD,GACnB,MAAM6D,EAAQ7D,EAAQ4F,WAChB3B,EAAMJ,EAAMK,UAClB,GAAIC,EAAgBF,IAAQG,EAAYH,GAAM,OAAO,EACrD,IAAKI,EAAYJ,GAAM,OAAO,EAE9B,MAAMK,EAAQT,EAAMU,SAASN,EAAIO,OAAOC,SACxC,IAAKH,GAAwB,cAAfA,EAAMhF,KAAsB,OAAO,EAIjD,GAAa,KAFAgH,EAAahC,GAET,CAEhB,MAAMuB,EAAKhC,EACTgB,YAAY,SACZE,aAAad,EAAIO,OAAOC,QAASO,EAAS,cAC1CC,aAAahB,GACbkB,QAEF,OADAnF,EAAQ8F,SAASD,IACV,CACR,CAGA,MAAMU,EAAaC,IACblF,EAAmD,CACxDC,SAAUwE,EAAazB,EAAO,aAAeA,EAAMhD,MAAMC,SAAW,SACpEC,OAAQuE,EAAazB,EAAO,aAAeA,EAAMhD,MAAME,OAAS,GAE1C,cAAnBF,EAAMC,WACTD,EAAMG,SAAU,GAGjB,MAAMoE,EAAKhC,EACTgB,YAAY,SACZ4B,WAAWxC,EAAIO,OAAOC,QAASR,EAAIO,OAAO6B,OAAQE,GAClDxB,aAAawB,EAAYvB,EAAS,aAAc1D,GAChD2D,aAAaC,EAAyBqB,EAAY,IAClDpB,QAEF,OADAnF,EAAQ8F,SAASD,IACV,CACR,CAIQ,4BAAA9E,CAA6Bf,GAC/BG,KAAKL,OAAOX,MAAM8D,SAAS,eAEhC9C,KAAKF,qBAAwByG,IAC5B,GAAI1G,EAAQkG,eAAiB/F,KAAKL,OAAOqG,sBAAuB,OAEhE,MAAMQ,EAA6BD,EAAEC,OACrC,KAAMA,aAAkBC,aAAc,OAEtC,MAAMhF,EAAyB+E,EAAOE,QAAQ,iCAC9C,IAAKjF,EAAI,OAET,MAAMkF,EAAgBlF,EAAGmF,wBAGzB,IAF0D,QAAnCC,iBAAiBpF,GAAIqF,UACLH,EAAKI,MAAQR,EAAES,QAAUT,EAAES,QAAUL,EAAKM,OFrenD,GEseW,OAEzCV,EAAEW,iBAEF,MAAMjB,EAAqBxE,EAAG0F,aAAa,iBACtClB,GAELjG,KAAK+C,cAAclD,EAASyE,EAAQ2B,KAGNpG,EAAQiB,eAC7BsG,iBAAiB,YAAapH,KAAKF,sBAC9C,CAIQ,YAAA0F,CAAa9B,EAAoBtC,GACxC,GAAI4C,EAAgBN,EAAMK,YAAcE,EAAYP,EAAMK,WAAY,OAAO,EAC7E,MAAMI,EAAQT,EAAMU,SAASV,EAAMK,UAAUM,OAAOC,SACpD,MAAuB,cAAhBH,GAAOhF,MAAwBgF,EAAMhD,OAAOC,WAAaA,CACjE,CAEQ,eAAAqB,GACP,OAAOvD,EAAsBmI,OAAQ3E,GAAQ1C,KAAKL,OAAOX,MAAM8D,SAASJ,EAAIvD,MAC7E"}
1
+ {"version":3,"file":"list.mjs","sources":["../../src/editor/styles/list.ts","../../src/plugins/list/ListLocale.ts","../../src/plugins/list/ListPlugin.ts"],"sourcesContent":["/** Width of the list marker / checkbox area in pixels. */\nexport const LIST_MARKER_WIDTH = 24;\n\n/** List styles — bullet, ordered, checklist items. */\nexport const LIST_CSS = `\n/* List Wrappers — suppress native markers, we use ::before pseudo-elements */\n.notectl-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Ordered List — each <ol> wrapper resets the counter */\n.notectl-list--ordered {\n\tcounter-reset: notectl-ordered;\n}\n\n/* List Items */\n.notectl-list-item {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: ${LIST_MARKER_WIDTH}px;\n\tmin-height: 1.6em;\n\tposition: relative;\n}\n\n.notectl-list-item::before {\n\tposition: absolute;\n\tinset-inline-start: 0;\n\tdisplay: inline-block;\n\twidth: ${LIST_MARKER_WIDTH}px;\n\ttext-align: center;\n}\n\n/* Bullet List */\n.notectl-list-item--bullet::before {\n\tcontent: '\\\\2022';\n\tcolor: var(--notectl-fg);\n}\n\n/* Ordered List — counter increment per item */\n.notectl-list-item--ordered {\n\tcounter-increment: notectl-ordered;\n}\n\n.notectl-list-item--ordered::before {\n\tcontent: counter(notectl-ordered) '.';\n\tcolor: var(--notectl-fg);\n\tfont-size: 14px;\n}\n\n/* Checklist */\n.notectl-list-item--checklist::before {\n\tcontent: '\\\\2610';\n\tfont-size: 16px;\n\tcolor: var(--notectl-fg-muted);\n\tcursor: pointer;\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"]::before {\n\tcontent: '\\\\2611';\n\tcolor: var(--notectl-success);\n}\n\n.notectl-list-item--checklist[data-checked=\"true\"] {\n\tcolor: var(--notectl-fg-muted);\n\ttext-decoration: line-through;\n}\n`;\n","/**\n * Locale interface and default English locale for the ListPlugin.\n */\n\n// --- Locale Interface ---\n\nexport interface ListLocale {\n\treadonly bulletList: string;\n\treadonly numberedList: string;\n\treadonly checklist: string;\n}\n\n// --- Default English Locale ---\n\nexport const LIST_LOCALE_EN: ListLocale = {\n\tbulletList: 'Bullet List',\n\tnumberedList: 'Numbered List',\n\tchecklist: 'Checklist',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: ListLocale }>> = import.meta.glob<{\n\tdefault: ListLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadListLocale(lang: string): Promise<ListLocale> {\n\tif (lang === 'en') return LIST_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return LIST_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn LIST_LOCALE_EN;\n\t}\n}\n","/**\n * ListPlugin: registers ordered, unordered, and checklist block types\n * with NodeSpecs, toggle commands, indent/outdent (Tab/Shift-Tab),\n * input rules, and toolbar buttons.\n *\n * List items are modeled as flat blocks with a `listType` and `indent` attribute,\n * allowing simple nesting representation without deep tree structures.\n */\n\nimport { LIST_CSS, LIST_MARKER_WIDTH } from '../../editor/styles/list.js';\nimport { isNodeOfType } from '../../model/AttrRegistry.js';\nimport { generateBlockId, getBlockText } from '../../model/Document.js';\nimport { createCollapsedSelection, isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport { type BlockId, blockId, nodeType } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport { setStyleProperty } from '../../style/StyleRuntime.js';\nimport { createBlockElement } from '../../view/DomUtils.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { LIST_LOCALE_EN, type ListLocale, loadListLocale } from './ListLocale.js';\n\n// --- Attribute Registry Augmentation ---\n\nexport type ListType = 'bullet' | 'ordered' | 'checklist';\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tlist_item: { listType: ListType; indent: number; checked: boolean };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface ListConfig {\n\t/** Which list types to enable. Defaults to all. */\n\treadonly types: readonly ListType[];\n\t/** Maximum indent depth. Defaults to 4. */\n\treadonly maxIndent: number;\n\t/**\n\t * When true, checklist checkboxes remain interactive even in read-only mode.\n\t * Defaults to false (checkboxes are fully read-only).\n\t */\n\treadonly interactiveCheckboxes?: boolean;\n\treadonly locale?: ListLocale;\n}\n\nconst DEFAULT_CONFIG: ListConfig = {\n\ttypes: ['bullet', 'ordered', 'checklist'],\n\tmaxIndent: 4,\n};\n\n// --- List Type Metadata ---\n\ninterface ListTypeDefinition {\n\treadonly type: ListType;\n\treadonly icon: string;\n\treadonly inputPattern: RegExp;\n\treadonly inputPrefix: string;\n}\n\nconst BULLET_LIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z\"/></svg>';\nconst NUMBERED_LIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z\"/></svg>';\nconst CHECKLIST_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M22 7h-9v2h9V7zm0 8h-9v2h9v-2zM5.54 11L2 7.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 11zm0 8L2 15.46l1.41-1.41 2.12 2.12 4.24-4.24 1.41 1.41L5.54 19z\"/></svg>';\n\nconst LIST_TYPE_DEFINITIONS: readonly ListTypeDefinition[] = [\n\t{\n\t\ttype: 'bullet',\n\t\ticon: BULLET_LIST_ICON,\n\t\tinputPattern: /^[-*] $/,\n\t\tinputPrefix: '- ',\n\t},\n\t{\n\t\ttype: 'ordered',\n\t\ticon: NUMBERED_LIST_ICON,\n\t\tinputPattern: /^\\d+\\. $/,\n\t\tinputPrefix: '1. ',\n\t},\n\t{\n\t\ttype: 'checklist',\n\t\ticon: CHECKLIST_ICON,\n\t\tinputPattern: /^\\[[ x]] $/,\n\t\tinputPrefix: '[ ] ',\n\t},\n];\n\n// --- Plugin ---\n\nexport class ListPlugin implements Plugin {\n\treadonly id = 'list';\n\treadonly name = 'List';\n\treadonly priority = 35;\n\n\tprivate readonly config: ListConfig;\n\tprivate locale!: ListLocale;\n\tprivate context: PluginContext | null = null;\n\tprivate checkboxClickHandler: ((e: MouseEvent) => void) | null = null;\n\n\tconstructor(config?: Partial<ListConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.context = context;\n\t\tthis.locale = await resolveLocale(context, this.config.locale, LIST_LOCALE_EN, loadListLocale);\n\t\tcontext.registerStyleSheet(LIST_CSS);\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerInputRules(context);\n\t\tthis.registerToolbarItems(context);\n\t\tthis.registerCheckboxClickHandler(context);\n\t}\n\n\tdestroy(): void {\n\t\tif (this.checkboxClickHandler && this.context) {\n\t\t\tconst container: HTMLElement = this.context.getContainer();\n\t\t\tcontainer.removeEventListener('mousedown', this.checkboxClickHandler);\n\t\t}\n\t\tthis.checkboxClickHandler = null;\n\t\tthis.context = null;\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'list_item',\n\t\t\tgroup: 'block',\n\t\t\tcontent: { allow: ['text'] },\n\t\t\tattrs: {\n\t\t\t\tlistType: { default: 'bullet' },\n\t\t\t\tindent: { default: 0 },\n\t\t\t\tchecked: { default: false },\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst listType = node.attrs?.listType ?? 'bullet';\n\t\t\t\tconst indent = node.attrs?.indent ?? 0;\n\t\t\t\tconst checked = node.attrs?.checked ?? false;\n\n\t\t\t\tconst li = createBlockElement('li', node.id);\n\t\t\t\tli.setAttribute('role', 'listitem');\n\t\t\t\tli.setAttribute('data-list-type', listType);\n\t\t\t\tli.setAttribute('data-indent', String(indent));\n\t\t\t\tli.className = `notectl-list-item notectl-list-item--${listType}`;\n\n\t\t\t\tif (indent > 0) {\n\t\t\t\t\tsetStyleProperty(li, 'marginLeft', `${indent * LIST_MARKER_WIDTH}px`);\n\t\t\t\t}\n\n\t\t\t\tif (listType === 'checklist') {\n\t\t\t\t\tli.setAttribute('data-checked', String(checked));\n\t\t\t\t\tli.setAttribute('aria-checked', String(checked));\n\t\t\t\t}\n\t\t\t\tli.setAttribute('aria-level', String(indent + 1));\n\n\t\t\t\treturn li;\n\t\t\t},\n\t\t\twrapper(node) {\n\t\t\t\tconst listType = node.attrs?.listType ?? 'bullet';\n\t\t\t\tconst tag = listType === 'ordered' ? 'ol' : 'ul';\n\t\t\t\treturn {\n\t\t\t\t\ttag,\n\t\t\t\t\tkey: `list-${listType}`,\n\t\t\t\t\tclassName: `notectl-list notectl-list--${listType}`,\n\t\t\t\t\tattrs: { role: 'list' },\n\t\t\t\t};\n\t\t\t},\n\t\t\ttoHTML(node, content) {\n\t\t\t\tconst listType: string = (node.attrs?.listType as string) ?? 'bullet';\n\t\t\t\tconst checked: boolean = (node.attrs?.checked as boolean) ?? false;\n\n\t\t\t\tif (listType === 'checklist') {\n\t\t\t\t\tconst checkedAttr: string = checked ? ' checked' : '';\n\t\t\t\t\tconst ariaChecked: string = String(checked);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t`<li role=\"checkbox\" aria-checked=\"${ariaChecked}\">` +\n\t\t\t\t\t\t`<input type=\"checkbox\" disabled${checkedAttr}>` +\n\t\t\t\t\t\t`${content || '<br>'}</li>`\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn `<li>${content || '<br>'}</li>`;\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'li' }],\n\t\t\tsanitize: {\n\t\t\t\ttags: ['ul', 'ol', 'li', 'input'],\n\t\t\t\tattrs: ['type', 'disabled', 'checked', 'role', 'aria-checked'],\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerCommand(`toggleList:${def.type}`, () => {\n\t\t\t\treturn this.toggleList(context, def.type);\n\t\t\t});\n\t\t}\n\n\t\tcontext.registerCommand('indentListItem', () => {\n\t\t\treturn this.indent(context);\n\t\t});\n\n\t\tcontext.registerCommand('outdentListItem', () => {\n\t\t\treturn this.outdent(context);\n\t\t});\n\n\t\tif (this.config.types.includes('checklist')) {\n\t\t\tcontext.registerCommand('toggleChecklistItem', () => this.toggleChecked(context), {\n\t\t\t\treadonlyAllowed: true,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\tEnter: () => this.handleEnter(context),\n\t\t\tBackspace: () => this.handleBackspace(context),\n\t\t\tTab: () => this.indent(context),\n\t\t\t'Shift-Tab': () => this.outdent(context),\n\t\t});\n\t}\n\n\tprivate registerInputRules(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerInputRule({\n\t\t\t\tpattern: def.inputPattern,\n\t\t\t\thandler: (state, match, start, _end) => {\n\t\t\t\t\tconst sel = state.selection;\n\t\t\t\t\tif (!isTextSelection(sel)) return null;\n\t\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\t\tconst matchStr = match[0] ?? '';\n\t\t\t\t\tconst matchLen = matchStr.length;\n\t\t\t\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\t\t\t\tlistType: def.type,\n\t\t\t\t\t\tindent: 0,\n\t\t\t\t\t};\n\t\t\t\t\tif (def.type === 'checklist') {\n\t\t\t\t\t\tattrs.checked = matchStr.includes('[x]');\n\t\t\t\t\t}\n\n\t\t\t\t\treturn state\n\t\t\t\t\t\t.transaction('input')\n\t\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + matchLen)\n\t\t\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t\t\t\t.setSelection(createCollapsedSelection(sel.anchor.blockId, 0))\n\t\t\t\t\t\t.build();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate getListLabel(type: ListType): string {\n\t\tconst labels: Record<ListType, string> = {\n\t\t\tbullet: this.locale.bulletList,\n\t\t\tordered: this.locale.numberedList,\n\t\t\tchecklist: this.locale.checklist,\n\t\t};\n\t\treturn labels[type];\n\t}\n\n\tprivate registerToolbarItems(context: PluginContext): void {\n\t\tconst enabledTypes = this.getEnabledTypes();\n\n\t\tfor (const def of enabledTypes) {\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: `list-${def.type}`,\n\t\t\t\tgroup: 'block',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel: this.getListLabel(def.type),\n\t\t\t\tcommand: `toggleList:${def.type}`,\n\t\t\t\tisActive: (state) => this.isListActive(state, def.type),\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Command Implementations ---\n\n\tprivate toggleList(context: PluginContext, listType: ListType): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\t// If already this list type, convert back to paragraph\n\t\tif (block.type === 'list_item' && block.attrs?.listType === listType) {\n\t\t\tconst tr = state\n\t\t\t\t.transaction('command')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Convert to list item\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlistType,\n\t\t\tindent: isNodeOfType(block, 'list_item') ? block.attrs.indent : 0,\n\t\t};\n\t\tif (listType === 'checklist') {\n\t\t\tattrs.checked = false;\n\t\t}\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate indent(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (!isTextSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || !isNodeOfType(block, 'list_item')) return false;\n\n\t\tif (block.attrs.indent >= this.config.maxIndent) return false;\n\n\t\treturn this.setIndent(context, state, block.attrs.indent + 1);\n\t}\n\n\tprivate outdent(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (!isTextSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\tif (!block || !isNodeOfType(block, 'list_item')) return false;\n\n\t\tif (block.attrs.indent <= 0) return false;\n\n\t\treturn this.setIndent(context, state, block.attrs.indent - 1);\n\t}\n\n\tprivate setIndent(context: PluginContext, state: EditorState, indent: number): boolean {\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block) return false;\n\n\t\tconst attrs = { ...block.attrs, indent } as Record<string, string | number | boolean>;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\tprivate toggleChecked(context: PluginContext, targetId?: BlockId): boolean {\n\t\tif (context.isReadOnly() && !this.config.interactiveCheckboxes) return false;\n\n\t\tconst state = context.getState();\n\t\tconst bid: BlockId | null =\n\t\t\ttargetId ?? (!isTextSelection(state.selection) ? null : state.selection.anchor.blockId);\n\t\tif (!bid) return false;\n\n\t\tconst block = state.getBlock(bid);\n\t\tif (!block || block.type !== 'list_item' || block.attrs?.listType !== 'checklist') {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst checked: boolean = !block.attrs?.checked;\n\t\tconst attrs = { ...block.attrs, checked } as Record<string, string | number | boolean>;\n\n\t\tconst tr = state\n\t\t\t.transaction('command')\n\t\t\t.setBlockType(bid, nodeType('list_item'), attrs)\n\t\t\t.setSelection(state.selection)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles Backspace at the start of a list item.\n\t * Converts the list item back to a paragraph, preserving text.\n\t */\n\tprivate handleBackspace(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item') return false;\n\t\tif (sel.anchor.offset !== 0) return false;\n\n\t\tconst tr = state\n\t\t\t.transaction('input')\n\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t.setSelection(sel)\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles Enter inside a list item.\n\t * Empty item → exit list (convert to paragraph).\n\t * Non-empty item → split and create a new list item with the same type.\n\t */\n\tprivate handleEnter(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\t\tif (!isCollapsed(sel)) return false;\n\n\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\tif (!block || block.type !== 'list_item') return false;\n\n\t\tconst text = getBlockText(block);\n\n\t\tif (text === '') {\n\t\t\t// Empty list item → convert to paragraph (exit list)\n\t\t\tconst tr = state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setBlockType(sel.anchor.blockId, nodeType('paragraph'))\n\t\t\t\t.setSelection(sel)\n\t\t\t\t.build();\n\t\t\tcontext.dispatch(tr);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Non-empty → split block and set new block to same list type\n\t\tconst newBlockId = generateBlockId();\n\t\tconst attrs: Record<string, string | number | boolean> = {\n\t\t\tlistType: isNodeOfType(block, 'list_item') ? block.attrs.listType : 'bullet',\n\t\t\tindent: isNodeOfType(block, 'list_item') ? block.attrs.indent : 0,\n\t\t};\n\t\tif (attrs.listType === 'checklist') {\n\t\t\tattrs.checked = false;\n\t\t}\n\n\t\tconst tr = state\n\t\t\t.transaction('input')\n\t\t\t.splitBlock(sel.anchor.blockId, sel.anchor.offset, newBlockId)\n\t\t\t.setBlockType(newBlockId, nodeType('list_item'), attrs)\n\t\t\t.setSelection(createCollapsedSelection(newBlockId, 0))\n\t\t\t.build();\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t// --- Checkbox Click Handling ---\n\n\tprivate registerCheckboxClickHandler(context: PluginContext): void {\n\t\tif (!this.config.types.includes('checklist')) return;\n\n\t\tthis.checkboxClickHandler = (e: MouseEvent) => {\n\t\t\tif (context.isReadOnly() && !this.config.interactiveCheckboxes) return;\n\n\t\t\tconst target: EventTarget | null = e.target;\n\t\t\tif (!(target instanceof HTMLElement)) return;\n\n\t\t\tconst li: HTMLElement | null = target.closest('.notectl-list-item--checklist');\n\t\t\tif (!li) return;\n\n\t\t\tconst rect: DOMRect = li.getBoundingClientRect();\n\t\t\tconst isRtl: boolean = getComputedStyle(li).direction === 'rtl';\n\t\t\tconst markerDistance: number = isRtl ? rect.right - e.clientX : e.clientX - rect.left;\n\t\t\tif (markerDistance >= LIST_MARKER_WIDTH) return;\n\n\t\t\te.preventDefault();\n\n\t\t\tconst bid: string | null = li.getAttribute('data-block-id');\n\t\t\tif (!bid) return;\n\n\t\t\tthis.toggleChecked(context, blockId(bid));\n\t\t};\n\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tcontainer.addEventListener('mousedown', this.checkboxClickHandler);\n\t}\n\n\t// --- Helpers ---\n\n\tprivate isListActive(state: EditorState, listType: ListType): boolean {\n\t\tif (!isTextSelection(state.selection)) return false;\n\t\tconst block = state.getBlock(state.selection.anchor.blockId);\n\t\treturn block?.type === 'list_item' && block.attrs?.listType === listType;\n\t}\n\n\tprivate getEnabledTypes(): readonly ListTypeDefinition[] {\n\t\treturn LIST_TYPE_DEFINITIONS.filter((def) => this.config.types.includes(def.type));\n\t}\n}\n"],"names":["LIST_LOCALE_EN","bulletList","numberedList","checklist","localeModules","assign","import","async","loadListLocale","lang","loader","default","DEFAULT_CONFIG","types","maxIndent","LIST_TYPE_DEFINITIONS","type","icon","inputPattern","inputPrefix","ListPlugin","id","name","priority","config","locale","context","checkboxClickHandler","constructor","this","init","resolveLocale","registerStyleSheet","registerNodeSpec","registerCommands","registerKeymaps","registerInputRules","registerToolbarItems","registerCheckboxClickHandler","destroy","getContainer","removeEventListener","group","content","allow","attrs","listType","indent","checked","toDOM","node","li","createBlockElement","setAttribute","String","className","setStyleProperty","wrapper","tag","key","role","toHTML","checkedAttr","parseHTML","sanitize","tags","enabledTypes","getEnabledTypes","def","registerCommand","toggleList","outdent","includes","toggleChecked","readonlyAllowed","registerKeymap","Enter","handleEnter","Backspace","handleBackspace","Tab","registerInputRule","pattern","handler","state","match","start","_end","sel","selection","isTextSelection","isCollapsed","block","getBlock","anchor","blockId","matchStr","matchLen","length","transaction","deleteTextAt","setBlockType","nodeType","setSelection","createCollapsedSelection","build","getListLabel","bullet","ordered","registerToolbarItem","label","command","isActive","isListActive","getState","tr","dispatch","isNodeOfType","setIndent","targetId","isReadOnly","interactiveCheckboxes","bid","offset","getBlockText","newBlockId","generateBlockId","splitBlock","e","target","HTMLElement","closest","rect","getBoundingClientRect","getComputedStyle","direction","right","clientX","left","preventDefault","getAttribute","addEventListener","filter"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PrintPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/print/PrintPlugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI1D,OAAO,KAAK,EAAgB,iBAAiB,EAAgB,MAAM,iBAAiB,CAAC;AAiBrF,qBAAa,WAAY,YAAW,MAAM;IACzC,QAAQ,CAAC,EAAE,WAAW;IACtB,QAAQ,CAAC,IAAI,WAAW;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,CAAC,EAAE,iBAAiB;IAIhC,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDjD,OAAO,IAAI,IAAI;CAGf"}
1
+ {"version":3,"file":"PrintPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/print/PrintPlugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAK1D,OAAO,KAAK,EAAgB,iBAAiB,EAAgB,MAAM,iBAAiB,CAAC;AAiBrF,qBAAa,WAAY,YAAW,MAAM;IACzC,QAAQ,CAAC,EAAE,WAAW;IACtB,QAAQ,CAAC,IAAI,WAAW;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,CAAC,EAAE,iBAAiB;IAIhC,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAmDjD,OAAO,IAAI,IAAI;CAGf"}
@@ -1,2 +1,2 @@
1
- import{a as t}from"../chunks/LocaleService-B6Z-wyAF.mjs";import{f as e}from"../chunks/ShortcutFormatting-BLKS0Gys.mjs";import{s as n,b as o}from"../chunks/StyleRuntime-BmsLoEa8.mjs";import{g as i,a as r,P as s,B as c,A as a,e as l}from"../chunks/PrintTypes-ehbL7ipA.mjs";const p={label:"Print",tooltip:t=>`Print (${t})`,printingAnnouncement:"Printing"},u=/* @__PURE__ */Object.assign({"./locales/ar.ts":()=>import("../chunks/ar-BAmGa08u.mjs"),"./locales/de.ts":()=>import("../chunks/de-CP5v-98M.mjs"),"./locales/es.ts":()=>import("../chunks/es-BkS6DsrM.mjs"),"./locales/fr.ts":()=>import("../chunks/fr-Ccku5KzA.mjs"),"./locales/hi.ts":()=>import("../chunks/hi-CpBWHmYH.mjs"),"./locales/pt.ts":()=>import("../chunks/pt-D6kdF3fH.mjs"),"./locales/ru.ts":()=>import("../chunks/ru-0h51zrqE.mjs"),"./locales/zh.ts":()=>import("../chunks/zh-DlBt06Pr.mjs")});async function m(t){if("en"===t)return p;const e=u[`./locales/${t}.ts`];if(!e)return p;try{return(await e()).default}catch{return p}}function h(t){return"function"==typeof t?t():t}const f={print(){},toHTML:()=>""};class d{id="print";name="Print";config;service=null;locale;constructor(t){this.config=t??{}}async init(u){if(this.config.locale)this.locale=this.config.locale;else{const e=u.getService(t),n=e?.getLocale()??"en";this.locale="en"===n?p:await m(n)}const d=u.getContainer(),g=d.getRootNode();if(g instanceof ShadowRoot){const t=g.host,e=u.getEventBus();this.service=function(t,e,l,p){function u(t){return t??{}}function m(o){const u={options:o,cancelled:!1};if(p.emit(c,u),u.cancelled)return null;const m=u.options,f=function(t,e,n,o="en"){return["<!DOCTYPE html>",`<html lang="${o}">`,"<head>",'<meta charset="utf-8">',`<title>${n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</title>`,`<style>${t}</style>`,"</head>",`<body>${e}</body>`,"</html>"].join("\n")}(function(t,e,n){const o=[],c=function(t){const e=[];for(const n of t.adoptedStyleSheets)for(const t of n.cssRules)e.push(t.cssText);return e.join("\n")}(t);c&&o.push(c);const a=function(t){const e=getComputedStyle(t),n=[];for(let o=0;o<e.length;o++){const t=e[o]??"";if(t.startsWith("--notectl-")){const o=e.getPropertyValue(t).trim();o&&n.push(` ${t}: ${o};`)}}return 0===n.length?"":`:root {\n${n.join("\n")}\n}`}(e);a&&o.push(a),o.push(function(t){const e=getComputedStyle(t),n=["font-family","font-size","font-weight","line-height","letter-spacing","word-spacing","color"],o=[" margin: 0;"];for(const i of n){const t=e.getPropertyValue(i).trim();t&&o.push(` ${i}: ${t};`)}return`body {\n${o.join("\n")}\n}`}(e));const l=function(t){const e=[],n=[];if(t.margin?n.push(` margin: ${t.margin};`):t.paperSize&&n.push(" margin: 0;"),t.paperSize||t.orientation){const e=[t.paperSize?i(t.paperSize):"A4"];t.orientation&&e.push(t.orientation),n.push(` size: ${e.join(" ")};`)}n.length>0&&e.push(`@page {\n${n.join("\n")}\n}`),t.paperSize&&e.push(`.notectl-content { padding: ${r}px ${s}px !important; }`);const o=[];return o.push("[data-notectl-no-print] { display: none !important; }"),o.push(".notectl-code-block { white-space: pre-wrap !important; word-break: break-all !important; page-break-inside: avoid; }"),o.push("img { page-break-inside: avoid; }"),o.push(".notectl-table { break-inside: avoid; }"),!1!==t.printBackground&&o.push("* { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }"),e.push(`@media print {\n ${o.join("\n ")}\n}`),e.join("\n\n")}(n);return l&&o.push(l),n.customCSS&&o.push(n.customCSS),o.join("\n\n")}(t,e,m),function(t,e){const o=function(t){return(t.querySelector(".notectl-content")??t).cloneNode(!0)}(t);return function(t){t.removeAttribute("contenteditable");const e=["notectl-node-selected","notectl-content--empty"];for(const n of e){t.classList.remove(n);for(const e of t.querySelectorAll(`.${n}`))e.classList.remove(n)}t.removeAttribute("data-placeholder")}(o),function(t,e){if(e.excludeBlockTypes)for(const n of e.excludeBlockTypes){const e=t.querySelectorAll(`[data-block-type="${n}"]`);for(const t of e)t.remove()}if(e.pageBreakBefore)for(const o of e.pageBreakBefore){const e=t.querySelectorAll(`[data-block-type="${o}"]`);for(const t of e)n(t,{breakBefore:"page",pageBreakBefore:"always"})}}(o,e),function(t,e){if(e.header){const n=document.createElement("div");n.className="notectl-print-header",n.innerHTML=h(e.header),t.insertBefore(n,t.firstChild)}if(e.footer){const n=document.createElement("div");n.className="notectl-print-footer",n.innerHTML=h(e.footer),t.appendChild(n)}}(o,e),o}(l,m).outerHTML,m.title??"",e.closest("[lang]")?.getAttribute("lang")??(document.documentElement.lang||"en")),d={html:f};return p.emit(a,d),f}return{print(t){const e=m(u(t));if(!e)return;const n=document.createElement("iframe");o(n,"position:fixed;left:-9999px;width:0;height:0;border:none"),document.body.appendChild(n);const i=n.contentDocument;if(!i)return void document.body.removeChild(n);i.open(),i.write(e),i.close();const r=()=>{n.remove()};n.contentWindow?(n.contentWindow.addEventListener("afterprint",r,{once:!0}),n.contentWindow.print()):r()},toHTML:t=>m(u(t))??""}}(g,t,d,e)}else this.service=f;u.registerService(l,this.service);const v=this.config.defaults??{},y=this.service,k=this.locale;u.registerCommand("print",()=>(u.announce(k.printingAnnouncement),y.print(v),!0));const b=this.config.keyBinding??"Mod-P";if(u.registerKeymap({[b]:()=>(u.executeCommand("print"),!0)}),!1!==this.config.showToolbarItem){const t=e(b);u.registerToolbarItem({id:"print",group:"actions",label:this.locale.label,tooltip:this.locale.tooltip(t),icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"/></svg>',command:"print"})}}destroy(){this.service=null}}export{a as AFTER_PRINT,c as BEFORE_PRINT,p as PRINT_LOCALE_EN,l as PRINT_SERVICE_KEY,d as PrintPlugin,m as loadPrintLocale};
1
+ import{r as t}from"../chunks/PluginHelpers-CdPR0MuT.mjs";import{f as e}from"../chunks/ShortcutFormatting-BLKS0Gys.mjs";import{s as n,b as o}from"../chunks/StyleRuntime-BmsLoEa8.mjs";import{g as r,a as i,P as s,B as c,A as a,e as l}from"../chunks/PrintTypes-DukwDSWS.mjs";const p={label:"Print",tooltip:t=>`Print (${t})`,printingAnnouncement:"Printing"},u=/* @__PURE__ */Object.assign({"./locales/ar.ts":()=>import("../chunks/ar-BAmGa08u.mjs"),"./locales/de.ts":()=>import("../chunks/de-CP5v-98M.mjs"),"./locales/es.ts":()=>import("../chunks/es-BkS6DsrM.mjs"),"./locales/fr.ts":()=>import("../chunks/fr-Ccku5KzA.mjs"),"./locales/hi.ts":()=>import("../chunks/hi-CpBWHmYH.mjs"),"./locales/pt.ts":()=>import("../chunks/pt-D6kdF3fH.mjs"),"./locales/ru.ts":()=>import("../chunks/ru-0h51zrqE.mjs"),"./locales/zh.ts":()=>import("../chunks/zh-DlBt06Pr.mjs")});async function m(t){if("en"===t)return p;const e=u[`./locales/${t}.ts`];if(!e)return p;try{return(await e()).default}catch{return p}}function h(t){return"function"==typeof t?t():t}const f={print(){},toHTML:()=>""};class d{id="print";name="Print";config;service=null;locale;constructor(t){this.config=t??{}}async init(u){this.locale=await t(u,this.config.locale,p,m);const d=u.getContainer(),g=d.getRootNode();if(g instanceof ShadowRoot){const t=g.host,e=u.getEventBus();this.service=function(t,e,l,p){function u(t){return t??{}}function m(o){const u={options:o,cancelled:!1};if(p.emit(c,u),u.cancelled)return null;const m=u.options,f=function(t,e,n,o="en"){return["<!DOCTYPE html>",`<html lang="${o}">`,"<head>",'<meta charset="utf-8">',`<title>${n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</title>`,`<style>${t}</style>`,"</head>",`<body>${e}</body>`,"</html>"].join("\n")}(function(t,e,n){const o=[],c=function(t){const e=[];for(const n of t.adoptedStyleSheets)for(const t of n.cssRules)e.push(t.cssText);return e.join("\n")}(t);c&&o.push(c);const a=function(t){const e=getComputedStyle(t),n=[];for(let o=0;o<e.length;o++){const t=e[o]??"";if(t.startsWith("--notectl-")){const o=e.getPropertyValue(t).trim();o&&n.push(` ${t}: ${o};`)}}return 0===n.length?"":`:root {\n${n.join("\n")}\n}`}(e);a&&o.push(a),o.push(function(t){const e=getComputedStyle(t),n=["font-family","font-size","font-weight","line-height","letter-spacing","word-spacing","color"],o=[" margin: 0;"];for(const r of n){const t=e.getPropertyValue(r).trim();t&&o.push(` ${r}: ${t};`)}return`body {\n${o.join("\n")}\n}`}(e));const l=function(t){const e=[],n=[];if(t.margin?n.push(` margin: ${t.margin};`):t.paperSize&&n.push(" margin: 0;"),t.paperSize||t.orientation){const e=[t.paperSize?r(t.paperSize):"A4"];t.orientation&&e.push(t.orientation),n.push(` size: ${e.join(" ")};`)}n.length>0&&e.push(`@page {\n${n.join("\n")}\n}`),t.paperSize&&e.push(`.notectl-content { padding: ${i}px ${s}px !important; }`);const o=[];return o.push("[data-notectl-no-print] { display: none !important; }"),o.push(".notectl-code-block { white-space: pre-wrap !important; word-break: break-all !important; page-break-inside: avoid; }"),o.push("img { page-break-inside: avoid; }"),o.push(".notectl-table { break-inside: avoid; }"),!1!==t.printBackground&&o.push("* { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }"),e.push(`@media print {\n ${o.join("\n ")}\n}`),e.join("\n\n")}(n);return l&&o.push(l),n.customCSS&&o.push(n.customCSS),o.join("\n\n")}(t,e,m),function(t,e){const o=function(t){return(t.querySelector(".notectl-content")??t).cloneNode(!0)}(t);return function(t){t.removeAttribute("contenteditable");const e=["notectl-node-selected","notectl-content--empty"];for(const n of e){t.classList.remove(n);for(const e of t.querySelectorAll(`.${n}`))e.classList.remove(n)}t.removeAttribute("data-placeholder")}(o),function(t,e){if(e.excludeBlockTypes)for(const n of e.excludeBlockTypes){const e=t.querySelectorAll(`[data-block-type="${n}"]`);for(const t of e)t.remove()}if(e.pageBreakBefore)for(const o of e.pageBreakBefore){const e=t.querySelectorAll(`[data-block-type="${o}"]`);for(const t of e)n(t,{breakBefore:"page",pageBreakBefore:"always"})}}(o,e),function(t,e){if(e.header){const n=document.createElement("div");n.className="notectl-print-header",n.innerHTML=h(e.header),t.insertBefore(n,t.firstChild)}if(e.footer){const n=document.createElement("div");n.className="notectl-print-footer",n.innerHTML=h(e.footer),t.appendChild(n)}}(o,e),o}(l,m).outerHTML,m.title??"",e.closest("[lang]")?.getAttribute("lang")??(document.documentElement.lang||"en")),d={html:f};return p.emit(a,d),f}return{print(t){const e=m(u(t));if(!e)return;const n=document.createElement("iframe");o(n,"position:fixed;left:-9999px;width:0;height:0;border:none"),document.body.appendChild(n);const r=n.contentDocument;if(!r)return void document.body.removeChild(n);r.open(),r.write(e),r.close();const i=()=>{n.remove()};n.contentWindow?(n.contentWindow.addEventListener("afterprint",i,{once:!0}),n.contentWindow.print()):i()},toHTML:t=>m(u(t))??""}}(g,t,d,e)}else this.service=f;u.registerService(l,this.service);const y=this.config.defaults??{},v=this.service,k=this.locale;u.registerCommand("print",()=>(u.announce(k.printingAnnouncement),v.print(y),!0));const b=this.config.keyBinding??"Mod-P";if(u.registerKeymap({[b]:()=>(u.executeCommand("print"),!0)}),!1!==this.config.showToolbarItem){const t=e(b);u.registerToolbarItem({id:"print",group:"actions",label:this.locale.label,tooltip:this.locale.tooltip(t),icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"/></svg>',command:"print"})}}destroy(){this.service=null}}export{a as AFTER_PRINT,c as BEFORE_PRINT,p as PRINT_LOCALE_EN,l as PRINT_SERVICE_KEY,d as PrintPlugin,m as loadPrintLocale};
2
2
  //# sourceMappingURL=print.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"print.mjs","sources":["../../src/plugins/print/PrintLocale.ts","../../src/plugins/print/PrintContentPreparer.ts","../../src/plugins/print/PrintPlugin.ts","../../src/plugins/print/PrintServiceImpl.ts","../../src/plugins/print/PrintStyleCollector.ts"],"sourcesContent":["/** Locale interface and default English locale for the PrintPlugin. */\n\n// --- Locale Interface ---\n\nexport interface PrintLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n\treadonly printingAnnouncement: string;\n}\n\n// --- Default English Locale ---\n\nexport const PRINT_LOCALE_EN: PrintLocale = {\n\tlabel: 'Print',\n\ttooltip: (shortcut: string) => `Print (${shortcut})`,\n\tprintingAnnouncement: 'Printing',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: PrintLocale }>> = import.meta.glob<{\n\tdefault: PrintLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadPrintLocale(lang: string): Promise<PrintLocale> {\n\tif (lang === 'en') return PRINT_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return PRINT_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn PRINT_LOCALE_EN;\n\t}\n}\n","/**\n * Prepares editor content for print output.\n * Clones the DOM, sanitizes interactive attributes, applies block filters,\n * and inserts header/footer elements.\n */\n\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Deep-clones the .notectl-content element from the editor container. */\nexport function cloneContent(container: HTMLElement): HTMLElement {\n\tconst content: HTMLElement | null = container.querySelector('.notectl-content');\n\tconst source: HTMLElement = content ?? container;\n\treturn source.cloneNode(true) as HTMLElement;\n}\n\n/** Sanitizes the cloned content for print: removes interactive attributes and selection styling. */\nexport function sanitize(clone: HTMLElement): void {\n\t// Remove contenteditable from the root\n\tclone.removeAttribute('contenteditable');\n\n\t// Remove selection-related CSS classes\n\tconst selectionClasses: readonly string[] = ['notectl-node-selected', 'notectl-content--empty'];\n\tfor (const cls of selectionClasses) {\n\t\tclone.classList.remove(cls);\n\t\tfor (const el of clone.querySelectorAll(`.${cls}`)) {\n\t\t\tel.classList.remove(cls);\n\t\t}\n\t}\n\n\t// Remove data-placeholder to avoid showing placeholder in print\n\tclone.removeAttribute('data-placeholder');\n}\n\n/** Removes excluded block types and applies page-break-before to configured block types. */\nexport function applyBlockFilters(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.excludeBlockTypes) {\n\t\tfor (const type of options.excludeBlockTypes) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tel.remove();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (options.pageBreakBefore) {\n\t\tfor (const type of options.pageBreakBefore) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tsetStyleProperties(el as HTMLElement, {\n\t\t\t\t\tbreakBefore: 'page',\n\t\t\t\t\tpageBreakBefore: 'always',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Resolves a header/footer value to an HTML string. */\nfunction resolveContent(value: string | (() => string)): string {\n\treturn typeof value === 'function' ? value() : value;\n}\n\n/** Inserts header and footer elements into the cloned content. */\nexport function insertHeaderFooter(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.header) {\n\t\tconst headerEl: HTMLDivElement = document.createElement('div');\n\t\theaderEl.className = 'notectl-print-header';\n\t\theaderEl.innerHTML = resolveContent(options.header);\n\t\tclone.insertBefore(headerEl, clone.firstChild);\n\t}\n\n\tif (options.footer) {\n\t\tconst footerEl: HTMLDivElement = document.createElement('div');\n\t\tfooterEl.className = 'notectl-print-footer';\n\t\tfooterEl.innerHTML = resolveContent(options.footer);\n\t\tclone.appendChild(footerEl);\n\t}\n}\n\n/** Orchestrates all content preparation steps. Returns a ready-to-print DOM element. */\nexport function prepare(container: HTMLElement, options: PrintOptions): HTMLElement {\n\tconst clone: HTMLElement = cloneContent(container);\n\tsanitize(clone);\n\tapplyBlockFilters(clone, options);\n\tinsertHeaderFooter(clone, options);\n\treturn clone;\n}\n","/**\n * PrintPlugin: provides print functionality for the notectl editor.\n * Registers a command, keymap, toolbar item, and exposes a PrintService.\n * Orchestrator only — delegates all logic to PrintServiceImpl, PrintStyleCollector,\n * and PrintContentPreparer.\n */\n\nimport { LocaleServiceKey } from '../../i18n/LocaleService.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { PRINT_LOCALE_EN, type PrintLocale, loadPrintLocale } from './PrintLocale.js';\nimport { createPrintService } from './PrintServiceImpl.js';\nimport type { PrintOptions, PrintPluginConfig, PrintService } from './PrintTypes.js';\nimport { PRINT_SERVICE_KEY } from './PrintTypes.js';\n\nconst PRINT_ICON: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\">' +\n\t'<path d=\"M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3' +\n\t' 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z\"/>' +\n\t'</svg>';\n\n/** No-op fallback service for environments without ShadowRoot. */\nconst NOOP_SERVICE: PrintService = {\n\tprint(): void {},\n\ttoHTML(): string {\n\t\treturn '';\n\t},\n};\n\nexport class PrintPlugin implements Plugin {\n\treadonly id = 'print';\n\treadonly name = 'Print';\n\n\tprivate readonly config: PrintPluginConfig;\n\tprivate service: PrintService | null = null;\n\tprivate locale!: PrintLocale;\n\n\tconstructor(config?: PrintPluginConfig) {\n\t\tthis.config = config ?? {};\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tif (this.config.locale) {\n\t\t\tthis.locale = this.config.locale;\n\t\t} else {\n\t\t\tconst service = context.getService(LocaleServiceKey);\n\t\t\tconst lang: string = service?.getLocale() ?? 'en';\n\t\t\tthis.locale = lang === 'en' ? PRINT_LOCALE_EN : await loadPrintLocale(lang);\n\t\t}\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tconst rootNode: Node = container.getRootNode();\n\n\t\tif (rootNode instanceof ShadowRoot) {\n\t\t\tconst host: HTMLElement = rootNode.host as HTMLElement;\n\t\t\tconst eventBus = context.getEventBus();\n\t\t\tthis.service = createPrintService(rootNode, host, container, eventBus);\n\t\t} else {\n\t\t\tthis.service = NOOP_SERVICE;\n\t\t}\n\n\t\tcontext.registerService(PRINT_SERVICE_KEY, this.service);\n\n\t\tconst defaults: PrintOptions = this.config.defaults ?? {};\n\t\tconst service: PrintService = this.service;\n\n\t\tconst printLocale = this.locale;\n\t\tcontext.registerCommand('print', () => {\n\t\t\tcontext.announce(printLocale.printingAnnouncement);\n\t\t\tservice.print(defaults);\n\t\t\treturn true;\n\t\t});\n\n\t\tconst keyBinding: string = this.config.keyBinding ?? 'Mod-P';\n\t\tcontext.registerKeymap({\n\t\t\t[keyBinding]: () => {\n\t\t\t\tcontext.executeCommand('print');\n\t\t\t\treturn true;\n\t\t\t},\n\t\t});\n\n\t\tif (this.config.showToolbarItem !== false) {\n\t\t\tconst shortcut: string = formatShortcut(keyBinding);\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: 'print',\n\t\t\t\tgroup: 'actions',\n\t\t\t\tlabel: this.locale.label,\n\t\t\t\ttooltip: this.locale.tooltip(shortcut),\n\t\t\t\ticon: PRINT_ICON,\n\t\t\t\tcommand: 'print',\n\t\t\t});\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.service = null;\n\t}\n}\n","/**\n * PrintService implementation.\n * Handles the synchronous print flow: event emission, style collection,\n * content preparation, iframe creation, and cleanup.\n */\n\nimport { setStyleText } from '../../style/StyleRuntime.js';\nimport type { PluginEventBus } from '../Plugin.js';\nimport { prepare } from './PrintContentPreparer.js';\nimport { collectAll } from './PrintStyleCollector.js';\nimport {\n\tAFTER_PRINT,\n\ttype AfterPrintEvent,\n\tBEFORE_PRINT,\n\ttype BeforePrintEvent,\n\ttype PrintOptions,\n\ttype PrintService,\n} from './PrintTypes.js';\n\n/** Escapes HTML special characters in a plain-text string. */\nfunction escapeHTML(text: string): string {\n\treturn text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\n/** Builds a complete HTML document string from CSS, body content, and title. */\nexport function buildHTMLDocument(\n\tcss: string,\n\tcontent: string,\n\ttitle: string,\n\tlang = 'en',\n): string {\n\tconst safeTitle: string = escapeHTML(title);\n\treturn [\n\t\t'<!DOCTYPE html>',\n\t\t`<html lang=\"${lang}\">`,\n\t\t'<head>',\n\t\t`<meta charset=\"utf-8\">`,\n\t\t`<title>${safeTitle}</title>`,\n\t\t`<style>${css}</style>`,\n\t\t'</head>',\n\t\t`<body>${content}</body>`,\n\t\t'</html>',\n\t].join('\\n');\n}\n\n/** Creates and returns the PrintService implementation. */\nexport function createPrintService(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\tcontainer: HTMLElement,\n\teventBus: PluginEventBus,\n): PrintService {\n\tfunction mergeOptions(options?: PrintOptions): PrintOptions {\n\t\treturn options ?? {};\n\t}\n\n\tfunction executePrint(options: PrintOptions): string | null {\n\t\t// 1. Emit BEFORE_PRINT — listeners can mutate options or cancel\n\t\tconst beforeEvent: BeforePrintEvent = {\n\t\t\toptions,\n\t\t\tcancelled: false,\n\t\t};\n\t\teventBus.emit(BEFORE_PRINT, beforeEvent);\n\n\t\tif (beforeEvent.cancelled) return null;\n\n\t\tconst finalOptions: PrintOptions = beforeEvent.options;\n\n\t\t// 2. Collect styles\n\t\tconst css: string = collectAll(shadowRoot, host, finalOptions);\n\n\t\t// 3. Prepare content\n\t\tconst clone: HTMLElement = prepare(container, finalOptions);\n\t\tconst contentHTML: string = clone.outerHTML;\n\n\t\t// 4. Build HTML document\n\t\tconst title: string = finalOptions.title ?? '';\n\t\tconst lang: string =\n\t\t\thost.closest('[lang]')?.getAttribute('lang') ?? (document.documentElement.lang || 'en');\n\t\tconst html: string = buildHTMLDocument(css, contentHTML, title, lang);\n\n\t\t// 5. Emit AFTER_PRINT\n\t\tconst afterEvent: AfterPrintEvent = { html };\n\t\teventBus.emit(AFTER_PRINT, afterEvent);\n\n\t\treturn html;\n\t}\n\n\treturn {\n\t\tprint(options?: PrintOptions): void {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\tconst html: string | null = executePrint(resolved);\n\t\t\tif (!html) return;\n\n\t\t\t// Create hidden iframe\n\t\t\tconst iframe: HTMLIFrameElement = document.createElement('iframe');\n\t\t\tsetStyleText(iframe, 'position:fixed;left:-9999px;width:0;height:0;border:none');\n\t\t\tdocument.body.appendChild(iframe);\n\n\t\t\tconst iframeDoc: Document | null = iframe.contentDocument;\n\t\t\tif (!iframeDoc) {\n\t\t\t\tdocument.body.removeChild(iframe);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tiframeDoc.open();\n\t\t\tiframeDoc.write(html);\n\t\t\tiframeDoc.close();\n\n\t\t\tconst cleanup = (): void => {\n\t\t\t\tiframe.remove();\n\t\t\t};\n\n\t\t\t// Defer cleanup until print dialog closes\n\t\t\tif (iframe.contentWindow) {\n\t\t\t\tiframe.contentWindow.addEventListener('afterprint', cleanup, { once: true });\n\t\t\t\tiframe.contentWindow.print();\n\t\t\t} else {\n\t\t\t\tcleanup();\n\t\t\t}\n\t\t},\n\n\t\ttoHTML(options?: PrintOptions): string {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\treturn executePrint(resolved) ?? '';\n\t\t},\n\t};\n}\n","/**\n * Collects and aggregates CSS for print output.\n * Extracts adopted stylesheets, snapshots theme tokens, and generates print-specific CSS.\n */\n\nimport {\n\tPAPER_MARGIN_HORIZONTAL_PX,\n\tPAPER_MARGIN_TOP_PX,\n\tgetPaperCSSSize,\n} from '../../model/PaperSize.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Extracts CSS text from all adopted stylesheets on a ShadowRoot. */\nexport function extractAdoptedStyles(shadowRoot: ShadowRoot): string {\n\tconst parts: string[] = [];\n\tfor (const sheet of shadowRoot.adoptedStyleSheets) {\n\t\tfor (const rule of sheet.cssRules) {\n\t\t\tparts.push(rule.cssText);\n\t\t}\n\t}\n\treturn parts.join('\\n');\n}\n\n/** Snapshots --notectl-* CSS custom properties from the host element into a :root block. */\nexport function snapshotThemeTokens(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst tokens: string[] = [];\n\n\tfor (let i = 0; i < computed.length; i++) {\n\t\tconst prop: string = computed[i] ?? '';\n\t\tif (prop.startsWith('--notectl-')) {\n\t\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\t\tif (value) {\n\t\t\t\ttokens.push(` ${prop}: ${value};`);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (tokens.length === 0) return '';\n\treturn `:root {\\n${tokens.join('\\n')}\\n}`;\n}\n\n/**\n * Snapshots computed typography from the host element into a `body` rule.\n * In the editor, typography is inherited from `:host` (shadow DOM).\n * The print iframe is a regular document where `:host` doesn't match,\n * so we must apply the same font/line-height explicitly.\n */\nexport function snapshotTypography(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst props: string[] = [\n\t\t'font-family',\n\t\t'font-size',\n\t\t'font-weight',\n\t\t'line-height',\n\t\t'letter-spacing',\n\t\t'word-spacing',\n\t\t'color',\n\t];\n\tconst rules: string[] = [' margin: 0;'];\n\tfor (const prop of props) {\n\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\tif (value) {\n\t\t\trules.push(` ${prop}: ${value};`);\n\t\t}\n\t}\n\treturn `body {\\n${rules.join('\\n')}\\n}`;\n}\n\n/** Generates print-specific CSS rules based on PrintOptions. */\nexport function generatePrintCSS(options: PrintOptions): string {\n\tconst parts: string[] = [];\n\n\t// @page rule\n\tconst pageProps: string[] = [];\n\tif (options.margin) {\n\t\tpageProps.push(` margin: ${options.margin};`);\n\t} else if (options.paperSize) {\n\t\t// WYSIWYG: zero @page margin so body = full paper width;\n\t\t// document margins are applied as content padding below.\n\t\tpageProps.push(' margin: 0;');\n\t}\n\tif (options.paperSize || options.orientation) {\n\t\tconst sizeKeyword: string = options.paperSize ? getPaperCSSSize(options.paperSize) : 'A4';\n\t\tconst sizeParts: string[] = [sizeKeyword];\n\t\tif (options.orientation) {\n\t\t\tsizeParts.push(options.orientation);\n\t\t}\n\t\tpageProps.push(` size: ${sizeParts.join(' ')};`);\n\t}\n\tif (pageProps.length > 0) {\n\t\tparts.push(`@page {\\n${pageProps.join('\\n')}\\n}`);\n\t}\n\n\t// WYSIWYG: apply paper-mode document margins to print content\n\tif (options.paperSize) {\n\t\tparts.push(\n\t\t\t`.notectl-content { padding: ${PAPER_MARGIN_TOP_PX}px ${PAPER_MARGIN_HORIZONTAL_PX}px !important; }`,\n\t\t);\n\t}\n\n\t// Print media rules\n\tconst printRules: string[] = [];\n\n\t// Hide non-printable elements\n\tprintRules.push('[data-notectl-no-print] { display: none !important; }');\n\n\t// Code blocks: preserve background, force wrapping\n\tprintRules.push(\n\t\t'.notectl-code-block { white-space: pre-wrap !important; ' +\n\t\t\t'word-break: break-all !important; page-break-inside: avoid; }',\n\t);\n\n\t// Images: avoid page breaks\n\tprintRules.push('img { page-break-inside: avoid; }');\n\n\t// Tables: avoid page breaks\n\tprintRules.push('.notectl-table { break-inside: avoid; }');\n\n\t// Preserve background colors and images in print output (WYSIWYG default).\n\t// Only omitted when the consumer explicitly opts out via printBackground: false.\n\tif (options.printBackground !== false) {\n\t\tprintRules.push(\n\t\t\t'* { -webkit-print-color-adjust: exact !important; ' +\n\t\t\t\t'print-color-adjust: exact !important; }',\n\t\t);\n\t}\n\n\tparts.push(`@media print {\\n ${printRules.join('\\n ')}\\n}`);\n\n\treturn parts.join('\\n\\n');\n}\n\n/** Collects all CSS needed for print: adopted styles, theme tokens, print CSS, and custom CSS. */\nexport function collectAll(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\toptions: PrintOptions,\n): string {\n\tconst parts: string[] = [];\n\n\tconst adopted: string = extractAdoptedStyles(shadowRoot);\n\tif (adopted) parts.push(adopted);\n\n\tconst theme: string = snapshotThemeTokens(host);\n\tif (theme) parts.push(theme);\n\n\t// WYSIWYG: snapshot host typography so the print iframe matches the editor.\n\t// In the editor, .notectl-content inherits font from :host (shadow DOM).\n\t// The print iframe is a regular document where :host doesn't apply.\n\tparts.push(snapshotTypography(host));\n\n\tconst printCSS: string = generatePrintCSS(options);\n\tif (printCSS) parts.push(printCSS);\n\n\tif (options.customCSS) {\n\t\tparts.push(options.customCSS);\n\t}\n\n\treturn parts.join('\\n\\n');\n}\n"],"names":["PRINT_LOCALE_EN","label","tooltip","shortcut","printingAnnouncement","localeModules","assign","import","async","loadPrintLocale","lang","loader","default","resolveContent","value","NOOP_SERVICE","print","toHTML","PrintPlugin","id","name","config","service","locale","constructor","this","init","context","getService","LocaleServiceKey","getLocale","container","getContainer","rootNode","getRootNode","ShadowRoot","host","eventBus","getEventBus","shadowRoot","mergeOptions","options","executePrint","beforeEvent","cancelled","emit","BEFORE_PRINT","finalOptions","html","css","content","title","replace","join","buildHTMLDocument","parts","adopted","sheet","adoptedStyleSheets","rule","cssRules","push","cssText","extractAdoptedStyles","theme","computed","getComputedStyle","tokens","i","length","prop","startsWith","getPropertyValue","trim","snapshotThemeTokens","props","rules","snapshotTypography","printCSS","pageProps","margin","paperSize","orientation","sizeParts","getPaperCSSSize","PAPER_MARGIN_TOP_PX","PAPER_MARGIN_HORIZONTAL_PX","printRules","printBackground","generatePrintCSS","customCSS","collectAll","clone","querySelector","cloneNode","cloneContent","removeAttribute","selectionClasses","cls","classList","remove","el","querySelectorAll","sanitize","excludeBlockTypes","type","elements","pageBreakBefore","setStyleProperties","breakBefore","applyBlockFilters","header","headerEl","document","createElement","className","innerHTML","insertBefore","firstChild","footer","footerEl","appendChild","insertHeaderFooter","prepare","outerHTML","closest","getAttribute","documentElement","afterEvent","AFTER_PRINT","iframe","setStyleText","body","iframeDoc","contentDocument","removeChild","open","write","close","cleanup","contentWindow","addEventListener","once","createPrintService","registerService","PRINT_SERVICE_KEY","defaults","printLocale","registerCommand","announce","keyBinding","registerKeymap","executeCommand","showToolbarItem","formatShortcut","registerToolbarItem","group","icon","command","destroy"],"mappings":"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"}
1
+ {"version":3,"file":"print.mjs","sources":["../../src/plugins/print/PrintLocale.ts","../../src/plugins/print/PrintContentPreparer.ts","../../src/plugins/print/PrintPlugin.ts","../../src/plugins/print/PrintServiceImpl.ts","../../src/plugins/print/PrintStyleCollector.ts"],"sourcesContent":["/** Locale interface and default English locale for the PrintPlugin. */\n\n// --- Locale Interface ---\n\nexport interface PrintLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n\treadonly printingAnnouncement: string;\n}\n\n// --- Default English Locale ---\n\nexport const PRINT_LOCALE_EN: PrintLocale = {\n\tlabel: 'Print',\n\ttooltip: (shortcut: string) => `Print (${shortcut})`,\n\tprintingAnnouncement: 'Printing',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: Record<string, () => Promise<{ default: PrintLocale }>> = import.meta.glob<{\n\tdefault: PrintLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadPrintLocale(lang: string): Promise<PrintLocale> {\n\tif (lang === 'en') return PRINT_LOCALE_EN;\n\tconst loader = localeModules[`./locales/${lang}.ts`];\n\tif (!loader) return PRINT_LOCALE_EN;\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn PRINT_LOCALE_EN;\n\t}\n}\n","/**\n * Prepares editor content for print output.\n * Clones the DOM, sanitizes interactive attributes, applies block filters,\n * and inserts header/footer elements.\n */\n\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Deep-clones the .notectl-content element from the editor container. */\nexport function cloneContent(container: HTMLElement): HTMLElement {\n\tconst content: HTMLElement | null = container.querySelector('.notectl-content');\n\tconst source: HTMLElement = content ?? container;\n\treturn source.cloneNode(true) as HTMLElement;\n}\n\n/** Sanitizes the cloned content for print: removes interactive attributes and selection styling. */\nexport function sanitize(clone: HTMLElement): void {\n\t// Remove contenteditable from the root\n\tclone.removeAttribute('contenteditable');\n\n\t// Remove selection-related CSS classes\n\tconst selectionClasses: readonly string[] = ['notectl-node-selected', 'notectl-content--empty'];\n\tfor (const cls of selectionClasses) {\n\t\tclone.classList.remove(cls);\n\t\tfor (const el of clone.querySelectorAll(`.${cls}`)) {\n\t\t\tel.classList.remove(cls);\n\t\t}\n\t}\n\n\t// Remove data-placeholder to avoid showing placeholder in print\n\tclone.removeAttribute('data-placeholder');\n}\n\n/** Removes excluded block types and applies page-break-before to configured block types. */\nexport function applyBlockFilters(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.excludeBlockTypes) {\n\t\tfor (const type of options.excludeBlockTypes) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tel.remove();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (options.pageBreakBefore) {\n\t\tfor (const type of options.pageBreakBefore) {\n\t\t\tconst elements: NodeListOf<Element> = clone.querySelectorAll(`[data-block-type=\"${type}\"]`);\n\t\t\tfor (const el of elements) {\n\t\t\t\tsetStyleProperties(el as HTMLElement, {\n\t\t\t\t\tbreakBefore: 'page',\n\t\t\t\t\tpageBreakBefore: 'always',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Resolves a header/footer value to an HTML string. */\nfunction resolveContent(value: string | (() => string)): string {\n\treturn typeof value === 'function' ? value() : value;\n}\n\n/** Inserts header and footer elements into the cloned content. */\nexport function insertHeaderFooter(clone: HTMLElement, options: PrintOptions): void {\n\tif (options.header) {\n\t\tconst headerEl: HTMLDivElement = document.createElement('div');\n\t\theaderEl.className = 'notectl-print-header';\n\t\theaderEl.innerHTML = resolveContent(options.header);\n\t\tclone.insertBefore(headerEl, clone.firstChild);\n\t}\n\n\tif (options.footer) {\n\t\tconst footerEl: HTMLDivElement = document.createElement('div');\n\t\tfooterEl.className = 'notectl-print-footer';\n\t\tfooterEl.innerHTML = resolveContent(options.footer);\n\t\tclone.appendChild(footerEl);\n\t}\n}\n\n/** Orchestrates all content preparation steps. Returns a ready-to-print DOM element. */\nexport function prepare(container: HTMLElement, options: PrintOptions): HTMLElement {\n\tconst clone: HTMLElement = cloneContent(container);\n\tsanitize(clone);\n\tapplyBlockFilters(clone, options);\n\tinsertHeaderFooter(clone, options);\n\treturn clone;\n}\n","/**\n * PrintPlugin: provides print functionality for the notectl editor.\n * Registers a command, keymap, toolbar item, and exposes a PrintService.\n * Orchestrator only — delegates all logic to PrintServiceImpl, PrintStyleCollector,\n * and PrintContentPreparer.\n */\n\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { PRINT_LOCALE_EN, type PrintLocale, loadPrintLocale } from './PrintLocale.js';\nimport { createPrintService } from './PrintServiceImpl.js';\nimport type { PrintOptions, PrintPluginConfig, PrintService } from './PrintTypes.js';\nimport { PRINT_SERVICE_KEY } from './PrintTypes.js';\n\nconst PRINT_ICON: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\">' +\n\t'<path d=\"M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3' +\n\t' 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z\"/>' +\n\t'</svg>';\n\n/** No-op fallback service for environments without ShadowRoot. */\nconst NOOP_SERVICE: PrintService = {\n\tprint(): void {},\n\ttoHTML(): string {\n\t\treturn '';\n\t},\n};\n\nexport class PrintPlugin implements Plugin {\n\treadonly id = 'print';\n\treadonly name = 'Print';\n\n\tprivate readonly config: PrintPluginConfig;\n\tprivate service: PrintService | null = null;\n\tprivate locale!: PrintLocale;\n\n\tconstructor(config?: PrintPluginConfig) {\n\t\tthis.config = config ?? {};\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tPRINT_LOCALE_EN,\n\t\t\tloadPrintLocale,\n\t\t);\n\t\tconst container: HTMLElement = context.getContainer();\n\t\tconst rootNode: Node = container.getRootNode();\n\n\t\tif (rootNode instanceof ShadowRoot) {\n\t\t\tconst host: HTMLElement = rootNode.host as HTMLElement;\n\t\t\tconst eventBus = context.getEventBus();\n\t\t\tthis.service = createPrintService(rootNode, host, container, eventBus);\n\t\t} else {\n\t\t\tthis.service = NOOP_SERVICE;\n\t\t}\n\n\t\tcontext.registerService(PRINT_SERVICE_KEY, this.service);\n\n\t\tconst defaults: PrintOptions = this.config.defaults ?? {};\n\t\tconst service: PrintService = this.service;\n\n\t\tconst printLocale = this.locale;\n\t\tcontext.registerCommand('print', () => {\n\t\t\tcontext.announce(printLocale.printingAnnouncement);\n\t\t\tservice.print(defaults);\n\t\t\treturn true;\n\t\t});\n\n\t\tconst keyBinding: string = this.config.keyBinding ?? 'Mod-P';\n\t\tcontext.registerKeymap({\n\t\t\t[keyBinding]: () => {\n\t\t\t\tcontext.executeCommand('print');\n\t\t\t\treturn true;\n\t\t\t},\n\t\t});\n\n\t\tif (this.config.showToolbarItem !== false) {\n\t\t\tconst shortcut: string = formatShortcut(keyBinding);\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: 'print',\n\t\t\t\tgroup: 'actions',\n\t\t\t\tlabel: this.locale.label,\n\t\t\t\ttooltip: this.locale.tooltip(shortcut),\n\t\t\t\ticon: PRINT_ICON,\n\t\t\t\tcommand: 'print',\n\t\t\t});\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.service = null;\n\t}\n}\n","/**\n * PrintService implementation.\n * Handles the synchronous print flow: event emission, style collection,\n * content preparation, iframe creation, and cleanup.\n */\n\nimport { setStyleText } from '../../style/StyleRuntime.js';\nimport type { PluginEventBus } from '../Plugin.js';\nimport { prepare } from './PrintContentPreparer.js';\nimport { collectAll } from './PrintStyleCollector.js';\nimport {\n\tAFTER_PRINT,\n\ttype AfterPrintEvent,\n\tBEFORE_PRINT,\n\ttype BeforePrintEvent,\n\ttype PrintOptions,\n\ttype PrintService,\n} from './PrintTypes.js';\n\n/** Escapes HTML special characters in a plain-text string. */\nfunction escapeHTML(text: string): string {\n\treturn text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\n/** Builds a complete HTML document string from CSS, body content, and title. */\nexport function buildHTMLDocument(\n\tcss: string,\n\tcontent: string,\n\ttitle: string,\n\tlang = 'en',\n): string {\n\tconst safeTitle: string = escapeHTML(title);\n\treturn [\n\t\t'<!DOCTYPE html>',\n\t\t`<html lang=\"${lang}\">`,\n\t\t'<head>',\n\t\t`<meta charset=\"utf-8\">`,\n\t\t`<title>${safeTitle}</title>`,\n\t\t`<style>${css}</style>`,\n\t\t'</head>',\n\t\t`<body>${content}</body>`,\n\t\t'</html>',\n\t].join('\\n');\n}\n\n/** Creates and returns the PrintService implementation. */\nexport function createPrintService(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\tcontainer: HTMLElement,\n\teventBus: PluginEventBus,\n): PrintService {\n\tfunction mergeOptions(options?: PrintOptions): PrintOptions {\n\t\treturn options ?? {};\n\t}\n\n\tfunction executePrint(options: PrintOptions): string | null {\n\t\t// 1. Emit BEFORE_PRINT — listeners can mutate options or cancel\n\t\tconst beforeEvent: BeforePrintEvent = {\n\t\t\toptions,\n\t\t\tcancelled: false,\n\t\t};\n\t\teventBus.emit(BEFORE_PRINT, beforeEvent);\n\n\t\tif (beforeEvent.cancelled) return null;\n\n\t\tconst finalOptions: PrintOptions = beforeEvent.options;\n\n\t\t// 2. Collect styles\n\t\tconst css: string = collectAll(shadowRoot, host, finalOptions);\n\n\t\t// 3. Prepare content\n\t\tconst clone: HTMLElement = prepare(container, finalOptions);\n\t\tconst contentHTML: string = clone.outerHTML;\n\n\t\t// 4. Build HTML document\n\t\tconst title: string = finalOptions.title ?? '';\n\t\tconst lang: string =\n\t\t\thost.closest('[lang]')?.getAttribute('lang') ?? (document.documentElement.lang || 'en');\n\t\tconst html: string = buildHTMLDocument(css, contentHTML, title, lang);\n\n\t\t// 5. Emit AFTER_PRINT\n\t\tconst afterEvent: AfterPrintEvent = { html };\n\t\teventBus.emit(AFTER_PRINT, afterEvent);\n\n\t\treturn html;\n\t}\n\n\treturn {\n\t\tprint(options?: PrintOptions): void {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\tconst html: string | null = executePrint(resolved);\n\t\t\tif (!html) return;\n\n\t\t\t// Create hidden iframe\n\t\t\tconst iframe: HTMLIFrameElement = document.createElement('iframe');\n\t\t\tsetStyleText(iframe, 'position:fixed;left:-9999px;width:0;height:0;border:none');\n\t\t\tdocument.body.appendChild(iframe);\n\n\t\t\tconst iframeDoc: Document | null = iframe.contentDocument;\n\t\t\tif (!iframeDoc) {\n\t\t\t\tdocument.body.removeChild(iframe);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tiframeDoc.open();\n\t\t\tiframeDoc.write(html);\n\t\t\tiframeDoc.close();\n\n\t\t\tconst cleanup = (): void => {\n\t\t\t\tiframe.remove();\n\t\t\t};\n\n\t\t\t// Defer cleanup until print dialog closes\n\t\t\tif (iframe.contentWindow) {\n\t\t\t\tiframe.contentWindow.addEventListener('afterprint', cleanup, { once: true });\n\t\t\t\tiframe.contentWindow.print();\n\t\t\t} else {\n\t\t\t\tcleanup();\n\t\t\t}\n\t\t},\n\n\t\ttoHTML(options?: PrintOptions): string {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\treturn executePrint(resolved) ?? '';\n\t\t},\n\t};\n}\n","/**\n * Collects and aggregates CSS for print output.\n * Extracts adopted stylesheets, snapshots theme tokens, and generates print-specific CSS.\n */\n\nimport {\n\tPAPER_MARGIN_HORIZONTAL_PX,\n\tPAPER_MARGIN_TOP_PX,\n\tgetPaperCSSSize,\n} from '../../model/PaperSize.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Extracts CSS text from all adopted stylesheets on a ShadowRoot. */\nexport function extractAdoptedStyles(shadowRoot: ShadowRoot): string {\n\tconst parts: string[] = [];\n\tfor (const sheet of shadowRoot.adoptedStyleSheets) {\n\t\tfor (const rule of sheet.cssRules) {\n\t\t\tparts.push(rule.cssText);\n\t\t}\n\t}\n\treturn parts.join('\\n');\n}\n\n/** Snapshots --notectl-* CSS custom properties from the host element into a :root block. */\nexport function snapshotThemeTokens(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst tokens: string[] = [];\n\n\tfor (let i = 0; i < computed.length; i++) {\n\t\tconst prop: string = computed[i] ?? '';\n\t\tif (prop.startsWith('--notectl-')) {\n\t\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\t\tif (value) {\n\t\t\t\ttokens.push(` ${prop}: ${value};`);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (tokens.length === 0) return '';\n\treturn `:root {\\n${tokens.join('\\n')}\\n}`;\n}\n\n/**\n * Snapshots computed typography from the host element into a `body` rule.\n * In the editor, typography is inherited from `:host` (shadow DOM).\n * The print iframe is a regular document where `:host` doesn't match,\n * so we must apply the same font/line-height explicitly.\n */\nexport function snapshotTypography(host: HTMLElement): string {\n\tconst computed: CSSStyleDeclaration = getComputedStyle(host);\n\tconst props: string[] = [\n\t\t'font-family',\n\t\t'font-size',\n\t\t'font-weight',\n\t\t'line-height',\n\t\t'letter-spacing',\n\t\t'word-spacing',\n\t\t'color',\n\t];\n\tconst rules: string[] = [' margin: 0;'];\n\tfor (const prop of props) {\n\t\tconst value: string = computed.getPropertyValue(prop).trim();\n\t\tif (value) {\n\t\t\trules.push(` ${prop}: ${value};`);\n\t\t}\n\t}\n\treturn `body {\\n${rules.join('\\n')}\\n}`;\n}\n\n/** Generates print-specific CSS rules based on PrintOptions. */\nexport function generatePrintCSS(options: PrintOptions): string {\n\tconst parts: string[] = [];\n\n\t// @page rule\n\tconst pageProps: string[] = [];\n\tif (options.margin) {\n\t\tpageProps.push(` margin: ${options.margin};`);\n\t} else if (options.paperSize) {\n\t\t// WYSIWYG: zero @page margin so body = full paper width;\n\t\t// document margins are applied as content padding below.\n\t\tpageProps.push(' margin: 0;');\n\t}\n\tif (options.paperSize || options.orientation) {\n\t\tconst sizeKeyword: string = options.paperSize ? getPaperCSSSize(options.paperSize) : 'A4';\n\t\tconst sizeParts: string[] = [sizeKeyword];\n\t\tif (options.orientation) {\n\t\t\tsizeParts.push(options.orientation);\n\t\t}\n\t\tpageProps.push(` size: ${sizeParts.join(' ')};`);\n\t}\n\tif (pageProps.length > 0) {\n\t\tparts.push(`@page {\\n${pageProps.join('\\n')}\\n}`);\n\t}\n\n\t// WYSIWYG: apply paper-mode document margins to print content\n\tif (options.paperSize) {\n\t\tparts.push(\n\t\t\t`.notectl-content { padding: ${PAPER_MARGIN_TOP_PX}px ${PAPER_MARGIN_HORIZONTAL_PX}px !important; }`,\n\t\t);\n\t}\n\n\t// Print media rules\n\tconst printRules: string[] = [];\n\n\t// Hide non-printable elements\n\tprintRules.push('[data-notectl-no-print] { display: none !important; }');\n\n\t// Code blocks: preserve background, force wrapping\n\tprintRules.push(\n\t\t'.notectl-code-block { white-space: pre-wrap !important; ' +\n\t\t\t'word-break: break-all !important; page-break-inside: avoid; }',\n\t);\n\n\t// Images: avoid page breaks\n\tprintRules.push('img { page-break-inside: avoid; }');\n\n\t// Tables: avoid page breaks\n\tprintRules.push('.notectl-table { break-inside: avoid; }');\n\n\t// Preserve background colors and images in print output (WYSIWYG default).\n\t// Only omitted when the consumer explicitly opts out via printBackground: false.\n\tif (options.printBackground !== false) {\n\t\tprintRules.push(\n\t\t\t'* { -webkit-print-color-adjust: exact !important; ' +\n\t\t\t\t'print-color-adjust: exact !important; }',\n\t\t);\n\t}\n\n\tparts.push(`@media print {\\n ${printRules.join('\\n ')}\\n}`);\n\n\treturn parts.join('\\n\\n');\n}\n\n/** Collects all CSS needed for print: adopted styles, theme tokens, print CSS, and custom CSS. */\nexport function collectAll(\n\tshadowRoot: ShadowRoot,\n\thost: HTMLElement,\n\toptions: PrintOptions,\n): string {\n\tconst parts: string[] = [];\n\n\tconst adopted: string = extractAdoptedStyles(shadowRoot);\n\tif (adopted) parts.push(adopted);\n\n\tconst theme: string = snapshotThemeTokens(host);\n\tif (theme) parts.push(theme);\n\n\t// WYSIWYG: snapshot host typography so the print iframe matches the editor.\n\t// In the editor, .notectl-content inherits font from :host (shadow DOM).\n\t// The print iframe is a regular document where :host doesn't apply.\n\tparts.push(snapshotTypography(host));\n\n\tconst printCSS: string = generatePrintCSS(options);\n\tif (printCSS) parts.push(printCSS);\n\n\tif (options.customCSS) {\n\t\tparts.push(options.customCSS);\n\t}\n\n\treturn parts.join('\\n\\n');\n}\n"],"names":["PRINT_LOCALE_EN","label","tooltip","shortcut","printingAnnouncement","localeModules","assign","import","async","loadPrintLocale","lang","loader","default","resolveContent","value","NOOP_SERVICE","print","toHTML","PrintPlugin","id","name","config","service","locale","constructor","this","init","context","resolveLocale","container","getContainer","rootNode","getRootNode","ShadowRoot","host","eventBus","getEventBus","shadowRoot","mergeOptions","options","executePrint","beforeEvent","cancelled","emit","BEFORE_PRINT","finalOptions","html","css","content","title","replace","join","buildHTMLDocument","parts","adopted","sheet","adoptedStyleSheets","rule","cssRules","push","cssText","extractAdoptedStyles","theme","computed","getComputedStyle","tokens","i","length","prop","startsWith","getPropertyValue","trim","snapshotThemeTokens","props","rules","snapshotTypography","printCSS","pageProps","margin","paperSize","orientation","sizeParts","getPaperCSSSize","PAPER_MARGIN_TOP_PX","PAPER_MARGIN_HORIZONTAL_PX","printRules","printBackground","generatePrintCSS","customCSS","collectAll","clone","querySelector","cloneNode","cloneContent","removeAttribute","selectionClasses","cls","classList","remove","el","querySelectorAll","sanitize","excludeBlockTypes","type","elements","pageBreakBefore","setStyleProperties","breakBefore","applyBlockFilters","header","headerEl","document","createElement","className","innerHTML","insertBefore","firstChild","footer","footerEl","appendChild","insertHeaderFooter","prepare","outerHTML","closest","getAttribute","documentElement","afterEvent","AFTER_PRINT","iframe","setStyleText","body","iframeDoc","contentDocument","removeChild","open","write","close","cleanup","contentWindow","addEventListener","once","createPrintService","registerService","PRINT_SERVICE_KEY","defaults","printLocale","registerCommand","announce","keyBinding","registerKeymap","executeCommand","showToolbarItem","formatShortcut","registerToolbarItem","group","icon","command","destroy"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { MarkAttrRegistry } from '../../model/AttrRegistry.js';
2
2
  import { EditorState } from '../../state/EditorState.js';
3
3
  import { PluginContext } from '../Plugin.js';
4
4
  /** Color mark type names that have `{ color: string }` attrs. */
5
- type ColorMarkType = {
5
+ export type ColorMarkType = {
6
6
  [K in keyof MarkAttrRegistry]: MarkAttrRegistry[K] extends {
7
7
  color: string;
8
8
  } ? K : never;
@@ -24,5 +24,4 @@ export declare function applyColorMark(context: PluginContext, state: EditorStat
24
24
  * Returns `false` when the mark was not present.
25
25
  */
26
26
  export declare function removeColorMark(context: PluginContext, state: EditorState, markTypeName: ColorMarkType): boolean;
27
- export {};
28
27
  //# sourceMappingURL=ColorMarkOperations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ColorMarkOperations.d.ts","sourceRoot":"","sources":["../../../src/plugins/shared/ColorMarkOperations.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,iEAAiE;AACjE,KAAK,aAAa,GAAG;KACnB,CAAC,IAAI,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,SAAS;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK;CACxF,CAAC,MAAM,gBAAgB,CAAC,CAAC;AAE1B;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAE7F;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,GAAG,OAAO,CAE1F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC7B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,WAAW,EAClB,YAAY,EAAE,aAAa,EAC3B,KAAK,EAAE,MAAM,GACX,OAAO,CAST;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,WAAW,EAClB,YAAY,EAAE,aAAa,GACzB,OAAO,CAMT"}
1
+ {"version":3,"file":"ColorMarkOperations.d.ts","sourceRoot":"","sources":["../../../src/plugins/shared/ColorMarkOperations.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG;KAC1B,CAAC,IAAI,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,SAAS;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK;CACxF,CAAC,MAAM,gBAAgB,CAAC,CAAC;AAE1B;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAE7F;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,GAAG,OAAO,CAE1F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC7B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,WAAW,EAClB,YAAY,EAAE,aAAa,EAC3B,KAAK,EAAE,MAAM,GACX,OAAO,CAST;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,WAAW,EAClB,YAAY,EAAE,aAAa,GACzB,OAAO,CAMT"}
@@ -1,12 +1,6 @@
1
- import { MarkAttrRegistry } from '../../model/AttrRegistry.js';
2
1
  import { PluginContext } from '../Plugin.js';
2
+ import { ColorMarkType } from './ColorMarkOperations.js';
3
3
  import { PopupCloseOptions } from './PopupManager.js';
4
- /** Color mark type names that have `{ color: string }` attrs. */
5
- type ColorMarkType = {
6
- [K in keyof MarkAttrRegistry]: MarkAttrRegistry[K] extends {
7
- color: string;
8
- } ? K : never;
9
- }[keyof MarkAttrRegistry];
10
4
  /** Configuration for `renderColorPickerPopup`. */
11
5
  export interface ColorPickerConfig {
12
6
  readonly markType: ColorMarkType;
@@ -28,5 +22,4 @@ export interface ColorPickerConfig {
28
22
  * - Roving tabindex on swatches
29
23
  */
30
24
  export declare function renderColorPickerPopup(container: HTMLElement, context: PluginContext, config: ColorPickerConfig): void;
31
- export {};
32
25
  //# sourceMappingURL=ColorPickerPopup.d.ts.map