@notectl/core 2.2.6 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. package/README.md +1 -1
  2. package/THIRD-PARTY-NOTICES.md +129 -0
  3. package/dist/chunks/{AlignmentPlugin-DeD4C4EP.mjs → AlignmentPlugin-C9Rr_R-g.mjs} +2 -2
  4. package/dist/chunks/{AlignmentPlugin-DeD4C4EP.mjs.map → AlignmentPlugin-C9Rr_R-g.mjs.map} +1 -1
  5. package/dist/chunks/{AttrRegistry-DcDVyzLm.mjs → AttrRegistry-B3zB02z9.mjs} +2 -2
  6. package/dist/chunks/AttrRegistry-B3zB02z9.mjs.map +1 -0
  7. package/dist/chunks/AttributedMarkCommands-BCvmqeFZ.mjs +2 -0
  8. package/dist/chunks/{AttributedMarkCommands-D4W2Jgpj.mjs.map → AttributedMarkCommands-BCvmqeFZ.mjs.map} +1 -1
  9. package/dist/chunks/{BidiIsolationPlugin-BddRbDCN.mjs → BidiIsolationPlugin-Cw2KMk-H.mjs} +2 -2
  10. package/dist/chunks/{BidiIsolationPlugin-BddRbDCN.mjs.map → BidiIsolationPlugin-Cw2KMk-H.mjs.map} +1 -1
  11. package/dist/chunks/BlockInsertion-CYH2gRkY.mjs +2 -0
  12. package/dist/chunks/BlockInsertion-CYH2gRkY.mjs.map +1 -0
  13. package/dist/chunks/BlockquotePlugin-0bZSbkyo.mjs +2 -0
  14. package/dist/chunks/{BlockquotePlugin-4V7KV_Sb.mjs.map → BlockquotePlugin-0bZSbkyo.mjs.map} +1 -1
  15. package/dist/chunks/CaretNavigationPlugin-BPZ9b6XR.mjs +2 -0
  16. package/dist/chunks/CaretNavigationPlugin-BPZ9b6XR.mjs.map +1 -0
  17. package/dist/chunks/CodeBlockPlugin-BCJ3faXx.mjs +2 -0
  18. package/dist/chunks/CodeBlockPlugin-BCJ3faXx.mjs.map +1 -0
  19. package/dist/chunks/{ColorGrid-DPNiXxpD.mjs → ColorGrid-DQEkJ-0y.mjs} +2 -2
  20. package/dist/chunks/{ColorGrid-DPNiXxpD.mjs.map → ColorGrid-DQEkJ-0y.mjs.map} +1 -1
  21. package/dist/chunks/{ColorPickerPopup-lcf3jS6G.mjs → ColorPickerPopup-CyF26zIU.mjs} +2 -2
  22. package/dist/chunks/{ColorPickerPopup-lcf3jS6G.mjs.map → ColorPickerPopup-CyF26zIU.mjs.map} +1 -1
  23. package/dist/chunks/Commands-D5ND50PQ.mjs +2 -0
  24. package/dist/chunks/Commands-D5ND50PQ.mjs.map +1 -0
  25. package/dist/chunks/ContentModel-NpAj7vGW.mjs +2 -0
  26. package/dist/chunks/ContentModel-NpAj7vGW.mjs.map +1 -0
  27. package/dist/chunks/Decoration-BOP1TAUd.mjs +2 -0
  28. package/dist/chunks/Decoration-BOP1TAUd.mjs.map +1 -0
  29. package/dist/chunks/{DirectionDetection-C7XE0nxW.mjs → DirectionDetection-CDVSEWQ6.mjs} +2 -2
  30. package/dist/chunks/{DirectionDetection-C7XE0nxW.mjs.map → DirectionDetection-CDVSEWQ6.mjs.map} +1 -1
  31. package/dist/chunks/Document-827l3P80.mjs +2 -0
  32. package/dist/chunks/Document-827l3P80.mjs.map +1 -0
  33. package/dist/chunks/DocumentParser-D2tr3ZKn.mjs +2 -0
  34. package/dist/chunks/DocumentParser-D2tr3ZKn.mjs.map +1 -0
  35. package/dist/chunks/EditorEventBoundary-zpYRxryo.mjs +2 -0
  36. package/dist/chunks/EditorEventBoundary-zpYRxryo.mjs.map +1 -0
  37. package/dist/chunks/{FontPlugin-DQMj65Bc.mjs → FontPlugin-D041tiLe.mjs} +2 -2
  38. package/dist/chunks/{FontPlugin-DQMj65Bc.mjs.map → FontPlugin-D041tiLe.mjs.map} +1 -1
  39. package/dist/chunks/{FontSizePlugin-9StCjEfN.mjs → FontSizePlugin-8CAvj1RD.mjs} +2 -2
  40. package/dist/chunks/FontSizePlugin-8CAvj1RD.mjs.map +1 -0
  41. package/dist/chunks/FormulaPlugin-DJ39BtqV.mjs +2 -0
  42. package/dist/chunks/FormulaPlugin-DJ39BtqV.mjs.map +1 -0
  43. package/dist/chunks/GapCursorNavigation-DCWOmopl.mjs +2 -0
  44. package/dist/chunks/{GapCursorNavigation-ycNzuQVH.mjs.map → GapCursorNavigation-DCWOmopl.mjs.map} +1 -1
  45. package/dist/chunks/GapCursorPlugin-2iR6506y.mjs +2 -0
  46. package/dist/chunks/{GapCursorPlugin-Zvxjnr82.mjs.map → GapCursorPlugin-2iR6506y.mjs.map} +1 -1
  47. package/dist/chunks/HTMLUtils-Bhg3_P8B.mjs +2 -0
  48. package/dist/chunks/HTMLUtils-Bhg3_P8B.mjs.map +1 -0
  49. package/dist/chunks/{HardBreakPlugin-9DOyCyyM.mjs → HardBreakPlugin-vniSvTgq.mjs} +2 -2
  50. package/dist/chunks/{HardBreakPlugin-9DOyCyyM.mjs.map → HardBreakPlugin-vniSvTgq.mjs.map} +1 -1
  51. package/dist/chunks/HeadingPlugin-DUKsLuMd.mjs +2 -0
  52. package/dist/chunks/{HeadingPlugin-BuGoM9Rz.mjs.map → HeadingPlugin-DUKsLuMd.mjs.map} +1 -1
  53. package/dist/chunks/{HighlightPlugin-C6pHifVz.mjs → HighlightPlugin-DRTAE1N5.mjs} +2 -2
  54. package/dist/chunks/{HighlightPlugin-C6pHifVz.mjs.map → HighlightPlugin-DRTAE1N5.mjs.map} +1 -1
  55. package/dist/chunks/HorizontalRulePlugin-B9OvwrKB.mjs +2 -0
  56. package/dist/chunks/HorizontalRulePlugin-B9OvwrKB.mjs.map +1 -0
  57. package/dist/chunks/ImagePlugin-CwxTRr6d.mjs +2 -0
  58. package/dist/chunks/{ImagePlugin-KpkuE2LH.mjs.map → ImagePlugin-CwxTRr6d.mjs.map} +1 -1
  59. package/dist/chunks/{InlineCodePlugin-DMr4O7c7.mjs → InlineCodePlugin-uxgMUX_E.mjs} +2 -2
  60. package/dist/chunks/InlineCodePlugin-uxgMUX_E.mjs.map +1 -0
  61. package/dist/chunks/InlineStyleMarkSpec-CjSRj4f_.mjs +2 -0
  62. package/dist/chunks/{InlineStyleMarkSpec-C6LJT7kp.mjs.map → InlineStyleMarkSpec-CjSRj4f_.mjs.map} +1 -1
  63. package/dist/chunks/LinkPlugin-CvWHbSkb.mjs +2 -0
  64. package/dist/chunks/LinkPlugin-CvWHbSkb.mjs.map +1 -0
  65. package/dist/chunks/ListPlugin-BchSFWVn.mjs +2 -0
  66. package/dist/chunks/ListPlugin-BchSFWVn.mjs.map +1 -0
  67. package/dist/chunks/MarkInputRule-Bdi8KPus.mjs +2 -0
  68. package/dist/chunks/MarkInputRule-Bdi8KPus.mjs.map +1 -0
  69. package/dist/chunks/MarkdownHTMLRegistry-Q7l0d6Ma.mjs +2 -0
  70. package/dist/chunks/MarkdownHTMLRegistry-Q7l0d6Ma.mjs.map +1 -0
  71. package/dist/chunks/MarkdownParser-Dp62mfUq.mjs +2 -0
  72. package/dist/chunks/MarkdownParser-Dp62mfUq.mjs.map +1 -0
  73. package/dist/chunks/MarkdownSerializer-DBELFAeo.mjs +2 -0
  74. package/dist/chunks/MarkdownSerializer-DBELFAeo.mjs.map +1 -0
  75. package/dist/chunks/MathFont-BS8IwYh2.mjs +2 -0
  76. package/dist/chunks/MathFont-BS8IwYh2.mjs.map +1 -0
  77. package/dist/chunks/{NodeResolver-ChgLF_IP.mjs → NodeResolver-Dleih-8R.mjs} +2 -2
  78. package/dist/chunks/{NodeResolver-ChgLF_IP.mjs.map → NodeResolver-Dleih-8R.mjs.map} +1 -1
  79. package/dist/chunks/NodeSelectionCommands-WH5snxr_.mjs +2 -0
  80. package/dist/chunks/{NodeSelectionCommands-Dj4VxLdD.mjs.map → NodeSelectionCommands-WH5snxr_.mjs.map} +1 -1
  81. package/dist/chunks/{PopupManager-DUtaK3WX.mjs → PopupManager-Cj86uDEB.mjs} +2 -2
  82. package/dist/chunks/{PopupManager-DUtaK3WX.mjs.map → PopupManager-Cj86uDEB.mjs.map} +1 -1
  83. package/dist/chunks/PopupPositioning-BFh6Ed1D.mjs +2 -0
  84. package/dist/chunks/{PopupPositioning-BB97-__N.mjs.map → PopupPositioning-BFh6Ed1D.mjs.map} +1 -1
  85. package/dist/chunks/PrintPlugin-D2javl_d.mjs +2 -0
  86. package/dist/chunks/PrintPlugin-D2javl_d.mjs.map +1 -0
  87. package/dist/chunks/{RangeIterator-o8v3msQe.mjs → RangeIterator-DP7Ud3Gp.mjs} +2 -2
  88. package/dist/chunks/{RangeIterator-o8v3msQe.mjs.map → RangeIterator-DP7Ud3Gp.mjs.map} +1 -1
  89. package/dist/chunks/SchemaRegistry-CkBN-1yW.mjs +2 -0
  90. package/dist/chunks/SchemaRegistry-CkBN-1yW.mjs.map +1 -0
  91. package/dist/chunks/SimpleMark-gTQaSJcO.mjs +2 -0
  92. package/dist/chunks/{SimpleMark-CaQtFAau.mjs.map → SimpleMark-gTQaSJcO.mjs.map} +1 -1
  93. package/dist/chunks/SmartPastePlugin-BvJQ-fOz.mjs +2 -0
  94. package/dist/chunks/SmartPastePlugin-BvJQ-fOz.mjs.map +1 -0
  95. package/dist/chunks/StarterFonts-BDQPg-cu.mjs +2 -0
  96. package/dist/chunks/StarterFonts-BDQPg-cu.mjs.map +1 -0
  97. package/dist/chunks/StrikethroughPlugin-BdrG1TTY.mjs +2 -0
  98. package/dist/chunks/StrikethroughPlugin-BdrG1TTY.mjs.map +1 -0
  99. package/dist/chunks/StyleRuntime-DW6omotc.mjs +2 -0
  100. package/dist/chunks/StyleRuntime-DW6omotc.mjs.map +1 -0
  101. package/dist/chunks/{SuperSubPlugin-DVP7VnIz.mjs → SuperSubPlugin-DTZB0Y3D.mjs} +2 -2
  102. package/dist/chunks/{SuperSubPlugin-DVP7VnIz.mjs.map → SuperSubPlugin-DTZB0Y3D.mjs.map} +1 -1
  103. package/dist/chunks/TableDimensions-BBhjHNjQ.mjs +2 -0
  104. package/dist/chunks/TableDimensions-BBhjHNjQ.mjs.map +1 -0
  105. package/dist/chunks/TablePlugin-CPvg9YZS.mjs +2 -0
  106. package/dist/chunks/TablePlugin-CPvg9YZS.mjs.map +1 -0
  107. package/dist/chunks/TextColorPlugin-Ckg3KWvb.mjs +2 -0
  108. package/dist/chunks/{TextColorPlugin-CEfZQ6Md.mjs.map → TextColorPlugin-Ckg3KWvb.mjs.map} +1 -1
  109. package/dist/chunks/TextDirectionAutoPlugin-DRGbgTlx.mjs +2 -0
  110. package/dist/chunks/{TextDirectionAutoPlugin-CzWJjrvG.mjs.map → TextDirectionAutoPlugin-DRGbgTlx.mjs.map} +1 -1
  111. package/dist/chunks/TextDirectionPlugin-BCeYyJHo.mjs +2 -0
  112. package/dist/chunks/{TextDirectionPlugin-DHB88HKf.mjs.map → TextDirectionPlugin-BCeYyJHo.mjs.map} +1 -1
  113. package/dist/chunks/TextFormattingPlugin-BhRxSC8q.mjs +2 -0
  114. package/dist/chunks/TextFormattingPlugin-BhRxSC8q.mjs.map +1 -0
  115. package/dist/chunks/ThemeEngine-BUVo_zaT.mjs +3 -0
  116. package/dist/chunks/ThemeEngine-BUVo_zaT.mjs.map +1 -0
  117. package/dist/chunks/ToolbarPlugin-dmTj1jIz.mjs +2 -0
  118. package/dist/chunks/{ToolbarPlugin-DVGrFf8v.mjs.map → ToolbarPlugin-dmTj1jIz.mjs.map} +1 -1
  119. package/dist/chunks/VideoPlugin-BugkI7-m.mjs +2 -0
  120. package/dist/chunks/VideoPlugin-BugkI7-m.mjs.map +1 -0
  121. package/dist/chunks/WordBoundary-CFpIJDNP.mjs +2 -0
  122. package/dist/chunks/{WordBoundary-DxeMBRyP.mjs.map → WordBoundary-CFpIJDNP.mjs.map} +1 -1
  123. package/dist/chunks/XmlSupport-DIXH5on9.mjs +2 -0
  124. package/dist/chunks/XmlSupport-DIXH5on9.mjs.map +1 -0
  125. package/dist/chunks/ar-Dg9PdDet.mjs +2 -0
  126. package/dist/chunks/ar-Dg9PdDet.mjs.map +1 -0
  127. package/dist/chunks/ar-eOA3UmiE.mjs +2 -0
  128. package/dist/chunks/{ar-BTShmP2E.mjs.map → ar-eOA3UmiE.mjs.map} +1 -1
  129. package/dist/chunks/de-DJ5EkXQo.mjs +2 -0
  130. package/dist/chunks/de-DJ5EkXQo.mjs.map +1 -0
  131. package/dist/chunks/{de-C--bRmjW.mjs → de-DRbhnS4T.mjs} +2 -2
  132. package/dist/chunks/{de-C--bRmjW.mjs.map → de-DRbhnS4T.mjs.map} +1 -1
  133. package/dist/chunks/{es-DFUVd7eO.mjs → es-BQ9dox_E.mjs} +2 -2
  134. package/dist/chunks/{es-DFUVd7eO.mjs.map → es-BQ9dox_E.mjs.map} +1 -1
  135. package/dist/chunks/es-CEAJj7aB.mjs +2 -0
  136. package/dist/chunks/es-CEAJj7aB.mjs.map +1 -0
  137. package/dist/chunks/fr-DhWQzZy3.mjs +2 -0
  138. package/dist/chunks/fr-DhWQzZy3.mjs.map +1 -0
  139. package/dist/chunks/{fr-BaXKyPmX.mjs → fr-NVOinLyF.mjs} +2 -2
  140. package/dist/chunks/{fr-BaXKyPmX.mjs.map → fr-NVOinLyF.mjs.map} +1 -1
  141. package/dist/chunks/full-JM0-SwWy.mjs +2 -0
  142. package/dist/chunks/{full-BBl7mvwH.mjs.map → full-JM0-SwWy.mjs.map} +1 -1
  143. package/dist/chunks/hi-BsZzSMfL.mjs +2 -0
  144. package/dist/chunks/hi-BsZzSMfL.mjs.map +1 -0
  145. package/dist/chunks/{hi-aH9HZG23.mjs → hi-DrC2H81d.mjs} +2 -2
  146. package/dist/chunks/{hi-aH9HZG23.mjs.map → hi-DrC2H81d.mjs.map} +1 -1
  147. package/dist/chunks/minimal-DSlR2A27.mjs +2 -0
  148. package/dist/chunks/{minimal-CtnR4dqp.mjs.map → minimal-DSlR2A27.mjs.map} +1 -1
  149. package/dist/chunks/pt-BuZ7acHF.mjs +2 -0
  150. package/dist/chunks/pt-BuZ7acHF.mjs.map +1 -0
  151. package/dist/chunks/{pt-Hy-0Xnnc.mjs → pt-CFrcl1v_.mjs} +2 -2
  152. package/dist/chunks/{pt-Hy-0Xnnc.mjs.map → pt-CFrcl1v_.mjs.map} +1 -1
  153. package/dist/chunks/register-BjsdJ3Aq.mjs +2 -0
  154. package/dist/chunks/register-BjsdJ3Aq.mjs.map +1 -0
  155. package/dist/chunks/rolldown-runtime-H_PjY6_i.mjs +1 -0
  156. package/dist/chunks/ru-CsP6mLxp.mjs +2 -0
  157. package/dist/chunks/ru-CsP6mLxp.mjs.map +1 -0
  158. package/dist/chunks/{ru-BFpEOrVp.mjs → ru-gxbzqLL8.mjs} +2 -2
  159. package/dist/chunks/{ru-BFpEOrVp.mjs.map → ru-gxbzqLL8.mjs.map} +1 -1
  160. package/dist/chunks/src-5GKFQ2mQ.mjs +2 -0
  161. package/dist/chunks/src-5GKFQ2mQ.mjs.map +1 -0
  162. package/dist/chunks/xml-BsV44TrJ.mjs +2 -0
  163. package/dist/chunks/xml-BsV44TrJ.mjs.map +1 -0
  164. package/dist/chunks/zh-BFZOM3lF.mjs +2 -0
  165. package/dist/chunks/{zh-BjoyjClN.mjs.map → zh-BFZOM3lF.mjs.map} +1 -1
  166. package/dist/chunks/zh-CiIyOm6U.mjs +2 -0
  167. package/dist/chunks/zh-CiIyOm6U.mjs.map +1 -0
  168. package/dist/commands/BlockInsertion.d.ts +5 -3
  169. package/dist/commands/BlockInsertion.d.ts.map +1 -1
  170. package/dist/commands/SelectionDeletion.d.ts +13 -2
  171. package/dist/commands/SelectionDeletion.d.ts.map +1 -1
  172. package/dist/editor/ContentSerializer.d.ts +21 -0
  173. package/dist/editor/ContentSerializer.d.ts.map +1 -1
  174. package/dist/editor/EditorConfig.d.ts +17 -0
  175. package/dist/editor/EditorConfig.d.ts.map +1 -1
  176. package/dist/editor/EditorConfigController.d.ts +10 -0
  177. package/dist/editor/EditorConfigController.d.ts.map +1 -1
  178. package/dist/editor/EditorInitializer.d.ts +4 -0
  179. package/dist/editor/EditorInitializer.d.ts.map +1 -1
  180. package/dist/editor/EditorLocale.d.ts +2 -0
  181. package/dist/editor/EditorLocale.d.ts.map +1 -1
  182. package/dist/editor/MarkdownMode.d.ts +46 -0
  183. package/dist/editor/MarkdownMode.d.ts.map +1 -0
  184. package/dist/editor/NotectlEditor.d.ts +24 -0
  185. package/dist/editor/NotectlEditor.d.ts.map +1 -1
  186. package/dist/editor/locales/ar.d.ts.map +1 -1
  187. package/dist/editor/locales/de.d.ts.map +1 -1
  188. package/dist/editor/locales/es.d.ts.map +1 -1
  189. package/dist/editor/locales/fr.d.ts.map +1 -1
  190. package/dist/editor/locales/hi.d.ts.map +1 -1
  191. package/dist/editor/locales/pt.d.ts.map +1 -1
  192. package/dist/editor/locales/ru.d.ts.map +1 -1
  193. package/dist/editor/locales/zh.d.ts.map +1 -1
  194. package/dist/editor/styles/list.d.ts +1 -1
  195. package/dist/editor/styles/list.d.ts.map +1 -1
  196. package/dist/editor/styles/table.d.ts +1 -1
  197. package/dist/editor/styles/table.d.ts.map +1 -1
  198. package/dist/fonts/math.d.ts +3 -0
  199. package/dist/fonts/math.d.ts.map +1 -0
  200. package/dist/fonts/math.mjs +1 -0
  201. package/dist/fonts/starter.d.ts +3 -0
  202. package/dist/fonts/starter.d.ts.map +1 -0
  203. package/dist/fonts/starter.mjs +1 -0
  204. package/dist/fonts.d.ts +4 -4
  205. package/dist/fonts.mjs +1 -1
  206. package/dist/full.d.ts +1 -1
  207. package/dist/full.mjs +1 -1
  208. package/dist/html.d.ts +1 -0
  209. package/dist/html.d.ts.map +1 -1
  210. package/dist/html.mjs +1 -1
  211. package/dist/index.d.ts +7 -6
  212. package/dist/index.d.ts.map +1 -1
  213. package/dist/input/ClipboardHandler.d.ts +2 -0
  214. package/dist/input/ClipboardHandler.d.ts.map +1 -1
  215. package/dist/input/InputHandler.d.ts +7 -0
  216. package/dist/input/InputHandler.d.ts.map +1 -1
  217. package/dist/input/InputManager.d.ts +10 -0
  218. package/dist/input/InputManager.d.ts.map +1 -1
  219. package/dist/input/KeyboardHandler.d.ts.map +1 -1
  220. package/dist/input/MarkdownPasteDetector.d.ts +26 -0
  221. package/dist/input/MarkdownPasteDetector.d.ts.map +1 -0
  222. package/dist/input/PasteHTMLHandler.d.ts +18 -1
  223. package/dist/input/PasteHTMLHandler.d.ts.map +1 -1
  224. package/dist/input/PasteHandler.d.ts +30 -0
  225. package/dist/input/PasteHandler.d.ts.map +1 -1
  226. package/dist/input/PasteRichBlockHandler.d.ts.map +1 -1
  227. package/dist/input/SelectionDocument.d.ts +2 -1
  228. package/dist/input/SelectionDocument.d.ts.map +1 -1
  229. package/dist/markdown.d.ts +17 -0
  230. package/dist/markdown.d.ts.map +1 -0
  231. package/dist/markdown.mjs +1 -0
  232. package/dist/model/AttrRegistry.d.ts +2 -2
  233. package/dist/model/AttrRegistry.d.ts.map +1 -1
  234. package/dist/model/ContentModel.d.ts +12 -0
  235. package/dist/model/ContentModel.d.ts.map +1 -1
  236. package/dist/model/Document.d.ts +28 -3
  237. package/dist/model/Document.d.ts.map +1 -1
  238. package/dist/model/HTMLUtils.d.ts +15 -0
  239. package/dist/model/HTMLUtils.d.ts.map +1 -1
  240. package/dist/model/InlineNodeSpec.d.ts +7 -1
  241. package/dist/model/InlineNodeSpec.d.ts.map +1 -1
  242. package/dist/model/InputRule.d.ts +11 -0
  243. package/dist/model/InputRule.d.ts.map +1 -1
  244. package/dist/model/MarkSpec.d.ts +7 -1
  245. package/dist/model/MarkSpec.d.ts.map +1 -1
  246. package/dist/model/MarkdownSyntaxRegistry.d.ts +51 -0
  247. package/dist/model/MarkdownSyntaxRegistry.d.ts.map +1 -0
  248. package/dist/model/NodeSpec.d.ts +47 -1
  249. package/dist/model/NodeSpec.d.ts.map +1 -1
  250. package/dist/model/RichBlockData.d.ts +2 -0
  251. package/dist/model/RichBlockData.d.ts.map +1 -1
  252. package/dist/model/SchemaRegistry.d.ts.map +1 -1
  253. package/dist/model/TableDimensions.d.ts +11 -0
  254. package/dist/model/TableDimensions.d.ts.map +1 -0
  255. package/dist/notectl-core.mjs +1 -1
  256. package/dist/notectl-core.umd.js +1 -1
  257. package/dist/notectl-core.umd.js.map +1 -1
  258. package/dist/platform/EditorEventBoundary.d.ts +12 -0
  259. package/dist/platform/EditorEventBoundary.d.ts.map +1 -0
  260. package/dist/plugins/Plugin.d.ts +7 -0
  261. package/dist/plugins/Plugin.d.ts.map +1 -1
  262. package/dist/plugins/PluginContextFactory.d.ts +2 -0
  263. package/dist/plugins/PluginContextFactory.d.ts.map +1 -1
  264. package/dist/plugins/PluginManager.d.ts +2 -0
  265. package/dist/plugins/PluginManager.d.ts.map +1 -1
  266. package/dist/plugins/alignment.mjs +1 -1
  267. package/dist/plugins/bidi-isolation.mjs +1 -1
  268. package/dist/plugins/blockquote/BlockquotePlugin.d.ts +2 -0
  269. package/dist/plugins/blockquote/BlockquotePlugin.d.ts.map +1 -1
  270. package/dist/plugins/blockquote.mjs +1 -1
  271. package/dist/plugins/caret-navigation.mjs +1 -1
  272. package/dist/plugins/code-block/CodeBlockHighlighting.d.ts.map +1 -1
  273. package/dist/plugins/code-block/CodeBlockTypes.d.ts +2 -0
  274. package/dist/plugins/code-block/CodeBlockTypes.d.ts.map +1 -1
  275. package/dist/plugins/code-block.mjs +1 -1
  276. package/dist/plugins/font-size/FontSizeOperations.d.ts.map +1 -1
  277. package/dist/plugins/font-size.mjs +1 -1
  278. package/dist/plugins/font.mjs +1 -1
  279. package/dist/plugins/formula/DisplayMathNodeSpec.d.ts.map +1 -1
  280. package/dist/plugins/formula/FormulaInputRules.d.ts.map +1 -1
  281. package/dist/plugins/formula/FormulaMarkdownSyntax.d.ts +4 -0
  282. package/dist/plugins/formula/FormulaMarkdownSyntax.d.ts.map +1 -0
  283. package/dist/plugins/formula/FormulaPlugin.d.ts.map +1 -1
  284. package/dist/plugins/formula/FormulaTypes.d.ts +3 -1
  285. package/dist/plugins/formula/FormulaTypes.d.ts.map +1 -1
  286. package/dist/plugins/formula/InlineMathNodeSpec.d.ts.map +1 -1
  287. package/dist/plugins/formula.mjs +1 -1
  288. package/dist/plugins/gap-cursor.mjs +1 -1
  289. package/dist/plugins/hard-break.mjs +1 -1
  290. package/dist/plugins/heading/HeadingPlugin.d.ts +2 -0
  291. package/dist/plugins/heading/HeadingPlugin.d.ts.map +1 -1
  292. package/dist/plugins/heading.mjs +1 -1
  293. package/dist/plugins/highlight.mjs +1 -1
  294. package/dist/plugins/horizontal-rule/HorizontalRulePlugin.d.ts +2 -0
  295. package/dist/plugins/horizontal-rule/HorizontalRulePlugin.d.ts.map +1 -1
  296. package/dist/plugins/horizontal-rule.mjs +1 -1
  297. package/dist/plugins/image/ImagePlugin.d.ts +14 -0
  298. package/dist/plugins/image/ImagePlugin.d.ts.map +1 -1
  299. package/dist/plugins/image.mjs +1 -1
  300. package/dist/plugins/inline-code/InlineCodePlugin.d.ts.map +1 -1
  301. package/dist/plugins/inline-code.mjs +1 -1
  302. package/dist/plugins/language.mjs +1 -1
  303. package/dist/plugins/link/LinkPlugin.d.ts +14 -0
  304. package/dist/plugins/link/LinkPlugin.d.ts.map +1 -1
  305. package/dist/plugins/link.mjs +1 -1
  306. package/dist/plugins/list/ListCommands.d.ts +5 -1
  307. package/dist/plugins/list/ListCommands.d.ts.map +1 -1
  308. package/dist/plugins/list/ListInputRules.d.ts.map +1 -1
  309. package/dist/plugins/list/ListItemContext.d.ts +27 -0
  310. package/dist/plugins/list/ListItemContext.d.ts.map +1 -0
  311. package/dist/plugins/list/ListKeyboardHandlers.d.ts.map +1 -1
  312. package/dist/plugins/list/ListPlugin.d.ts +2 -0
  313. package/dist/plugins/list/ListPlugin.d.ts.map +1 -1
  314. package/dist/plugins/list/ListToolbarItems.d.ts.map +1 -1
  315. package/dist/plugins/list.mjs +1 -1
  316. package/dist/plugins/print/PrintContentPreparer.d.ts.map +1 -1
  317. package/dist/plugins/print/PrintDestinationBridge.d.ts +23 -0
  318. package/dist/plugins/print/PrintDestinationBridge.d.ts.map +1 -0
  319. package/dist/plugins/print/PrintHostStyles.d.ts.map +1 -1
  320. package/dist/plugins/print/PrintServiceImpl.d.ts +5 -1
  321. package/dist/plugins/print/PrintServiceImpl.d.ts.map +1 -1
  322. package/dist/plugins/print/PrintStyleCollector.d.ts.map +1 -1
  323. package/dist/plugins/print.mjs +1 -1
  324. package/dist/plugins/shared/MarkInputRule.d.ts +9 -0
  325. package/dist/plugins/shared/MarkInputRule.d.ts.map +1 -0
  326. package/dist/plugins/shared/PopupPositioning.d.ts +2 -0
  327. package/dist/plugins/shared/PopupPositioning.d.ts.map +1 -1
  328. package/dist/plugins/shared/index.d.ts +1 -0
  329. package/dist/plugins/shared/index.d.ts.map +1 -1
  330. package/dist/plugins/shared.mjs +1 -1
  331. package/dist/plugins/smart-paste/SmartPastePlugin.d.ts.map +1 -1
  332. package/dist/plugins/smart-paste.mjs +1 -1
  333. package/dist/plugins/strikethrough/StrikethroughPlugin.d.ts +2 -0
  334. package/dist/plugins/strikethrough/StrikethroughPlugin.d.ts.map +1 -1
  335. package/dist/plugins/strikethrough.mjs +1 -1
  336. package/dist/plugins/super-sub.mjs +1 -1
  337. package/dist/plugins/table/TableClipboard.d.ts +8 -0
  338. package/dist/plugins/table/TableClipboard.d.ts.map +1 -0
  339. package/dist/plugins/table/TableCommands.d.ts.map +1 -1
  340. package/dist/plugins/table/TableContextMenu.d.ts +11 -1
  341. package/dist/plugins/table/TableContextMenu.d.ts.map +1 -1
  342. package/dist/plugins/table/TableControls.d.ts +6 -1
  343. package/dist/plugins/table/TableControls.d.ts.map +1 -1
  344. package/dist/plugins/table/TableControlsDOM.d.ts +11 -2
  345. package/dist/plugins/table/TableControlsDOM.d.ts.map +1 -1
  346. package/dist/plugins/table/TableControlsLayout.d.ts +12 -3
  347. package/dist/plugins/table/TableControlsLayout.d.ts.map +1 -1
  348. package/dist/plugins/table/TableGrid.d.ts +57 -0
  349. package/dist/plugins/table/TableGrid.d.ts.map +1 -0
  350. package/dist/plugins/table/TableHelpers.d.ts +4 -0
  351. package/dist/plugins/table/TableHelpers.d.ts.map +1 -1
  352. package/dist/plugins/table/TableLocale.d.ts +30 -0
  353. package/dist/plugins/table/TableLocale.d.ts.map +1 -1
  354. package/dist/plugins/table/TableNavigation.d.ts +5 -1
  355. package/dist/plugins/table/TableNavigation.d.ts.map +1 -1
  356. package/dist/plugins/table/TableNodeViews.d.ts +13 -1
  357. package/dist/plugins/table/TableNodeViews.d.ts.map +1 -1
  358. package/dist/plugins/table/TablePlugin.d.ts +21 -1
  359. package/dist/plugins/table/TablePlugin.d.ts.map +1 -1
  360. package/dist/plugins/table/TableSelection.d.ts.map +1 -1
  361. package/dist/plugins/table/TableSizeEditor.d.ts +11 -0
  362. package/dist/plugins/table/TableSizeEditor.d.ts.map +1 -0
  363. package/dist/plugins/table/TableSizing.d.ts +70 -0
  364. package/dist/plugins/table/TableSizing.d.ts.map +1 -0
  365. package/dist/plugins/table/index.d.ts +3 -1
  366. package/dist/plugins/table/index.d.ts.map +1 -1
  367. package/dist/plugins/table/locales/ar.d.ts.map +1 -1
  368. package/dist/plugins/table/locales/de.d.ts.map +1 -1
  369. package/dist/plugins/table/locales/es.d.ts.map +1 -1
  370. package/dist/plugins/table/locales/fr.d.ts.map +1 -1
  371. package/dist/plugins/table/locales/hi.d.ts.map +1 -1
  372. package/dist/plugins/table/locales/pt.d.ts.map +1 -1
  373. package/dist/plugins/table/locales/ru.d.ts.map +1 -1
  374. package/dist/plugins/table/locales/zh.d.ts.map +1 -1
  375. package/dist/plugins/table.mjs +1 -1
  376. package/dist/plugins/text-color.mjs +1 -1
  377. package/dist/plugins/text-direction-auto.mjs +1 -1
  378. package/dist/plugins/text-direction.mjs +1 -1
  379. package/dist/plugins/text-formatting/TextFormattingPlugin.d.ts +9 -0
  380. package/dist/plugins/text-formatting/TextFormattingPlugin.d.ts.map +1 -1
  381. package/dist/plugins/text-formatting.mjs +1 -1
  382. package/dist/plugins/toolbar.mjs +1 -1
  383. package/dist/plugins/video/VideoCommands.d.ts.map +1 -1
  384. package/dist/plugins/video.mjs +1 -1
  385. package/dist/presets/full.d.ts +1 -1
  386. package/dist/presets/full.mjs +1 -1
  387. package/dist/presets/minimal.d.ts +1 -1
  388. package/dist/presets/minimal.mjs +1 -1
  389. package/dist/presets.d.ts +1 -1
  390. package/dist/presets.mjs +1 -1
  391. package/dist/register.d.ts +3 -0
  392. package/dist/register.d.ts.map +1 -0
  393. package/dist/register.mjs +1 -0
  394. package/dist/serialization/DocumentParser.d.ts.map +1 -1
  395. package/dist/serialization/DocumentSerializer.d.ts +2 -0
  396. package/dist/serialization/DocumentSerializer.d.ts.map +1 -1
  397. package/dist/serialization/HTMLSanitization.d.ts +15 -0
  398. package/dist/serialization/HTMLSanitization.d.ts.map +1 -0
  399. package/dist/serialization/MarkSerializer.d.ts +12 -0
  400. package/dist/serialization/MarkSerializer.d.ts.map +1 -1
  401. package/dist/serialization/MarkdownParser.d.ts +6 -0
  402. package/dist/serialization/MarkdownParser.d.ts.map +1 -0
  403. package/dist/serialization/MarkdownSerializer.d.ts +12 -0
  404. package/dist/serialization/MarkdownSerializer.d.ts.map +1 -0
  405. package/dist/serialization/MarkdownTypes.d.ts +59 -0
  406. package/dist/serialization/MarkdownTypes.d.ts.map +1 -0
  407. package/dist/serialization/TableDimensions.d.ts +37 -0
  408. package/dist/serialization/TableDimensions.d.ts.map +1 -0
  409. package/dist/serialization/markdown/BlockSerializers.d.ts +7 -0
  410. package/dist/serialization/markdown/BlockSerializers.d.ts.map +1 -0
  411. package/dist/serialization/markdown/BlockTokenizer.d.ts +54 -0
  412. package/dist/serialization/markdown/BlockTokenizer.d.ts.map +1 -0
  413. package/dist/serialization/markdown/GfmAutolink.d.ts +20 -0
  414. package/dist/serialization/markdown/GfmAutolink.d.ts.map +1 -0
  415. package/dist/serialization/markdown/GfmTableParser.d.ts +26 -0
  416. package/dist/serialization/markdown/GfmTableParser.d.ts.map +1 -0
  417. package/dist/serialization/markdown/InlineAst.d.ts +34 -0
  418. package/dist/serialization/markdown/InlineAst.d.ts.map +1 -0
  419. package/dist/serialization/markdown/InlineSerializers.d.ts +5 -0
  420. package/dist/serialization/markdown/InlineSerializers.d.ts.map +1 -0
  421. package/dist/serialization/markdown/InlineTokenizer.d.ts +5 -0
  422. package/dist/serialization/markdown/InlineTokenizer.d.ts.map +1 -0
  423. package/dist/serialization/markdown/LinkReferenceExtractor.d.ts +37 -0
  424. package/dist/serialization/markdown/LinkReferenceExtractor.d.ts.map +1 -0
  425. package/dist/serialization/markdown/MarkdownContext.d.ts +32 -0
  426. package/dist/serialization/markdown/MarkdownContext.d.ts.map +1 -0
  427. package/dist/serialization/markdown/MarkdownEntities.d.ts +33 -0
  428. package/dist/serialization/markdown/MarkdownEntities.d.ts.map +1 -0
  429. package/dist/serialization/markdown/MarkdownEscape.d.ts +33 -0
  430. package/dist/serialization/markdown/MarkdownEscape.d.ts.map +1 -0
  431. package/dist/serialization/markdown/MarkdownHTMLRegistry.d.ts +4 -0
  432. package/dist/serialization/markdown/MarkdownHTMLRegistry.d.ts.map +1 -0
  433. package/dist/serialization/markdown/MarkdownParseContext.d.ts +23 -0
  434. package/dist/serialization/markdown/MarkdownParseContext.d.ts.map +1 -0
  435. package/dist/state/Mapping.d.ts +33 -10
  436. package/dist/state/Mapping.d.ts.map +1 -1
  437. package/dist/state/StepApplication.d.ts +3 -1
  438. package/dist/state/StepApplication.d.ts.map +1 -1
  439. package/dist/state/StepHandlers.d.ts.map +1 -1
  440. package/dist/state/StepInversion.d.ts +2 -1
  441. package/dist/state/StepInversion.d.ts.map +1 -1
  442. package/dist/state/StepMapping.d.ts +3 -2
  443. package/dist/state/StepMapping.d.ts.map +1 -1
  444. package/dist/state/StepMaps.d.ts +3 -2
  445. package/dist/state/StepMaps.d.ts.map +1 -1
  446. package/dist/state/Steps.d.ts +34 -2
  447. package/dist/state/Steps.d.ts.map +1 -1
  448. package/dist/state/TransactionBuilder.d.ts +7 -1
  449. package/dist/state/TransactionBuilder.d.ts.map +1 -1
  450. package/dist/test/MarkdownConformanceUtils.d.ts +12 -0
  451. package/dist/test/MarkdownConformanceUtils.d.ts.map +1 -0
  452. package/dist/view/BlockRendering.d.ts +5 -0
  453. package/dist/view/BlockRendering.d.ts.map +1 -1
  454. package/dist/view/DecorationRendering.d.ts +6 -0
  455. package/dist/view/DecorationRendering.d.ts.map +1 -1
  456. package/dist/view/EditorViewEvents.d.ts.map +1 -1
  457. package/dist/view/Reconciler.d.ts.map +1 -1
  458. package/package.json +28 -214
  459. package/dist/chunks/AttrRegistry-DcDVyzLm.mjs.map +0 -1
  460. package/dist/chunks/AttributedMarkCommands-D4W2Jgpj.mjs +0 -2
  461. package/dist/chunks/BlockInsertion-6rR9tIGP.mjs +0 -2
  462. package/dist/chunks/BlockInsertion-6rR9tIGP.mjs.map +0 -1
  463. package/dist/chunks/BlockquotePlugin-4V7KV_Sb.mjs +0 -2
  464. package/dist/chunks/CaretNavigationPlugin-C6XBwp0N.mjs +0 -2
  465. package/dist/chunks/CaretNavigationPlugin-C6XBwp0N.mjs.map +0 -1
  466. package/dist/chunks/CodeBlockPlugin-3V2K3RBe.mjs +0 -2
  467. package/dist/chunks/CodeBlockPlugin-3V2K3RBe.mjs.map +0 -1
  468. package/dist/chunks/Commands-BIIpx_Zd.mjs +0 -2
  469. package/dist/chunks/Commands-BIIpx_Zd.mjs.map +0 -1
  470. package/dist/chunks/Decoration-ZeyVfwJB.mjs +0 -2
  471. package/dist/chunks/Decoration-ZeyVfwJB.mjs.map +0 -1
  472. package/dist/chunks/Document-r7vLOAGA.mjs +0 -2
  473. package/dist/chunks/Document-r7vLOAGA.mjs.map +0 -1
  474. package/dist/chunks/DocumentParser-CcTSeT1B.mjs +0 -2
  475. package/dist/chunks/DocumentParser-CcTSeT1B.mjs.map +0 -1
  476. package/dist/chunks/FontSizePlugin-9StCjEfN.mjs.map +0 -1
  477. package/dist/chunks/FormulaPlugin-CV5VUxkb.mjs +0 -2
  478. package/dist/chunks/FormulaPlugin-CV5VUxkb.mjs.map +0 -1
  479. package/dist/chunks/GapCursorNavigation-ycNzuQVH.mjs +0 -2
  480. package/dist/chunks/GapCursorPlugin-Zvxjnr82.mjs +0 -2
  481. package/dist/chunks/HTMLUtils-C6B4UT00.mjs +0 -2
  482. package/dist/chunks/HTMLUtils-C6B4UT00.mjs.map +0 -1
  483. package/dist/chunks/HeadingPlugin-BuGoM9Rz.mjs +0 -2
  484. package/dist/chunks/HorizontalRulePlugin-0FjHPZuA.mjs +0 -2
  485. package/dist/chunks/HorizontalRulePlugin-0FjHPZuA.mjs.map +0 -1
  486. package/dist/chunks/ImagePlugin-KpkuE2LH.mjs +0 -2
  487. package/dist/chunks/InlineCodePlugin-DMr4O7c7.mjs.map +0 -1
  488. package/dist/chunks/InlineStyleMarkSpec-C6LJT7kp.mjs +0 -2
  489. package/dist/chunks/LinkPlugin-DvZ3MPgL.mjs +0 -2
  490. package/dist/chunks/LinkPlugin-DvZ3MPgL.mjs.map +0 -1
  491. package/dist/chunks/ListPlugin-2yl6KiTK.mjs +0 -2
  492. package/dist/chunks/ListPlugin-2yl6KiTK.mjs.map +0 -1
  493. package/dist/chunks/NodeSelectionCommands-Dj4VxLdD.mjs +0 -2
  494. package/dist/chunks/PopupPositioning-BB97-__N.mjs +0 -2
  495. package/dist/chunks/PrintPlugin-DyIZDY3Q.mjs +0 -2
  496. package/dist/chunks/PrintPlugin-DyIZDY3Q.mjs.map +0 -1
  497. package/dist/chunks/PrintTypes-CxU69qu3.mjs +0 -3
  498. package/dist/chunks/PrintTypes-CxU69qu3.mjs.map +0 -1
  499. package/dist/chunks/SimpleMark-CaQtFAau.mjs +0 -2
  500. package/dist/chunks/SmartPastePlugin-Bi_wpTCV.mjs +0 -2
  501. package/dist/chunks/SmartPastePlugin-Bi_wpTCV.mjs.map +0 -1
  502. package/dist/chunks/StrikethroughPlugin-BLKDRWtf.mjs +0 -2
  503. package/dist/chunks/StrikethroughPlugin-BLKDRWtf.mjs.map +0 -1
  504. package/dist/chunks/StyleRuntime-BFKu52mS.mjs +0 -2
  505. package/dist/chunks/StyleRuntime-BFKu52mS.mjs.map +0 -1
  506. package/dist/chunks/TablePlugin-BTH9VRZq.mjs +0 -2
  507. package/dist/chunks/TablePlugin-BTH9VRZq.mjs.map +0 -1
  508. package/dist/chunks/TextColorPlugin-CEfZQ6Md.mjs +0 -2
  509. package/dist/chunks/TextDirectionAutoPlugin-CzWJjrvG.mjs +0 -2
  510. package/dist/chunks/TextDirectionPlugin-DHB88HKf.mjs +0 -2
  511. package/dist/chunks/TextFormattingPlugin-Cubp3e7f.mjs +0 -2
  512. package/dist/chunks/TextFormattingPlugin-Cubp3e7f.mjs.map +0 -1
  513. package/dist/chunks/ToolbarPlugin-DVGrFf8v.mjs +0 -2
  514. package/dist/chunks/VideoPlugin-B3uf1Dwp.mjs +0 -2
  515. package/dist/chunks/VideoPlugin-B3uf1Dwp.mjs.map +0 -1
  516. package/dist/chunks/WordBoundary-DxeMBRyP.mjs +0 -2
  517. package/dist/chunks/XmlDetector-D7TQpw-e.mjs +0 -2
  518. package/dist/chunks/XmlDetector-D7TQpw-e.mjs.map +0 -1
  519. package/dist/chunks/XmlSupport-BYiRwlkK.mjs +0 -2
  520. package/dist/chunks/XmlSupport-BYiRwlkK.mjs.map +0 -1
  521. package/dist/chunks/ar-BTShmP2E.mjs +0 -2
  522. package/dist/chunks/ar-jbplYWkC.mjs +0 -2
  523. package/dist/chunks/ar-jbplYWkC.mjs.map +0 -1
  524. package/dist/chunks/de-DN-e6G5A.mjs +0 -2
  525. package/dist/chunks/de-DN-e6G5A.mjs.map +0 -1
  526. package/dist/chunks/es-CM55WeEN.mjs +0 -2
  527. package/dist/chunks/es-CM55WeEN.mjs.map +0 -1
  528. package/dist/chunks/fonts-DQC6Uj4r.mjs +0 -2
  529. package/dist/chunks/fonts-DQC6Uj4r.mjs.map +0 -1
  530. package/dist/chunks/fr-C_2i5Ono.mjs +0 -2
  531. package/dist/chunks/fr-C_2i5Ono.mjs.map +0 -1
  532. package/dist/chunks/full-BBl7mvwH.mjs +0 -2
  533. package/dist/chunks/hi-C9fvG91d.mjs +0 -2
  534. package/dist/chunks/hi-C9fvG91d.mjs.map +0 -1
  535. package/dist/chunks/minimal-CtnR4dqp.mjs +0 -2
  536. package/dist/chunks/pt-GqLw5tN0.mjs +0 -2
  537. package/dist/chunks/pt-GqLw5tN0.mjs.map +0 -1
  538. package/dist/chunks/ru-4g_qsaLr.mjs +0 -2
  539. package/dist/chunks/ru-4g_qsaLr.mjs.map +0 -1
  540. package/dist/chunks/src-C89Cw7ni.mjs +0 -2
  541. package/dist/chunks/src-C89Cw7ni.mjs.map +0 -1
  542. package/dist/chunks/zh-BjoyjClN.mjs +0 -2
  543. package/dist/chunks/zh-DeZP08HI.mjs +0 -2
  544. package/dist/chunks/zh-DeZP08HI.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MathFont-BS8IwYh2.mjs","names":[],"sources":["../../src/plugins/formula/MathFont.ts"],"sourcesContent":[null],"mappings":"AAwBA,IAIa,EAAoC,CAChD,KAAM,eACN,OAAQ,uBACR,SAAU,QACV,UAAW,CACV,CACC,IAAK,+9hXACL,OAAQ,MACR,MAAO,SACP,QAAS"}
@@ -1,2 +1,2 @@
1
- import{S as n}from"./Document-r7vLOAGA.mjs";function t(t,i){if(0===i.length)return;let r=t.children.find(n=>n.id===i[0]);if(r){for(let t=1;t<i.length;t++){const e=i[t];if(!e)return;const o=r?.children.find(t=>n(t)&&t.id===e);if(!o)return;r=o}return r}}function i(i,r,e){if(0===r.length){const t=i.children[e];return t&&n(t)?t:void 0}const o=t(i,r);if(!o)return;const f=o.children[e];return f&&n(f)?f:void 0}function r(i,r){if(0===r.length)return;if(1===r.length){const n=i.children.findIndex(n=>n.id===r[0]);if(-1===n)return;return{parent:i,index:n}}const e=t(i,r.slice(0,-1));if(!e)return;const o=r[r.length-1];if(!o)return;const f=e.children.findIndex(t=>n(t)&&t.id===o);return-1!==f?{parent:e,index:f}:void 0}function e(n,t){for(const i of n.children){if(i.id===t)return[t];const n=o(i,t);if(n)return[i.id,...n]}}function o(t,i){for(const r of t.children){if(!n(r))continue;if(r.id===i)return[i];const t=o(r,i);if(t)return[r.id,...t]}}function f(n,t){for(const i of n.children)c(i,[i.id],t)}function c(t,i,r){r(t,i);for(const e of t.children)n(e)&&c(e,[...i,e.id],r)}function u(n,t){for(const i of n.children){if(i.id===t)return i;const n=d(i,t);if(n)return n}}function d(t,i){for(const r of t.children){if(!n(r))continue;if(r.id===i)return r;const t=d(r,i);if(t)return t}}function s(n,i){const r=e(n,i);if(!r)return;const o=t(n,r);return o?{node:o,path:r}:void 0}function l(n,i,r){const o=e(n,i);if(o&&!(o.length<2))for(let e=o.length-2;e>=0;e--){const i=o.slice(0,e+1),f=t(n,i);if(f?.type===r)return{node:f,path:i}}}function h(n,t,i){return void 0!==l(n,t,i)}export{h as a,r as c,s as i,f as l,u as n,i as o,e as r,t as s,l as t};
2
- //# sourceMappingURL=NodeResolver-ChgLF_IP.mjs.map
1
+ import{w as n}from"./Document-827l3P80.mjs";function t(t,i){if(0===i.length)return;let r=t.children.find(n=>n.id===i[0]);if(r){for(let t=1;t<i.length;t++){const e=i[t];if(!e)return;const o=r?.children.find(t=>n(t)&&t.id===e);if(!o)return;r=o}return r}}function i(i,r,e){if(0===r.length){const t=i.children[e];return t&&n(t)?t:void 0}const o=t(i,r);if(!o)return;const f=o.children[e];return f&&n(f)?f:void 0}function r(i,r){if(0===r.length)return;if(1===r.length){const n=i.children.findIndex(n=>n.id===r[0]);if(-1===n)return;return{parent:i,index:n}}const e=t(i,r.slice(0,-1));if(!e)return;const o=r[r.length-1];if(!o)return;const f=e.children.findIndex(t=>n(t)&&t.id===o);return-1!==f?{parent:e,index:f}:void 0}function e(n,t){for(const i of n.children){if(i.id===t)return[t];const n=o(i,t);if(n)return[i.id,...n]}}function o(t,i){for(const r of t.children){if(!n(r))continue;if(r.id===i)return[i];const t=o(r,i);if(t)return[r.id,...t]}}function f(n,t){for(const i of n.children)c(i,[i.id],t)}function c(t,i,r){r(t,i);for(const e of t.children)n(e)&&c(e,[...i,e.id],r)}function u(n,t){for(const i of n.children){if(i.id===t)return i;const n=d(i,t);if(n)return n}}function d(t,i){for(const r of t.children){if(!n(r))continue;if(r.id===i)return r;const t=d(r,i);if(t)return t}}function s(n,i){const r=e(n,i);if(!r)return;const o=t(n,r);return o?{node:o,path:r}:void 0}function l(n,i,r){const o=e(n,i);if(o&&!(o.length<2))for(let e=o.length-2;e>=0;e--){const i=o.slice(0,e+1),f=t(n,i);if(f?.type===r)return{node:f,path:i}}}function h(n,t,i){return void 0!==l(n,t,i)}export{h as a,r as c,s as i,f as l,u as n,i as o,e as r,t as s,l as t};
2
+ //# sourceMappingURL=NodeResolver-Dleih-8R.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"NodeResolver-ChgLF_IP.mjs","names":[],"sources":["../../src/model/NodeResolver.ts"],"sourcesContent":["/**\n * Utilities for resolving nodes by path within the document tree.\n * Supports both flat and recursive (nested) document structures.\n */\n\nimport type { BlockNode, Document } from './Document.js';\nimport { isBlockNode } from './Document.js';\n\n/**\n * Resolves a node in the document tree by its path (array of block IDs).\n * The path traces the lineage from the root block down to the target.\n */\nexport function resolveNodeByPath(doc: Document, path: readonly string[]): BlockNode | undefined {\n\tif (path.length === 0) return undefined;\n\n\tlet current: BlockNode | undefined = doc.children.find((b) => b.id === path[0]);\n\tif (!current) return undefined;\n\n\tfor (let i = 1; i < path.length; i++) {\n\t\tconst childId = path[i];\n\t\tif (!childId) return undefined;\n\t\tconst next: BlockNode | undefined = current?.children.find(\n\t\t\t(c): c is BlockNode => isBlockNode(c) && c.id === childId,\n\t\t);\n\t\tif (!next) return undefined;\n\t\tcurrent = next;\n\t}\n\n\treturn current;\n}\n\n/**\n * Resolves the block child at `(parentPath, index)`. `parentPath = []` addresses\n * the document root; otherwise the path traces from the document root to the\n * containing block. Returns `undefined` when the parent does not exist or the\n * indexed slot is missing / occupied by a non-block child.\n */\nexport function resolveChildAt(\n\tdoc: Document,\n\tparentPath: readonly string[],\n\tindex: number,\n): BlockNode | undefined {\n\tif (parentPath.length === 0) {\n\t\tconst child = doc.children[index];\n\t\treturn child && isBlockNode(child) ? child : undefined;\n\t}\n\tconst parent = resolveNodeByPath(doc, parentPath);\n\tif (!parent) return undefined;\n\tconst child = parent.children[index];\n\treturn child && isBlockNode(child) ? child : undefined;\n}\n\n/**\n * Resolves the parent of a node at the given path.\n * Returns the parent container (Document or BlockNode) and the child's index within it.\n */\nexport function resolveParentByPath(\n\tdoc: Document,\n\tpath: readonly string[],\n): { parent: Document | BlockNode; index: number } | undefined {\n\tif (path.length === 0) return undefined;\n\n\tif (path.length === 1) {\n\t\tconst index = doc.children.findIndex((b) => b.id === path[0]);\n\t\tif (index === -1) return undefined;\n\t\treturn { parent: doc, index };\n\t}\n\n\tconst parentPath = path.slice(0, -1);\n\tconst parent = resolveNodeByPath(doc, parentPath);\n\tif (!parent) return undefined;\n\n\tconst childId = path[path.length - 1];\n\tif (!childId) return undefined;\n\tconst index = parent.children.findIndex(\n\t\t(c): c is BlockNode => isBlockNode(c) && c.id === childId,\n\t);\n\tif (index === -1) return undefined;\n\n\treturn { parent, index };\n}\n\n/**\n * Finds the path (array of block IDs) to a node by its ID.\n * Performs recursive DFS through the document tree.\n */\nexport function findNodePath(doc: Document, nodeId: string): string[] | undefined {\n\tfor (const block of doc.children) {\n\t\tif (block.id === nodeId) return [nodeId];\n\n\t\tconst subPath = findNodePathInBlock(block, nodeId);\n\t\tif (subPath) return [block.id, ...subPath];\n\t}\n\treturn undefined;\n}\n\nfunction findNodePathInBlock(block: BlockNode, nodeId: string): string[] | undefined {\n\tfor (const child of block.children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tif (child.id === nodeId) return [nodeId];\n\n\t\tconst subPath = findNodePathInBlock(child, nodeId);\n\t\tif (subPath) return [child.id, ...subPath];\n\t}\n\treturn undefined;\n}\n\n/**\n * Walks all block nodes in the document tree in depth-first order.\n * Visits every BlockNode, including nested ones, with their full path.\n */\nexport function walkNodes(\n\tdoc: Document,\n\tcallback: (node: BlockNode, path: string[]) => void,\n): void {\n\tfor (const block of doc.children) {\n\t\twalkNodeRecursive(block, [block.id], callback);\n\t}\n}\n\nfunction walkNodeRecursive(\n\tnode: BlockNode,\n\tpath: string[],\n\tcallback: (node: BlockNode, path: string[]) => void,\n): void {\n\tcallback(node, path);\n\tfor (const child of node.children) {\n\t\tif (isBlockNode(child)) {\n\t\t\twalkNodeRecursive(child, [...path, child.id], callback);\n\t\t}\n\t}\n}\n\n/**\n * Finds a block node by ID anywhere in the document tree (recursive DFS).\n */\nexport function findNode(doc: Document, nodeId: string): BlockNode | undefined {\n\tfor (const block of doc.children) {\n\t\tif (block.id === nodeId) return block;\n\t\tconst found = findNodeInBlock(block, nodeId);\n\t\tif (found) return found;\n\t}\n\treturn undefined;\n}\n\nfunction findNodeInBlock(block: BlockNode, nodeId: string): BlockNode | undefined {\n\tfor (const child of block.children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tif (child.id === nodeId) return child;\n\t\tconst found = findNodeInBlock(child, nodeId);\n\t\tif (found) return found;\n\t}\n\treturn undefined;\n}\n\n/**\n * Finds a block node and returns it together with its path.\n */\nexport function findNodeWithPath(\n\tdoc: Document,\n\tnodeId: string,\n): { node: BlockNode; path: string[] } | undefined {\n\tconst path = findNodePath(doc, nodeId);\n\tif (!path) return undefined;\n\tconst node = resolveNodeByPath(doc, path);\n\tif (!node) return undefined;\n\treturn { node, path };\n}\n\n/**\n * Returns the nearest ancestor of the given node whose type matches `type`,\n * together with its path. Excludes the node itself. Returns undefined when no\n * matching ancestor exists.\n */\nexport function findAncestorOfType(\n\tdoc: Document,\n\tnodeId: string,\n\ttype: string,\n): { node: BlockNode; path: string[] } | undefined {\n\tconst path = findNodePath(doc, nodeId);\n\tif (!path || path.length < 2) return undefined;\n\t// Walk ancestors from nearest to root, skipping the node itself (last entry).\n\tfor (let i = path.length - 2; i >= 0; i--) {\n\t\tconst ancestorPath = path.slice(0, i + 1);\n\t\tconst ancestor = resolveNodeByPath(doc, ancestorPath);\n\t\tif (ancestor?.type === type) return { node: ancestor, path: ancestorPath };\n\t}\n\treturn undefined;\n}\n\n/** Returns true if the node has an ancestor (excluding itself) of the given type. */\nexport function hasAncestorOfType(doc: Document, nodeId: string, type: string): boolean {\n\treturn findAncestorOfType(doc, nodeId, type) !== undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"NodeResolver-Dleih-8R.mjs","names":[],"sources":["../../src/model/NodeResolver.ts"],"sourcesContent":["/**\n * Utilities for resolving nodes by path within the document tree.\n * Supports both flat and recursive (nested) document structures.\n */\n\nimport type { BlockNode, Document } from './Document.js';\nimport { isBlockNode } from './Document.js';\n\n/**\n * Resolves a node in the document tree by its path (array of block IDs).\n * The path traces the lineage from the root block down to the target.\n */\nexport function resolveNodeByPath(doc: Document, path: readonly string[]): BlockNode | undefined {\n\tif (path.length === 0) return undefined;\n\n\tlet current: BlockNode | undefined = doc.children.find((b) => b.id === path[0]);\n\tif (!current) return undefined;\n\n\tfor (let i = 1; i < path.length; i++) {\n\t\tconst childId = path[i];\n\t\tif (!childId) return undefined;\n\t\tconst next: BlockNode | undefined = current?.children.find(\n\t\t\t(c): c is BlockNode => isBlockNode(c) && c.id === childId,\n\t\t);\n\t\tif (!next) return undefined;\n\t\tcurrent = next;\n\t}\n\n\treturn current;\n}\n\n/**\n * Resolves the block child at `(parentPath, index)`. `parentPath = []` addresses\n * the document root; otherwise the path traces from the document root to the\n * containing block. Returns `undefined` when the parent does not exist or the\n * indexed slot is missing / occupied by a non-block child.\n */\nexport function resolveChildAt(\n\tdoc: Document,\n\tparentPath: readonly string[],\n\tindex: number,\n): BlockNode | undefined {\n\tif (parentPath.length === 0) {\n\t\tconst child = doc.children[index];\n\t\treturn child && isBlockNode(child) ? child : undefined;\n\t}\n\tconst parent = resolveNodeByPath(doc, parentPath);\n\tif (!parent) return undefined;\n\tconst child = parent.children[index];\n\treturn child && isBlockNode(child) ? child : undefined;\n}\n\n/**\n * Resolves the parent of a node at the given path.\n * Returns the parent container (Document or BlockNode) and the child's index within it.\n */\nexport function resolveParentByPath(\n\tdoc: Document,\n\tpath: readonly string[],\n): { parent: Document | BlockNode; index: number } | undefined {\n\tif (path.length === 0) return undefined;\n\n\tif (path.length === 1) {\n\t\tconst index = doc.children.findIndex((b) => b.id === path[0]);\n\t\tif (index === -1) return undefined;\n\t\treturn { parent: doc, index };\n\t}\n\n\tconst parentPath = path.slice(0, -1);\n\tconst parent = resolveNodeByPath(doc, parentPath);\n\tif (!parent) return undefined;\n\n\tconst childId = path[path.length - 1];\n\tif (!childId) return undefined;\n\tconst index = parent.children.findIndex(\n\t\t(c): c is BlockNode => isBlockNode(c) && c.id === childId,\n\t);\n\tif (index === -1) return undefined;\n\n\treturn { parent, index };\n}\n\n/**\n * Finds the path (array of block IDs) to a node by its ID.\n * Performs recursive DFS through the document tree.\n */\nexport function findNodePath(doc: Document, nodeId: string): string[] | undefined {\n\tfor (const block of doc.children) {\n\t\tif (block.id === nodeId) return [nodeId];\n\n\t\tconst subPath = findNodePathInBlock(block, nodeId);\n\t\tif (subPath) return [block.id, ...subPath];\n\t}\n\treturn undefined;\n}\n\nfunction findNodePathInBlock(block: BlockNode, nodeId: string): string[] | undefined {\n\tfor (const child of block.children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tif (child.id === nodeId) return [nodeId];\n\n\t\tconst subPath = findNodePathInBlock(child, nodeId);\n\t\tif (subPath) return [child.id, ...subPath];\n\t}\n\treturn undefined;\n}\n\n/**\n * Walks all block nodes in the document tree in depth-first order.\n * Visits every BlockNode, including nested ones, with their full path.\n */\nexport function walkNodes(\n\tdoc: Document,\n\tcallback: (node: BlockNode, path: string[]) => void,\n): void {\n\tfor (const block of doc.children) {\n\t\twalkNodeRecursive(block, [block.id], callback);\n\t}\n}\n\nfunction walkNodeRecursive(\n\tnode: BlockNode,\n\tpath: string[],\n\tcallback: (node: BlockNode, path: string[]) => void,\n): void {\n\tcallback(node, path);\n\tfor (const child of node.children) {\n\t\tif (isBlockNode(child)) {\n\t\t\twalkNodeRecursive(child, [...path, child.id], callback);\n\t\t}\n\t}\n}\n\n/**\n * Finds a block node by ID anywhere in the document tree (recursive DFS).\n */\nexport function findNode(doc: Document, nodeId: string): BlockNode | undefined {\n\tfor (const block of doc.children) {\n\t\tif (block.id === nodeId) return block;\n\t\tconst found = findNodeInBlock(block, nodeId);\n\t\tif (found) return found;\n\t}\n\treturn undefined;\n}\n\nfunction findNodeInBlock(block: BlockNode, nodeId: string): BlockNode | undefined {\n\tfor (const child of block.children) {\n\t\tif (!isBlockNode(child)) continue;\n\t\tif (child.id === nodeId) return child;\n\t\tconst found = findNodeInBlock(child, nodeId);\n\t\tif (found) return found;\n\t}\n\treturn undefined;\n}\n\n/**\n * Finds a block node and returns it together with its path.\n */\nexport function findNodeWithPath(\n\tdoc: Document,\n\tnodeId: string,\n): { node: BlockNode; path: string[] } | undefined {\n\tconst path = findNodePath(doc, nodeId);\n\tif (!path) return undefined;\n\tconst node = resolveNodeByPath(doc, path);\n\tif (!node) return undefined;\n\treturn { node, path };\n}\n\n/**\n * Returns the nearest ancestor of the given node whose type matches `type`,\n * together with its path. Excludes the node itself. Returns undefined when no\n * matching ancestor exists.\n */\nexport function findAncestorOfType(\n\tdoc: Document,\n\tnodeId: string,\n\ttype: string,\n): { node: BlockNode; path: string[] } | undefined {\n\tconst path = findNodePath(doc, nodeId);\n\tif (!path || path.length < 2) return undefined;\n\t// Walk ancestors from nearest to root, skipping the node itself (last entry).\n\tfor (let i = path.length - 2; i >= 0; i--) {\n\t\tconst ancestorPath = path.slice(0, i + 1);\n\t\tconst ancestor = resolveNodeByPath(doc, ancestorPath);\n\t\tif (ancestor?.type === type) return { node: ancestor, path: ancestorPath };\n\t}\n\treturn undefined;\n}\n\n/** Returns true if the node has an ancestor (excluding itself) of the given type. */\nexport function hasAncestorOfType(doc: Document, nodeId: string, type: string): boolean {\n\treturn findAncestorOfType(doc, nodeId, type) !== undefined;\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{c as t,f as n,h as e,w as i}from"./Document-827l3P80.mjs";import{r as o}from"./NodeResolver-Dleih-8R.mjs";import{c as r,l as s,n as c,o as l,r as u,t as a}from"./Selection-HYoVFpAx.mjs";import{i as d}from"./NavigationQueries-Bt4zZ17v.mjs";import{T as f,_ as b,l as p}from"./BlockInsertion-CYH2gRkY.mjs";function m(e,o){const{parentPath:r,siblings:s,index:c}=f(e,o.nodeId);if(c<0)return null;const l=e.transaction("input");if(1===s.length){const e=n();return l.insertNode(r,0,t(e)),l.removeNode(r,1),l.setSelection(a(e,0)),l.build()}l.removeNode(r,c);const u=s[c-1];if(u&&i(u)){const t=b(e,u.id,"end");if(t)return l.setSelection(t),l.build()}const d=s[c+1];if(d&&i(d)){const t=b(e,d.id,"start");if(t)return l.setSelection(t),l.build()}return null}function h(t,n){if(n<0)return;const e=t[n+1];return e&&i(e)&&p(e)?e:void 0}function g(e,i){const{parentPath:o,siblings:r,index:s}=f(e,i.nodeId);if(s<0)return null;const c=h(r,s);if(c)return e.transaction("input").setSelection(a(c.id,0)).build();const l=n(),u=e.transaction("input");return u.insertNode(o,s+1,t(l)),u.setSelection(a(l,0)),u.build()}function S(e,i,o,r){const{parentPath:s,siblings:c,index:l}=f(e,i.nodeId),u=e.transaction(r),d=h(c,l);if(d)return u.insertText(d.id,0,o,[]),u.setSelection(a(d.id,o.length)),u.build();const b=n(),p=l>=0?l+1:c.length;return u.insertNode(s,p,t(b)),u.insertText(b,0,o,[]),u.setSelection(a(b,o.length)),u.build()}function I(t,n,i){const f=t.selection,b=t.getBlockOrder(),p=!i||"left"!==n&&"right"!==n?n:"left"===n?"right":"left";return s(f)?function(t,n,i,r){const s=r.indexOf(n.nodeId),l=o(t.doc,n.nodeId)??[];if("left"===i||"up"===i){if(s>0){const i=r[s-1];if(!i)return null;if(d(t,i))return t.transaction("input").setSelection(c(n.nodeId,"before",l)).build();const o=t.getBlock(i),u=o?e(o):0;return t.transaction("input").setSelection(a(i,u)).build()}return t.transaction("input").setSelection(c(n.nodeId,"before",l)).build()}if(s<r.length-1){const e=r[s+1];return e?d(t,e)?t.transaction("input").setSelection(c(n.nodeId,"after",l)).build():t.transaction("input").setSelection(a(e,0)).build():null}return t.transaction("input").setSelection(c(n.nodeId,"after",l)).build()}(t,f,p,b):r(f)?null:l(f)?function(t,n,i,r){const s=r.indexOf(n.anchor.blockId),c=t.getBlock(n.anchor.blockId);if(!c)return null;const l=e(c);if(("right"===i||"down"===i)&&n.anchor.offset===l&&s<r.length-1){const n=r[s+1];if(n&&d(t,n)){const e=o(t.doc,n)??[];return t.transaction("input").setSelection(u(n,e)).build()}}if(("left"===i||"up"===i)&&0===n.anchor.offset&&s>0){const n=r[s-1];if(n&&d(t,n)){const e=o(t.doc,n)??[];return t.transaction("input").setSelection(u(n,e)).build()}}return null}(t,f,p,b):null}export{I as i,g as n,S as r,m as t};
2
+ //# sourceMappingURL=NodeSelectionCommands-WH5snxr_.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"NodeSelectionCommands-Dj4VxLdD.mjs","names":[],"sources":["../../src/commands/NodeSelectionCommands.ts"],"sourcesContent":["/**\n * Commands for NodeSelection: deleting void blocks, inserting paragraphs\n * after void blocks, and navigating arrow keys into/out of void blocks.\n */\n\nimport type { BlockNode, ChildNode } from '../model/Document.js';\nimport {\n\tcreateEmptyParagraph,\n\tgenerateBlockId,\n\tgetBlockLength,\n\tisBlockNode,\n} from '../model/Document.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { NodeSelection } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateGapCursor,\n\tcreateNodeSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport { isVoidBlock } from '../state/NavigationQueries.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { isEmptyParagraph } from './BlockInsertion.js';\nimport { createSelectionForBlockBoundary, resolveSiblingContext } from './CommandHelpers.js';\n\nexport { findFirstLeafBlockId, findLastLeafBlockId } from './CommandHelpers.js';\n\n/**\n * Deletes the selected block and places cursor on a valid adjacent position.\n * If it is the only child in its parent, replaces it with an empty paragraph.\n */\nexport function deleteNodeSelection(state: EditorState, sel: NodeSelection): Transaction | null {\n\tconst { parentPath, siblings, index } = resolveSiblingContext(state, sel.nodeId);\n\tif (index < 0) return null;\n\n\tconst builder = state.transaction('input');\n\n\t// Keep container invariants intact when removing the only child in any parent.\n\tif (siblings.length === 1) {\n\t\tconst newId = generateBlockId();\n\t\tbuilder.insertNode(parentPath, 0, createEmptyParagraph(newId));\n\t\tbuilder.removeNode(parentPath, 1);\n\t\tbuilder.setSelection(createCollapsedSelection(newId, 0));\n\t\treturn builder.build();\n\t}\n\n\tbuilder.removeNode(parentPath, index);\n\n\t// Prefer the previous sibling, matching Backspace/Delete semantics.\n\tconst prevSibling = siblings[index - 1];\n\tif (prevSibling && isBlockNode(prevSibling)) {\n\t\tconst selection = createSelectionForBlockBoundary(state, prevSibling.id, 'end');\n\t\tif (selection) {\n\t\t\tbuilder.setSelection(selection);\n\t\t\treturn builder.build();\n\t\t}\n\t}\n\n\tconst nextSibling = siblings[index + 1];\n\tif (nextSibling && isBlockNode(nextSibling)) {\n\t\tconst selection = createSelectionForBlockBoundary(state, nextSibling.id, 'start');\n\t\tif (selection) {\n\t\t\tbuilder.setSelection(selection);\n\t\t\treturn builder.build();\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * The void block's trailing escape line, when it already exists as an empty\n * paragraph. A void block at the document root always owns such a paragraph\n * (#152/#158), so reusing it stops a second blank line from stacking up when\n * text or a paragraph is inserted while the void is node-selected (#163).\n * Returns undefined when there is no reusable line (a non-empty sibling, or the\n * void is the last block), so callers fall back to creating one.\n */\nfunction trailingEscapeParagraph(\n\tsiblings: readonly ChildNode[],\n\tindex: number,\n): BlockNode | undefined {\n\tif (index < 0) return undefined;\n\tconst next: ChildNode | undefined = siblings[index + 1];\n\treturn next && isBlockNode(next) && isEmptyParagraph(next) ? next : undefined;\n}\n\n/**\n * Places a collapsed cursor on an empty paragraph after a node-selected void\n * block (Enter). Reuses the void's existing trailing escape line when present so\n * no blank line stacks up (#163); otherwise inserts a fresh paragraph.\n */\nexport function insertParagraphAfterNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n): Transaction | null {\n\tconst { parentPath, siblings, index } = resolveSiblingContext(state, sel.nodeId);\n\tif (index < 0) return null;\n\n\tconst trailing: BlockNode | undefined = trailingEscapeParagraph(siblings, index);\n\tif (trailing) {\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createCollapsedSelection(trailing.id, 0))\n\t\t\t.build();\n\t}\n\n\tconst newId = generateBlockId();\n\tconst builder = state.transaction('input');\n\tbuilder.insertNode(parentPath, index + 1, createEmptyParagraph(newId));\n\tbuilder.setSelection(createCollapsedSelection(newId, 0));\n\treturn builder.build();\n}\n\n/**\n * Inserts text on a paragraph after a node-selected void block (typing). Reuses\n * the void's existing trailing escape line when present so no blank line stacks\n * up (#163); otherwise inserts a fresh paragraph to hold the text.\n */\nexport function insertTextAfterNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n\ttext: string,\n\torigin: 'input' | 'paste',\n): Transaction {\n\tconst { parentPath, siblings, index } = resolveSiblingContext(state, sel.nodeId);\n\tconst builder = state.transaction(origin);\n\n\tconst trailing: BlockNode | undefined = trailingEscapeParagraph(siblings, index);\n\tif (trailing) {\n\t\tbuilder.insertText(trailing.id, 0, text, []);\n\t\tbuilder.setSelection(createCollapsedSelection(trailing.id, text.length));\n\t\treturn builder.build();\n\t}\n\n\tconst newId = generateBlockId();\n\tconst insertIdx = index >= 0 ? index + 1 : siblings.length;\n\tbuilder.insertNode(parentPath, insertIdx, createEmptyParagraph(newId));\n\tbuilder.insertText(newId, 0, text, []);\n\tbuilder.setSelection(createCollapsedSelection(newId, text.length));\n\treturn builder.build();\n}\n\n/**\n * Navigates arrow keys into/out of void blocks.\n * Returns a transaction if navigation should create a NodeSelection, or null.\n *\n * @param isRtl — When true, flips left/right to account for RTL block direction.\n */\nexport function navigateArrowIntoVoid(\n\tstate: EditorState,\n\tdirection: 'left' | 'right' | 'up' | 'down',\n\tisRtl?: boolean,\n): Transaction | null {\n\tconst sel = state.selection;\n\tconst blockOrder = state.getBlockOrder();\n\tconst effectiveDir: 'left' | 'right' | 'up' | 'down' =\n\t\tisRtl && (direction === 'left' || direction === 'right')\n\t\t\t? direction === 'left'\n\t\t\t\t? 'right'\n\t\t\t\t: 'left'\n\t\t\t: direction;\n\n\t// If currently on a NodeSelection, navigate away from it\n\tif (isNodeSelection(sel)) {\n\t\treturn navigateAwayFromNodeSelection(state, sel, effectiveDir, blockOrder);\n\t}\n\n\t// GapCursor is handled by navigateFromGapCursor in CaretNavigation\n\tif (isGapCursor(sel)) return null;\n\n\t// Text selection: check if navigating into a void block\n\tif (!isCollapsed(sel)) return null;\n\n\treturn navigateIntoVoid(state, sel, effectiveDir, blockOrder);\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Handles navigation away from a NodeSelection (arrow keys while void is selected). */\nfunction navigateAwayFromNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n\tdirection: 'left' | 'right' | 'up' | 'down',\n\tblockOrder: readonly BlockId[],\n): Transaction | null {\n\tconst nodeIdx = blockOrder.indexOf(sel.nodeId);\n\tconst nodePath = (findNodePath(state.doc, sel.nodeId) ?? []) as BlockId[];\n\n\tif (direction === 'left' || direction === 'up') {\n\t\tif (nodeIdx > 0) {\n\t\t\tconst prevId = blockOrder[nodeIdx - 1];\n\t\t\tif (!prevId) return null;\n\t\t\tif (isVoidBlock(state, prevId)) {\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createGapCursor(sel.nodeId, 'before', nodePath))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t\tconst prevBlock = state.getBlock(prevId);\n\t\t\tconst prevLen = prevBlock ? getBlockLength(prevBlock) : 0;\n\t\t\treturn state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setSelection(createCollapsedSelection(prevId, prevLen))\n\t\t\t\t.build();\n\t\t}\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createGapCursor(sel.nodeId, 'before', nodePath))\n\t\t\t.build();\n\t}\n\n\t// right or down\n\tif (nodeIdx < blockOrder.length - 1) {\n\t\tconst nextId = blockOrder[nodeIdx + 1];\n\t\tif (!nextId) return null;\n\t\tif (isVoidBlock(state, nextId)) {\n\t\t\treturn state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setSelection(createGapCursor(sel.nodeId, 'after', nodePath))\n\t\t\t\t.build();\n\t\t}\n\t\treturn state.transaction('input').setSelection(createCollapsedSelection(nextId, 0)).build();\n\t}\n\treturn state\n\t\t.transaction('input')\n\t\t.setSelection(createGapCursor(sel.nodeId, 'after', nodePath))\n\t\t.build();\n}\n\n/** Handles text selection navigating into an adjacent void block. */\nfunction navigateIntoVoid(\n\tstate: EditorState,\n\tsel: { readonly anchor: { readonly blockId: BlockId; readonly offset: number } },\n\tdirection: 'left' | 'right' | 'up' | 'down',\n\tblockOrder: readonly BlockId[],\n): Transaction | null {\n\tconst blockIdx = blockOrder.indexOf(sel.anchor.blockId);\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\tconst blockLen = getBlockLength(block);\n\n\tif (direction === 'right' || direction === 'down') {\n\t\tif (sel.anchor.offset === blockLen && blockIdx < blockOrder.length - 1) {\n\t\t\tconst nextId = blockOrder[blockIdx + 1];\n\t\t\tif (nextId && isVoidBlock(state, nextId)) {\n\t\t\t\tconst path = findNodePath(state.doc, nextId) ?? [];\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createNodeSelection(nextId, path as BlockId[]))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (direction === 'left' || direction === 'up') {\n\t\tif (sel.anchor.offset === 0 && blockIdx > 0) {\n\t\t\tconst prevId = blockOrder[blockIdx - 1];\n\t\t\tif (prevId && isVoidBlock(state, prevId)) {\n\t\t\t\tconst path = findNodePath(state.doc, prevId) ?? [];\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createNodeSelection(prevId, path as BlockId[]))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"NodeSelectionCommands-WH5snxr_.mjs","names":[],"sources":["../../src/commands/NodeSelectionCommands.ts"],"sourcesContent":["/**\n * Commands for NodeSelection: deleting void blocks, inserting paragraphs\n * after void blocks, and navigating arrow keys into/out of void blocks.\n */\n\nimport type { BlockNode, ChildNode } from '../model/Document.js';\nimport {\n\tcreateEmptyParagraph,\n\tgenerateBlockId,\n\tgetBlockLength,\n\tisBlockNode,\n} from '../model/Document.js';\nimport { findNodePath } from '../model/NodeResolver.js';\nimport type { NodeSelection } from '../model/Selection.js';\nimport {\n\tcreateCollapsedSelection,\n\tcreateGapCursor,\n\tcreateNodeSelection,\n\tisCollapsed,\n\tisGapCursor,\n\tisNodeSelection,\n} from '../model/Selection.js';\nimport type { BlockId } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport { isVoidBlock } from '../state/NavigationQueries.js';\nimport type { Transaction } from '../state/Transaction.js';\nimport { isEmptyParagraph } from './BlockInsertion.js';\nimport { createSelectionForBlockBoundary, resolveSiblingContext } from './CommandHelpers.js';\n\nexport { findFirstLeafBlockId, findLastLeafBlockId } from './CommandHelpers.js';\n\n/**\n * Deletes the selected block and places cursor on a valid adjacent position.\n * If it is the only child in its parent, replaces it with an empty paragraph.\n */\nexport function deleteNodeSelection(state: EditorState, sel: NodeSelection): Transaction | null {\n\tconst { parentPath, siblings, index } = resolveSiblingContext(state, sel.nodeId);\n\tif (index < 0) return null;\n\n\tconst builder = state.transaction('input');\n\n\t// Keep container invariants intact when removing the only child in any parent.\n\tif (siblings.length === 1) {\n\t\tconst newId = generateBlockId();\n\t\tbuilder.insertNode(parentPath, 0, createEmptyParagraph(newId));\n\t\tbuilder.removeNode(parentPath, 1);\n\t\tbuilder.setSelection(createCollapsedSelection(newId, 0));\n\t\treturn builder.build();\n\t}\n\n\tbuilder.removeNode(parentPath, index);\n\n\t// Prefer the previous sibling, matching Backspace/Delete semantics.\n\tconst prevSibling = siblings[index - 1];\n\tif (prevSibling && isBlockNode(prevSibling)) {\n\t\tconst selection = createSelectionForBlockBoundary(state, prevSibling.id, 'end');\n\t\tif (selection) {\n\t\t\tbuilder.setSelection(selection);\n\t\t\treturn builder.build();\n\t\t}\n\t}\n\n\tconst nextSibling = siblings[index + 1];\n\tif (nextSibling && isBlockNode(nextSibling)) {\n\t\tconst selection = createSelectionForBlockBoundary(state, nextSibling.id, 'start');\n\t\tif (selection) {\n\t\t\tbuilder.setSelection(selection);\n\t\t\treturn builder.build();\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * The void block's trailing escape line, when it already exists as an empty\n * paragraph. A void block at the document root always owns such a paragraph\n * (#152/#158), so reusing it stops a second blank line from stacking up when\n * text or a paragraph is inserted while the void is node-selected (#163).\n * Returns undefined when there is no reusable line (a non-empty sibling, or the\n * void is the last block), so callers fall back to creating one.\n */\nfunction trailingEscapeParagraph(\n\tsiblings: readonly ChildNode[],\n\tindex: number,\n): BlockNode | undefined {\n\tif (index < 0) return undefined;\n\tconst next: ChildNode | undefined = siblings[index + 1];\n\treturn next && isBlockNode(next) && isEmptyParagraph(next) ? next : undefined;\n}\n\n/**\n * Places a collapsed cursor on an empty paragraph after a node-selected void\n * block (Enter). Reuses the void's existing trailing escape line when present so\n * no blank line stacks up (#163); otherwise inserts a fresh paragraph.\n */\nexport function insertParagraphAfterNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n): Transaction | null {\n\tconst { parentPath, siblings, index } = resolveSiblingContext(state, sel.nodeId);\n\tif (index < 0) return null;\n\n\tconst trailing: BlockNode | undefined = trailingEscapeParagraph(siblings, index);\n\tif (trailing) {\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createCollapsedSelection(trailing.id, 0))\n\t\t\t.build();\n\t}\n\n\tconst newId = generateBlockId();\n\tconst builder = state.transaction('input');\n\tbuilder.insertNode(parentPath, index + 1, createEmptyParagraph(newId));\n\tbuilder.setSelection(createCollapsedSelection(newId, 0));\n\treturn builder.build();\n}\n\n/**\n * Inserts text on a paragraph after a node-selected void block (typing). Reuses\n * the void's existing trailing escape line when present so no blank line stacks\n * up (#163); otherwise inserts a fresh paragraph to hold the text.\n */\nexport function insertTextAfterNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n\ttext: string,\n\torigin: 'input' | 'paste',\n): Transaction {\n\tconst { parentPath, siblings, index } = resolveSiblingContext(state, sel.nodeId);\n\tconst builder = state.transaction(origin);\n\n\tconst trailing: BlockNode | undefined = trailingEscapeParagraph(siblings, index);\n\tif (trailing) {\n\t\tbuilder.insertText(trailing.id, 0, text, []);\n\t\tbuilder.setSelection(createCollapsedSelection(trailing.id, text.length));\n\t\treturn builder.build();\n\t}\n\n\tconst newId = generateBlockId();\n\tconst insertIdx = index >= 0 ? index + 1 : siblings.length;\n\tbuilder.insertNode(parentPath, insertIdx, createEmptyParagraph(newId));\n\tbuilder.insertText(newId, 0, text, []);\n\tbuilder.setSelection(createCollapsedSelection(newId, text.length));\n\treturn builder.build();\n}\n\n/**\n * Navigates arrow keys into/out of void blocks.\n * Returns a transaction if navigation should create a NodeSelection, or null.\n *\n * @param isRtl — When true, flips left/right to account for RTL block direction.\n */\nexport function navigateArrowIntoVoid(\n\tstate: EditorState,\n\tdirection: 'left' | 'right' | 'up' | 'down',\n\tisRtl?: boolean,\n): Transaction | null {\n\tconst sel = state.selection;\n\tconst blockOrder = state.getBlockOrder();\n\tconst effectiveDir: 'left' | 'right' | 'up' | 'down' =\n\t\tisRtl && (direction === 'left' || direction === 'right')\n\t\t\t? direction === 'left'\n\t\t\t\t? 'right'\n\t\t\t\t: 'left'\n\t\t\t: direction;\n\n\t// If currently on a NodeSelection, navigate away from it\n\tif (isNodeSelection(sel)) {\n\t\treturn navigateAwayFromNodeSelection(state, sel, effectiveDir, blockOrder);\n\t}\n\n\t// GapCursor is handled by navigateFromGapCursor in CaretNavigation\n\tif (isGapCursor(sel)) return null;\n\n\t// Text selection: check if navigating into a void block\n\tif (!isCollapsed(sel)) return null;\n\n\treturn navigateIntoVoid(state, sel, effectiveDir, blockOrder);\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** Handles navigation away from a NodeSelection (arrow keys while void is selected). */\nfunction navigateAwayFromNodeSelection(\n\tstate: EditorState,\n\tsel: NodeSelection,\n\tdirection: 'left' | 'right' | 'up' | 'down',\n\tblockOrder: readonly BlockId[],\n): Transaction | null {\n\tconst nodeIdx = blockOrder.indexOf(sel.nodeId);\n\tconst nodePath = (findNodePath(state.doc, sel.nodeId) ?? []) as BlockId[];\n\n\tif (direction === 'left' || direction === 'up') {\n\t\tif (nodeIdx > 0) {\n\t\t\tconst prevId = blockOrder[nodeIdx - 1];\n\t\t\tif (!prevId) return null;\n\t\t\tif (isVoidBlock(state, prevId)) {\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createGapCursor(sel.nodeId, 'before', nodePath))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t\tconst prevBlock = state.getBlock(prevId);\n\t\t\tconst prevLen = prevBlock ? getBlockLength(prevBlock) : 0;\n\t\t\treturn state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setSelection(createCollapsedSelection(prevId, prevLen))\n\t\t\t\t.build();\n\t\t}\n\t\treturn state\n\t\t\t.transaction('input')\n\t\t\t.setSelection(createGapCursor(sel.nodeId, 'before', nodePath))\n\t\t\t.build();\n\t}\n\n\t// right or down\n\tif (nodeIdx < blockOrder.length - 1) {\n\t\tconst nextId = blockOrder[nodeIdx + 1];\n\t\tif (!nextId) return null;\n\t\tif (isVoidBlock(state, nextId)) {\n\t\t\treturn state\n\t\t\t\t.transaction('input')\n\t\t\t\t.setSelection(createGapCursor(sel.nodeId, 'after', nodePath))\n\t\t\t\t.build();\n\t\t}\n\t\treturn state.transaction('input').setSelection(createCollapsedSelection(nextId, 0)).build();\n\t}\n\treturn state\n\t\t.transaction('input')\n\t\t.setSelection(createGapCursor(sel.nodeId, 'after', nodePath))\n\t\t.build();\n}\n\n/** Handles text selection navigating into an adjacent void block. */\nfunction navigateIntoVoid(\n\tstate: EditorState,\n\tsel: { readonly anchor: { readonly blockId: BlockId; readonly offset: number } },\n\tdirection: 'left' | 'right' | 'up' | 'down',\n\tblockOrder: readonly BlockId[],\n): Transaction | null {\n\tconst blockIdx = blockOrder.indexOf(sel.anchor.blockId);\n\tconst block = state.getBlock(sel.anchor.blockId);\n\tif (!block) return null;\n\tconst blockLen = getBlockLength(block);\n\n\tif (direction === 'right' || direction === 'down') {\n\t\tif (sel.anchor.offset === blockLen && blockIdx < blockOrder.length - 1) {\n\t\t\tconst nextId = blockOrder[blockIdx + 1];\n\t\t\tif (nextId && isVoidBlock(state, nextId)) {\n\t\t\t\tconst path = findNodePath(state.doc, nextId) ?? [];\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createNodeSelection(nextId, path as BlockId[]))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (direction === 'left' || direction === 'up') {\n\t\tif (sel.anchor.offset === 0 && blockIdx > 0) {\n\t\t\tconst prevId = blockOrder[blockIdx - 1];\n\t\t\tif (prevId && isVoidBlock(state, prevId)) {\n\t\t\t\tconst path = findNodePath(state.doc, prevId) ?? [];\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.setSelection(createNodeSelection(prevId, path as BlockId[]))\n\t\t\t\t\t.build();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{i as e}from"./Platform-ByobkiCc.mjs";import{n as t}from"./TypedKeys-CA4bfw9O.mjs";import{i as s,r as n,t as o}from"./PopupPositioning-BB97-__N.mjs";var r=new t("popup"),i=class{stack=[];referenceNode;constructor(e){this.referenceNode=e}open(e){const t=document.createElement("div");t.className=e.className?`notectl-popup ${e.className}`:"notectl-popup",e.ariaRole&&t.setAttribute("role",e.ariaRole),e.ariaLabel&&t.setAttribute("aria-label",e.ariaLabel);const r=e.parent?this.findEntryByHandle(e.parent):null;let i;const c={close:e=>this.closeEntry(i,e),getElement:()=>t},l=s=>{const n=s.composedPath();if(!n.includes(t)){for(const e of this.stack)if(n.includes(e.element))return;e.anchor instanceof HTMLElement&&n.includes(e.anchor)||this.closeEntry(i)}};i={element:t,config:e,clickOutsideHandler:l,parent:r,listenerRegistrationTimer:null,documentListenerAttached:!1},this.stack.push(i);try{e.content(t,e=>this.closeEntry(i,e))}catch(a){throw this.removeEntry(i),a}return this.stack.includes(i)?(o(t,e.referenceNode??this.referenceNode),s(t),n(t,e.anchor instanceof HTMLElement?e.anchor.getBoundingClientRect():e.anchor,{position:e.position??"below-start",isRtl:this.isRtlContext()}),i.listenerRegistrationTimer=setTimeout(()=>{i.listenerRegistrationTimer=null,this.stack.includes(i)&&(document.addEventListener("mousedown",l),i.documentListenerAttached=!0)},0),this.focusFirstItem(t),c):c}close(){const e=this.stack[this.stack.length-1];e&&this.closeEntry(e)}closeAll(){for(;this.stack.length>0;){const e=this.stack[this.stack.length-1];e&&this.closeEntry(e)}}isOpen(){return this.stack.length>0}destroy(){this.closeAll()}closeEntry(e,t){const s=this.stack.indexOf(e);if(-1!==s){for(;this.stack.length>s+1;){const e=this.stack[this.stack.length-1];e&&this.removeEntry(e)}this.removeEntry(e),void 0!==t&&"restoreFocusTo"in t?t.restoreFocusTo?.focus():e.config.restoreFocusTo&&e.config.restoreFocusTo.focus(),e.config.onClose?.()}}removeEntry(e){const t=this.stack.indexOf(e);-1!==t&&(this.stack.splice(t,1),null!==e.listenerRegistrationTimer&&(clearTimeout(e.listenerRegistrationTimer),e.listenerRegistrationTimer=null),e.element.remove(),e.documentListenerAttached&&(document.removeEventListener("mousedown",e.clickOutsideHandler),e.documentListenerAttached=!1))}findEntryByHandle(e){const t=e.getElement();return this.stack.find(e=>e.element===t)??null}isRtlContext(){return this.referenceNode instanceof HTMLElement&&e(this.referenceNode)}focusFirstItem(e){requestAnimationFrame(()=>{(e.querySelector('[role="menuitem"]')??e.querySelector('[role="option"]')??e.querySelector('[role="gridcell"]')??e.querySelector("input, textarea")??e.querySelector("button"))?.focus()})}};export{r as n,i as t};
2
- //# sourceMappingURL=PopupManager-DUtaK3WX.mjs.map
1
+ import{n as e}from"./TypedKeys-CA4bfw9O.mjs";import{i as t}from"./Platform-ByobkiCc.mjs";import{a as s,i as n,t as o}from"./PopupPositioning-BFh6Ed1D.mjs";var r=new e("popup"),i=class{stack=[];referenceNode;constructor(e){this.referenceNode=e}open(e){const t=document.createElement("div");t.className=e.className?`notectl-popup ${e.className}`:"notectl-popup",e.ariaRole&&t.setAttribute("role",e.ariaRole),e.ariaLabel&&t.setAttribute("aria-label",e.ariaLabel);const r=e.parent?this.findEntryByHandle(e.parent):null;let i;const c={close:e=>this.closeEntry(i,e),getElement:()=>t},l=s=>{const n=s.composedPath();if(!n.includes(t)){for(const e of this.stack)if(n.includes(e.element))return;e.anchor instanceof HTMLElement&&n.includes(e.anchor)||this.closeEntry(i)}};i={element:t,config:e,clickOutsideHandler:l,parent:r,listenerRegistrationTimer:null,documentListenerAttached:!1},this.stack.push(i);try{e.content(t,e=>this.closeEntry(i,e))}catch(a){throw this.removeEntry(i),a}return this.stack.includes(i)?(o(t,e.referenceNode??this.referenceNode),s(t),n(t,e.anchor instanceof HTMLElement?e.anchor.getBoundingClientRect():e.anchor,{position:e.position??"below-start",isRtl:this.isRtlContext()}),i.listenerRegistrationTimer=setTimeout(()=>{i.listenerRegistrationTimer=null,this.stack.includes(i)&&(document.addEventListener("mousedown",l),i.documentListenerAttached=!0)},0),this.focusFirstItem(t),c):c}close(){const e=this.stack[this.stack.length-1];e&&this.closeEntry(e)}closeAll(){for(;this.stack.length>0;){const e=this.stack[this.stack.length-1];e&&this.closeEntry(e)}}isOpen(){return this.stack.length>0}destroy(){this.closeAll()}closeEntry(e,t){const s=this.stack.indexOf(e);if(-1!==s){for(;this.stack.length>s+1;){const e=this.stack[this.stack.length-1];e&&this.removeEntry(e)}this.removeEntry(e),void 0!==t&&"restoreFocusTo"in t?t.restoreFocusTo?.focus():e.config.restoreFocusTo&&e.config.restoreFocusTo.focus(),e.config.onClose?.()}}removeEntry(e){const t=this.stack.indexOf(e);-1!==t&&(this.stack.splice(t,1),null!==e.listenerRegistrationTimer&&(clearTimeout(e.listenerRegistrationTimer),e.listenerRegistrationTimer=null),e.element.remove(),e.documentListenerAttached&&(document.removeEventListener("mousedown",e.clickOutsideHandler),e.documentListenerAttached=!1))}findEntryByHandle(e){const t=e.getElement();return this.stack.find(e=>e.element===t)??null}isRtlContext(){return this.referenceNode instanceof HTMLElement&&t(this.referenceNode)}focusFirstItem(e){requestAnimationFrame(()=>{(e.querySelector('[role="menuitem"]')??e.querySelector('[role="option"]')??e.querySelector('[role="gridcell"]')??e.querySelector("input, textarea")??e.querySelector("button"))?.focus()})}};export{r as n,i as t};
2
+ //# sourceMappingURL=PopupManager-Cj86uDEB.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"PopupManager-DUtaK3WX.mjs","names":[],"sources":["../../src/plugins/shared/PopupManager.ts"],"sourcesContent":["/**\n * Central popup lifecycle manager. Handles creation, positioning,\n * click-outside closing, Escape key, focus restoration, and popup stacking\n * for submenus/nested popups.\n */\n\nimport { isRtlContext } from '../../platform/Platform.js';\nimport { ServiceKey } from '../Plugin.js';\nimport {\n\ttype PopupPosition,\n\tappendToRoot,\n\tpositionPopup,\n\tpromoteToTopLayer,\n} from './PopupPositioning.js';\n\n// --- Types ---\n\n/** Options for overriding focus restoration when closing a popup. */\nexport interface PopupCloseOptions {\n\t/**\n\t * Override the default focus target on close.\n\t * - `HTMLElement` → focus that element instead of `config.restoreFocusTo`\n\t * - `null` → skip focus restoration entirely\n\t * - `undefined` / omitted → use default `config.restoreFocusTo`\n\t */\n\treadonly restoreFocusTo?: HTMLElement | null;\n}\n\nexport interface PopupConfig {\n\treadonly anchor: HTMLElement | DOMRect;\n\treadonly content: (container: HTMLElement, close: (options?: PopupCloseOptions) => void) => void;\n\treadonly className?: string;\n\treadonly ariaRole?: 'menu' | 'listbox' | 'grid' | 'dialog';\n\treadonly ariaLabel?: string;\n\treadonly restoreFocusTo?: HTMLElement;\n\treadonly onClose?: () => void;\n\treadonly position?: PopupPosition;\n\treadonly parent?: PopupHandle;\n\treadonly referenceNode?: Node;\n}\n\nexport interface PopupHandle {\n\tclose(options?: PopupCloseOptions): void;\n\tgetElement(): HTMLElement;\n}\n\nexport interface PopupServiceAPI {\n\topen(config: PopupConfig): PopupHandle;\n\tclose(): void;\n\tcloseAll(): void;\n\tisOpen(): boolean;\n}\n\nexport const PopupServiceKey = new ServiceKey<PopupServiceAPI>('popup');\n\n// --- Internal Entry ---\n\ninterface PopupEntry {\n\treadonly element: HTMLElement;\n\treadonly config: PopupConfig;\n\treadonly clickOutsideHandler: (e: MouseEvent) => void;\n\treadonly parent: PopupEntry | null;\n\tlistenerRegistrationTimer: ReturnType<typeof setTimeout> | null;\n\tdocumentListenerAttached: boolean;\n}\n\n// --- Manager ---\n\nexport class PopupManager implements PopupServiceAPI {\n\tprivate readonly stack: PopupEntry[] = [];\n\tprivate readonly referenceNode: Node;\n\n\tconstructor(referenceNode: Node) {\n\t\tthis.referenceNode = referenceNode;\n\t}\n\n\t/** Opens a popup with the given configuration. Returns a handle for closing it. */\n\topen(config: PopupConfig): PopupHandle {\n\t\tconst popup: HTMLDivElement = document.createElement('div');\n\t\tpopup.className = config.className ? `notectl-popup ${config.className}` : 'notectl-popup';\n\n\t\tif (config.ariaRole) {\n\t\t\tpopup.setAttribute('role', config.ariaRole);\n\t\t}\n\t\tif (config.ariaLabel) {\n\t\t\tpopup.setAttribute('aria-label', config.ariaLabel);\n\t\t}\n\n\t\tconst parentEntry: PopupEntry | null = config.parent\n\t\t\t? this.findEntryByHandle(config.parent)\n\t\t\t: null;\n\n\t\tlet entry!: PopupEntry;\n\t\tconst handle: PopupHandle = {\n\t\t\tclose: (options?: PopupCloseOptions) => this.closeEntry(entry, options),\n\t\t\tgetElement: () => popup,\n\t\t};\n\n\t\tconst clickOutsideHandler = (e: MouseEvent): void => {\n\t\t\tconst path: EventTarget[] = e.composedPath();\n\t\t\tif (path.includes(popup)) return;\n\n\t\t\t// Don't close if click is inside any ancestor popup in the stack\n\t\t\tfor (const stackEntry of this.stack) {\n\t\t\t\tif (path.includes(stackEntry.element)) return;\n\t\t\t}\n\n\t\t\t// Don't close if click is on the anchor element\n\t\t\tif (config.anchor instanceof HTMLElement && path.includes(config.anchor)) return;\n\n\t\t\tthis.closeEntry(entry);\n\t\t};\n\n\t\tentry = {\n\t\t\telement: popup,\n\t\t\tconfig,\n\t\t\tclickOutsideHandler,\n\t\t\tparent: parentEntry,\n\t\t\tlistenerRegistrationTimer: null,\n\t\t\tdocumentListenerAttached: false,\n\t\t};\n\n\t\tthis.stack.push(entry);\n\n\t\ttry {\n\t\t\tconfig.content(popup, (options?: PopupCloseOptions) => this.closeEntry(entry, options));\n\t\t} catch (error) {\n\t\t\tthis.removeEntry(entry);\n\t\t\tthrow error;\n\t\t}\n\n\t\tif (!this.stack.includes(entry)) {\n\t\t\treturn handle;\n\t\t}\n\n\t\tconst refNode: Node = config.referenceNode ?? this.referenceNode;\n\t\tappendToRoot(popup, refNode);\n\t\t// Promote to the top layer before measuring/positioning so the popup\n\t\t// escapes any ancestor stacking context in the host page.\n\t\tpromoteToTopLayer(popup);\n\n\t\tconst anchorRect: DOMRect =\n\t\t\tconfig.anchor instanceof HTMLElement ? config.anchor.getBoundingClientRect() : config.anchor;\n\t\tpositionPopup(popup, anchorRect, {\n\t\t\tposition: config.position ?? 'below-start',\n\t\t\tisRtl: this.isRtlContext(),\n\t\t});\n\n\t\tentry.listenerRegistrationTimer = setTimeout(() => {\n\t\t\tentry.listenerRegistrationTimer = null;\n\t\t\tif (!this.stack.includes(entry)) return;\n\t\t\tdocument.addEventListener('mousedown', clickOutsideHandler);\n\t\t\tentry.documentListenerAttached = true;\n\t\t}, 0);\n\n\t\tthis.focusFirstItem(popup);\n\n\t\treturn handle;\n\t}\n\n\t/** Closes the topmost popup in the stack. */\n\tclose(): void {\n\t\tconst top: PopupEntry | undefined = this.stack[this.stack.length - 1];\n\t\tif (top) {\n\t\t\tthis.closeEntry(top);\n\t\t}\n\t}\n\n\t/** Closes all open popups. */\n\tcloseAll(): void {\n\t\twhile (this.stack.length > 0) {\n\t\t\tconst top: PopupEntry | undefined = this.stack[this.stack.length - 1];\n\t\t\tif (top) {\n\t\t\t\tthis.closeEntry(top);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Returns true if any popup is currently open. */\n\tisOpen(): boolean {\n\t\treturn this.stack.length > 0;\n\t}\n\n\t/** Cleans up all popups and event listeners. */\n\tdestroy(): void {\n\t\tthis.closeAll();\n\t}\n\n\t// --- Internal ---\n\n\tprivate closeEntry(entry: PopupEntry, options?: PopupCloseOptions): void {\n\t\tconst index: number = this.stack.indexOf(entry);\n\t\tif (index === -1) return;\n\n\t\t// Close all child popups first (anything above this entry in the stack)\n\t\twhile (this.stack.length > index + 1) {\n\t\t\tconst child: PopupEntry | undefined = this.stack[this.stack.length - 1];\n\t\t\tif (child) {\n\t\t\t\tthis.removeEntry(child);\n\t\t\t}\n\t\t}\n\n\t\tthis.removeEntry(entry);\n\n\t\tif (options !== undefined && 'restoreFocusTo' in options) {\n\t\t\toptions.restoreFocusTo?.focus();\n\t\t} else if (entry.config.restoreFocusTo) {\n\t\t\tentry.config.restoreFocusTo.focus();\n\t\t}\n\t\tentry.config.onClose?.();\n\t}\n\n\tprivate removeEntry(entry: PopupEntry): void {\n\t\tconst index: number = this.stack.indexOf(entry);\n\t\tif (index === -1) return;\n\n\t\tthis.stack.splice(index, 1);\n\t\tif (entry.listenerRegistrationTimer !== null) {\n\t\t\tclearTimeout(entry.listenerRegistrationTimer);\n\t\t\tentry.listenerRegistrationTimer = null;\n\t\t}\n\t\tentry.element.remove();\n\t\tif (entry.documentListenerAttached) {\n\t\t\tdocument.removeEventListener('mousedown', entry.clickOutsideHandler);\n\t\t\tentry.documentListenerAttached = false;\n\t\t}\n\t}\n\n\tprivate findEntryByHandle(handle: PopupHandle): PopupEntry | null {\n\t\tconst element: HTMLElement = handle.getElement();\n\t\treturn this.stack.find((e) => e.element === element) ?? null;\n\t}\n\n\t/** Detects whether the editor context is RTL from the computed style. */\n\tprivate isRtlContext(): boolean {\n\t\tif (this.referenceNode instanceof HTMLElement) {\n\t\t\treturn isRtlContext(this.referenceNode);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate focusFirstItem(popup: HTMLElement): void {\n\t\trequestAnimationFrame(() => {\n\t\t\tconst firstFocusable: HTMLElement | null =\n\t\t\t\tpopup.querySelector('[role=\"menuitem\"]') ??\n\t\t\t\tpopup.querySelector('[role=\"option\"]') ??\n\t\t\t\tpopup.querySelector('[role=\"gridcell\"]') ??\n\t\t\t\t// `input, textarea` returns whichever comes first in the DOM, so a\n\t\t\t\t// popup whose primary field is a textarea (e.g. the formula editor's\n\t\t\t\t// LaTeX field) focuses that rather than a later text input.\n\t\t\t\tpopup.querySelector('input, textarea') ??\n\t\t\t\tpopup.querySelector('button');\n\t\t\tfirstFocusable?.focus();\n\t\t});\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PopupManager-Cj86uDEB.mjs","names":[],"sources":["../../src/plugins/shared/PopupManager.ts"],"sourcesContent":["/**\n * Central popup lifecycle manager. Handles creation, positioning,\n * click-outside closing, Escape key, focus restoration, and popup stacking\n * for submenus/nested popups.\n */\n\nimport { isRtlContext } from '../../platform/Platform.js';\nimport { ServiceKey } from '../Plugin.js';\nimport {\n\ttype PopupPosition,\n\tappendToRoot,\n\tpositionPopup,\n\tpromoteToTopLayer,\n} from './PopupPositioning.js';\n\n// --- Types ---\n\n/** Options for overriding focus restoration when closing a popup. */\nexport interface PopupCloseOptions {\n\t/**\n\t * Override the default focus target on close.\n\t * - `HTMLElement` → focus that element instead of `config.restoreFocusTo`\n\t * - `null` → skip focus restoration entirely\n\t * - `undefined` / omitted → use default `config.restoreFocusTo`\n\t */\n\treadonly restoreFocusTo?: HTMLElement | null;\n}\n\nexport interface PopupConfig {\n\treadonly anchor: HTMLElement | DOMRect;\n\treadonly content: (container: HTMLElement, close: (options?: PopupCloseOptions) => void) => void;\n\treadonly className?: string;\n\treadonly ariaRole?: 'menu' | 'listbox' | 'grid' | 'dialog';\n\treadonly ariaLabel?: string;\n\treadonly restoreFocusTo?: HTMLElement;\n\treadonly onClose?: () => void;\n\treadonly position?: PopupPosition;\n\treadonly parent?: PopupHandle;\n\treadonly referenceNode?: Node;\n}\n\nexport interface PopupHandle {\n\tclose(options?: PopupCloseOptions): void;\n\tgetElement(): HTMLElement;\n}\n\nexport interface PopupServiceAPI {\n\topen(config: PopupConfig): PopupHandle;\n\tclose(): void;\n\tcloseAll(): void;\n\tisOpen(): boolean;\n}\n\nexport const PopupServiceKey = new ServiceKey<PopupServiceAPI>('popup');\n\n// --- Internal Entry ---\n\ninterface PopupEntry {\n\treadonly element: HTMLElement;\n\treadonly config: PopupConfig;\n\treadonly clickOutsideHandler: (e: MouseEvent) => void;\n\treadonly parent: PopupEntry | null;\n\tlistenerRegistrationTimer: ReturnType<typeof setTimeout> | null;\n\tdocumentListenerAttached: boolean;\n}\n\n// --- Manager ---\n\nexport class PopupManager implements PopupServiceAPI {\n\tprivate readonly stack: PopupEntry[] = [];\n\tprivate readonly referenceNode: Node;\n\n\tconstructor(referenceNode: Node) {\n\t\tthis.referenceNode = referenceNode;\n\t}\n\n\t/** Opens a popup with the given configuration. Returns a handle for closing it. */\n\topen(config: PopupConfig): PopupHandle {\n\t\tconst popup: HTMLDivElement = document.createElement('div');\n\t\tpopup.className = config.className ? `notectl-popup ${config.className}` : 'notectl-popup';\n\n\t\tif (config.ariaRole) {\n\t\t\tpopup.setAttribute('role', config.ariaRole);\n\t\t}\n\t\tif (config.ariaLabel) {\n\t\t\tpopup.setAttribute('aria-label', config.ariaLabel);\n\t\t}\n\n\t\tconst parentEntry: PopupEntry | null = config.parent\n\t\t\t? this.findEntryByHandle(config.parent)\n\t\t\t: null;\n\n\t\tlet entry!: PopupEntry;\n\t\tconst handle: PopupHandle = {\n\t\t\tclose: (options?: PopupCloseOptions) => this.closeEntry(entry, options),\n\t\t\tgetElement: () => popup,\n\t\t};\n\n\t\tconst clickOutsideHandler = (e: MouseEvent): void => {\n\t\t\tconst path: EventTarget[] = e.composedPath();\n\t\t\tif (path.includes(popup)) return;\n\n\t\t\t// Don't close if click is inside any ancestor popup in the stack\n\t\t\tfor (const stackEntry of this.stack) {\n\t\t\t\tif (path.includes(stackEntry.element)) return;\n\t\t\t}\n\n\t\t\t// Don't close if click is on the anchor element\n\t\t\tif (config.anchor instanceof HTMLElement && path.includes(config.anchor)) return;\n\n\t\t\tthis.closeEntry(entry);\n\t\t};\n\n\t\tentry = {\n\t\t\telement: popup,\n\t\t\tconfig,\n\t\t\tclickOutsideHandler,\n\t\t\tparent: parentEntry,\n\t\t\tlistenerRegistrationTimer: null,\n\t\t\tdocumentListenerAttached: false,\n\t\t};\n\n\t\tthis.stack.push(entry);\n\n\t\ttry {\n\t\t\tconfig.content(popup, (options?: PopupCloseOptions) => this.closeEntry(entry, options));\n\t\t} catch (error) {\n\t\t\tthis.removeEntry(entry);\n\t\t\tthrow error;\n\t\t}\n\n\t\tif (!this.stack.includes(entry)) {\n\t\t\treturn handle;\n\t\t}\n\n\t\tconst refNode: Node = config.referenceNode ?? this.referenceNode;\n\t\tappendToRoot(popup, refNode);\n\t\t// Promote to the top layer before measuring/positioning so the popup\n\t\t// escapes any ancestor stacking context in the host page.\n\t\tpromoteToTopLayer(popup);\n\n\t\tconst anchorRect: DOMRect =\n\t\t\tconfig.anchor instanceof HTMLElement ? config.anchor.getBoundingClientRect() : config.anchor;\n\t\tpositionPopup(popup, anchorRect, {\n\t\t\tposition: config.position ?? 'below-start',\n\t\t\tisRtl: this.isRtlContext(),\n\t\t});\n\n\t\tentry.listenerRegistrationTimer = setTimeout(() => {\n\t\t\tentry.listenerRegistrationTimer = null;\n\t\t\tif (!this.stack.includes(entry)) return;\n\t\t\tdocument.addEventListener('mousedown', clickOutsideHandler);\n\t\t\tentry.documentListenerAttached = true;\n\t\t}, 0);\n\n\t\tthis.focusFirstItem(popup);\n\n\t\treturn handle;\n\t}\n\n\t/** Closes the topmost popup in the stack. */\n\tclose(): void {\n\t\tconst top: PopupEntry | undefined = this.stack[this.stack.length - 1];\n\t\tif (top) {\n\t\t\tthis.closeEntry(top);\n\t\t}\n\t}\n\n\t/** Closes all open popups. */\n\tcloseAll(): void {\n\t\twhile (this.stack.length > 0) {\n\t\t\tconst top: PopupEntry | undefined = this.stack[this.stack.length - 1];\n\t\t\tif (top) {\n\t\t\t\tthis.closeEntry(top);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Returns true if any popup is currently open. */\n\tisOpen(): boolean {\n\t\treturn this.stack.length > 0;\n\t}\n\n\t/** Cleans up all popups and event listeners. */\n\tdestroy(): void {\n\t\tthis.closeAll();\n\t}\n\n\t// --- Internal ---\n\n\tprivate closeEntry(entry: PopupEntry, options?: PopupCloseOptions): void {\n\t\tconst index: number = this.stack.indexOf(entry);\n\t\tif (index === -1) return;\n\n\t\t// Close all child popups first (anything above this entry in the stack)\n\t\twhile (this.stack.length > index + 1) {\n\t\t\tconst child: PopupEntry | undefined = this.stack[this.stack.length - 1];\n\t\t\tif (child) {\n\t\t\t\tthis.removeEntry(child);\n\t\t\t}\n\t\t}\n\n\t\tthis.removeEntry(entry);\n\n\t\tif (options !== undefined && 'restoreFocusTo' in options) {\n\t\t\toptions.restoreFocusTo?.focus();\n\t\t} else if (entry.config.restoreFocusTo) {\n\t\t\tentry.config.restoreFocusTo.focus();\n\t\t}\n\t\tentry.config.onClose?.();\n\t}\n\n\tprivate removeEntry(entry: PopupEntry): void {\n\t\tconst index: number = this.stack.indexOf(entry);\n\t\tif (index === -1) return;\n\n\t\tthis.stack.splice(index, 1);\n\t\tif (entry.listenerRegistrationTimer !== null) {\n\t\t\tclearTimeout(entry.listenerRegistrationTimer);\n\t\t\tentry.listenerRegistrationTimer = null;\n\t\t}\n\t\tentry.element.remove();\n\t\tif (entry.documentListenerAttached) {\n\t\t\tdocument.removeEventListener('mousedown', entry.clickOutsideHandler);\n\t\t\tentry.documentListenerAttached = false;\n\t\t}\n\t}\n\n\tprivate findEntryByHandle(handle: PopupHandle): PopupEntry | null {\n\t\tconst element: HTMLElement = handle.getElement();\n\t\treturn this.stack.find((e) => e.element === element) ?? null;\n\t}\n\n\t/** Detects whether the editor context is RTL from the computed style. */\n\tprivate isRtlContext(): boolean {\n\t\tif (this.referenceNode instanceof HTMLElement) {\n\t\t\treturn isRtlContext(this.referenceNode);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate focusFirstItem(popup: HTMLElement): void {\n\t\trequestAnimationFrame(() => {\n\t\t\tconst firstFocusable: HTMLElement | null =\n\t\t\t\tpopup.querySelector('[role=\"menuitem\"]') ??\n\t\t\t\tpopup.querySelector('[role=\"option\"]') ??\n\t\t\t\tpopup.querySelector('[role=\"gridcell\"]') ??\n\t\t\t\t// `input, textarea` returns whichever comes first in the DOM, so a\n\t\t\t\t// popup whose primary field is a textarea (e.g. the formula editor's\n\t\t\t\t// LaTeX field) focuses that rather than a later text input.\n\t\t\t\tpopup.querySelector('input, textarea') ??\n\t\t\t\tpopup.querySelector('button');\n\t\t\tfirstFocusable?.focus();\n\t\t});\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{s as t}from"./StyleRuntime-DW6omotc.mjs";function e(t){const e=t.style.top,o=t.style.left,i=t.style.right;t.style.top="0px",t.style.left="0px",t.style.right="auto";const n=t.getBoundingClientRect(),l=n.left,s=n.top;t.style.left="auto",t.style.right="0px";const r=t.getBoundingClientRect(),p=window.innerWidth-r.right;return t.style.top=e,t.style.left=o,t.style.right=i,{x:l,y:s,rightX:p}}function o(o,i,n){const l=n.offset??2,s=window.innerWidth,r=window.innerHeight;t(o,{position:"fixed",zIndex:"10000"});const p=e(o),a=o.offsetWidth,f=o.offsetHeight,h={};switch(n.position){case"below-start":{let t=i.bottom+l;if(n.isRtl){let e=s-i.right;e+a>s-4&&(e=s-a-4),t+f>r-4&&(t=i.top-f-l),e<4&&(e=4),t<4&&(t=4),h.top=t-p.y+"px",h.right=e-p.rightX+"px",h.left="auto"}else{let e=i.left;e+a>s-4&&(e=s-a-4),t+f>r-4&&(t=i.top-f-l),e<4&&(e=4),t<4&&(t=4),h.top=t-p.y+"px",h.left=e-p.x+"px",h.right="auto"}break}case"below-end":{let t=i.bottom+l;if(n.isRtl){let e=i.left;e+a>s-4&&(e=s-a-4),t+f>r-4&&(t=i.top-f-l),e<4&&(e=4),t<4&&(t=4),h.top=t-p.y+"px",h.left=e-p.x+"px",h.right="auto"}else{let e=s-i.right;e+a>s-4&&(e=s-a-4),t+f>r-4&&(t=i.top-f-l),e<4&&(e=4),t<4&&(t=4),h.top=t-p.y+"px",h.right=e-p.rightX+"px",h.left="auto"}break}case"right":{let t=i.top;if(n.isRtl){let e=i.left-a-l;e<4&&(e=i.right+l),t+f>r-4&&(t=r-f-4),e<4&&(e=4),t<4&&(t=4),h.top=t-p.y+"px",h.left=e-p.x+"px",h.right="auto"}else{let e=i.right+l;e+a>s-4&&(e=i.left-a-l),t+f>r-4&&(t=r-f-4),e<4&&(e=4),t<4&&(t=4),h.top=t-p.y+"px",h.left=e-p.x+"px",h.right="auto"}break}}t(o,h)}function i(t,e){const o=e.getRootNode();o instanceof ShadowRoot?o.appendChild(t):document.body.appendChild(t)}function n(t){const e=t.getRootNode();let o=e instanceof ShadowRoot||e instanceof Document?e.activeElement:document.activeElement;for(;o?.shadowRoot?.activeElement;)o=o.shadowRoot.activeElement;return o instanceof HTMLElement?o:null}function l(e){if("function"==typeof e.showPopover){e.setAttribute("popover","manual");try{e.showPopover()}catch{return void e.removeAttribute("popover")}t(e,{margin:"0",inset:"auto"})}}export{l as a,o as i,n,e as r,i as t};
2
+ //# sourceMappingURL=PopupPositioning-BFh6Ed1D.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"PopupPositioning-BB97-__N.mjs","names":[],"sources":["../../src/plugins/shared/PopupPositioning.ts"],"sourcesContent":["/**\n * Shared popup positioning logic. Positions a popup element relative to an\n * anchor rectangle, clamping to the viewport. Also provides a shadow DOM-aware\n * append helper.\n */\n\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\n\n// --- Types ---\n\nexport type PopupPosition = 'below-start' | 'below-end' | 'right';\n\nexport interface PositionOptions {\n\treadonly position: PopupPosition;\n\treadonly offset?: number;\n\treadonly isRtl?: boolean;\n}\n\nexport interface ContainingBlockOffset {\n\treadonly x: number;\n\treadonly y: number;\n\treadonly rightX: number;\n}\n\n// --- Constants ---\n\nconst DEFAULT_OFFSET = 2;\nconst Z_INDEX = '10000';\nconst POPUP_MIN_MARGIN = 4;\n\n// --- Containing Block Offset ---\n\n/**\n * Measures the offset between the popup's CSS containing block and the\n * viewport. When an ancestor has `transform`, `will-change: transform`,\n * `filter`, or `perspective`, `position: fixed` resolves relative to that\n * ancestor — not the viewport. This probe detects the shift so callers\n * can compensate.\n *\n * Technique: temporarily set `top: 0; left: 0` on the fixed-position\n * element and read `getBoundingClientRect()`. If no containing-block\n * ancestor exists the rect origin is `(0, 0)`; otherwise it equals the\n * ancestor's offset.\n */\nexport function measureContainingBlockOffset(popup: HTMLElement): ContainingBlockOffset {\n\tconst prevTop: string = popup.style.top;\n\tconst prevLeft: string = popup.style.left;\n\tconst prevRight: string = popup.style.right;\n\n\t// Probe 1: left-edge offset\n\tpopup.style.top = '0px';\n\tpopup.style.left = '0px';\n\tpopup.style.right = 'auto';\n\n\tconst leftRect: DOMRect = popup.getBoundingClientRect();\n\tconst x: number = leftRect.left;\n\tconst y: number = leftRect.top;\n\n\t// Probe 2: right-edge offset\n\tpopup.style.left = 'auto';\n\tpopup.style.right = '0px';\n\n\tconst rightRect: DOMRect = popup.getBoundingClientRect();\n\tconst rightX: number = window.innerWidth - rightRect.right;\n\n\tpopup.style.top = prevTop;\n\tpopup.style.left = prevLeft;\n\tpopup.style.right = prevRight;\n\n\treturn { x, y, rightX };\n}\n\n// --- Positioning ---\n\n/**\n * Positions a popup element relative to the given anchor rectangle.\n * Uses fixed positioning and clamps to the viewport edges.\n * Automatically compensates for ancestors that create a new containing\n * block (e.g. `transform`, `will-change: transform`).\n */\nexport function positionPopup(popup: HTMLElement, anchor: DOMRect, options: PositionOptions): void {\n\tconst offset: number = options.offset ?? DEFAULT_OFFSET;\n\tconst vpWidth: number = window.innerWidth;\n\tconst vpHeight: number = window.innerHeight;\n\n\t// Apply fixed positioning first so offsetWidth/offsetHeight reflect\n\t// shrink-to-fit sizing rather than normal-flow block width.\n\tsetStyleProperties(popup, { position: 'fixed', zIndex: Z_INDEX });\n\n\t// Detect containing-block offset caused by ancestor transforms etc.\n\tconst cbOffset: ContainingBlockOffset = measureContainingBlockOffset(popup);\n\n\tconst popupWidth: number = popup.offsetWidth;\n\tconst popupHeight: number = popup.offsetHeight;\n\n\tconst styles: Record<string, string> = {};\n\n\tswitch (options.position) {\n\t\tcase 'below-start': {\n\t\t\tlet top: number = anchor.bottom + offset;\n\n\t\t\tif (options.isRtl) {\n\t\t\t\t// RTL: anchor to physical right edge (visual start)\n\t\t\t\tlet right: number = vpWidth - anchor.right;\n\t\t\t\tif (right + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tright = vpWidth - popupWidth - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = anchor.top - popupHeight - offset;\n\t\t\t\t}\n\t\t\t\tif (right < POPUP_MIN_MARGIN) right = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.right = `${right - cbOffset.rightX}px`;\n\t\t\t\tstyles.left = 'auto';\n\t\t\t} else {\n\t\t\t\tlet left: number = anchor.left;\n\t\t\t\tif (left + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tleft = vpWidth - popupWidth - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = anchor.top - popupHeight - offset;\n\t\t\t\t}\n\t\t\t\tif (left < POPUP_MIN_MARGIN) left = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.left = `${left - cbOffset.x}px`;\n\t\t\t\tstyles.right = 'auto';\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 'below-end': {\n\t\t\tlet top: number = anchor.bottom + offset;\n\n\t\t\tif (options.isRtl) {\n\t\t\t\t// RTL: \"end\" = physical left edge\n\t\t\t\tlet left: number = anchor.left;\n\t\t\t\tif (left + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tleft = vpWidth - popupWidth - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = anchor.top - popupHeight - offset;\n\t\t\t\t}\n\t\t\t\tif (left < POPUP_MIN_MARGIN) left = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.left = `${left - cbOffset.x}px`;\n\t\t\t\tstyles.right = 'auto';\n\t\t\t} else {\n\t\t\t\t// LTR: \"end\" = physical right edge\n\t\t\t\tlet right: number = vpWidth - anchor.right;\n\t\t\t\tif (right + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tright = vpWidth - popupWidth - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = anchor.top - popupHeight - offset;\n\t\t\t\t}\n\t\t\t\tif (right < POPUP_MIN_MARGIN) right = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.right = `${right - cbOffset.rightX}px`;\n\t\t\t\tstyles.left = 'auto';\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 'right': {\n\t\t\tlet top: number = anchor.top;\n\n\t\t\tif (options.isRtl) {\n\t\t\t\t// RTL: open submenu to the physical left\n\t\t\t\tlet left: number = anchor.left - popupWidth - offset;\n\t\t\t\tif (left < POPUP_MIN_MARGIN) {\n\t\t\t\t\tleft = anchor.right + offset;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = vpHeight - popupHeight - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (left < POPUP_MIN_MARGIN) left = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.left = `${left - cbOffset.x}px`;\n\t\t\t\tstyles.right = 'auto';\n\t\t\t} else {\n\t\t\t\tlet left: number = anchor.right + offset;\n\t\t\t\tif (left + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tleft = anchor.left - popupWidth - offset;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = vpHeight - popupHeight - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (left < POPUP_MIN_MARGIN) left = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.left = `${left - cbOffset.x}px`;\n\t\t\t\tstyles.right = 'auto';\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tsetStyleProperties(popup, styles);\n}\n\n/**\n * Appends an element to the appropriate root: the shadow root if the\n * reference node lives inside one, otherwise `document.body`.\n */\nexport function appendToRoot(element: HTMLElement, referenceNode: Node): void {\n\tconst root: Node = referenceNode.getRootNode();\n\tif (root instanceof ShadowRoot) {\n\t\troot.appendChild(element);\n\t} else {\n\t\tdocument.body.appendChild(element);\n\t}\n}\n\n/**\n * Promotes a popup/overlay to the browser's top layer via the Popover API so it\n * paints above — and receives pointer events ahead of — every stacking context\n * in the host page. A high `z-index` alone is not enough: an ancestor that forms\n * a stacking context (e.g. Starlight's `isolation: isolate` content wrapper)\n * traps the popup below a sibling such as the fixed table-of-contents sidebar,\n * so clicks on the overlapped region hit the sidebar and dismiss the popup.\n *\n * The element keeps living in the editor's shadow DOM, so its registered styles\n * still apply; only its paint layer changes. Must be called while the element is\n * connected to the document and BEFORE positioning, so subsequent\n * `offsetWidth`/containing-block measurements reflect the displayed top-layer\n * box.\n *\n * No-ops when the Popover API is unavailable (older engines, happy-dom in unit\n * tests); callers then fall back to plain `z-index` stacking. Neutralizes the UA\n * popover box styles (`inset: 0; margin: auto`) so the caller's explicit\n * `top`/`left` placement is what positions the element.\n */\nexport function promoteToTopLayer(element: HTMLElement): void {\n\tif (typeof element.showPopover !== 'function') return;\n\telement.setAttribute('popover', 'manual');\n\ttry {\n\t\telement.showPopover();\n\t} catch {\n\t\telement.removeAttribute('popover');\n\t\treturn;\n\t}\n\tsetStyleProperties(element, { margin: '0', inset: 'auto' });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PopupPositioning-BFh6Ed1D.mjs","names":[],"sources":["../../src/plugins/shared/PopupPositioning.ts"],"sourcesContent":["/**\n * Shared popup positioning logic. Positions a popup element relative to an\n * anchor rectangle, clamping to the viewport. Also provides a shadow DOM-aware\n * append helper.\n */\n\nimport { setStyleProperties } from '../../style/StyleRuntime.js';\n\n// --- Types ---\n\nexport type PopupPosition = 'below-start' | 'below-end' | 'right';\n\nexport interface PositionOptions {\n\treadonly position: PopupPosition;\n\treadonly offset?: number;\n\treadonly isRtl?: boolean;\n}\n\nexport interface ContainingBlockOffset {\n\treadonly x: number;\n\treadonly y: number;\n\treadonly rightX: number;\n}\n\n// --- Constants ---\n\nconst DEFAULT_OFFSET = 2;\nconst Z_INDEX = '10000';\nconst POPUP_MIN_MARGIN = 4;\n\n// --- Containing Block Offset ---\n\n/**\n * Measures the offset between the popup's CSS containing block and the\n * viewport. When an ancestor has `transform`, `will-change: transform`,\n * `filter`, or `perspective`, `position: fixed` resolves relative to that\n * ancestor — not the viewport. This probe detects the shift so callers\n * can compensate.\n *\n * Technique: temporarily set `top: 0; left: 0` on the fixed-position\n * element and read `getBoundingClientRect()`. If no containing-block\n * ancestor exists the rect origin is `(0, 0)`; otherwise it equals the\n * ancestor's offset.\n */\nexport function measureContainingBlockOffset(popup: HTMLElement): ContainingBlockOffset {\n\tconst prevTop: string = popup.style.top;\n\tconst prevLeft: string = popup.style.left;\n\tconst prevRight: string = popup.style.right;\n\n\t// Probe 1: left-edge offset\n\tpopup.style.top = '0px';\n\tpopup.style.left = '0px';\n\tpopup.style.right = 'auto';\n\n\tconst leftRect: DOMRect = popup.getBoundingClientRect();\n\tconst x: number = leftRect.left;\n\tconst y: number = leftRect.top;\n\n\t// Probe 2: right-edge offset\n\tpopup.style.left = 'auto';\n\tpopup.style.right = '0px';\n\n\tconst rightRect: DOMRect = popup.getBoundingClientRect();\n\tconst rightX: number = window.innerWidth - rightRect.right;\n\n\tpopup.style.top = prevTop;\n\tpopup.style.left = prevLeft;\n\tpopup.style.right = prevRight;\n\n\treturn { x, y, rightX };\n}\n\n// --- Positioning ---\n\n/**\n * Positions a popup element relative to the given anchor rectangle.\n * Uses fixed positioning and clamps to the viewport edges.\n * Automatically compensates for ancestors that create a new containing\n * block (e.g. `transform`, `will-change: transform`).\n */\nexport function positionPopup(popup: HTMLElement, anchor: DOMRect, options: PositionOptions): void {\n\tconst offset: number = options.offset ?? DEFAULT_OFFSET;\n\tconst vpWidth: number = window.innerWidth;\n\tconst vpHeight: number = window.innerHeight;\n\n\t// Apply fixed positioning first so offsetWidth/offsetHeight reflect\n\t// shrink-to-fit sizing rather than normal-flow block width.\n\tsetStyleProperties(popup, { position: 'fixed', zIndex: Z_INDEX });\n\n\t// Detect containing-block offset caused by ancestor transforms etc.\n\tconst cbOffset: ContainingBlockOffset = measureContainingBlockOffset(popup);\n\n\tconst popupWidth: number = popup.offsetWidth;\n\tconst popupHeight: number = popup.offsetHeight;\n\n\tconst styles: Record<string, string> = {};\n\n\tswitch (options.position) {\n\t\tcase 'below-start': {\n\t\t\tlet top: number = anchor.bottom + offset;\n\n\t\t\tif (options.isRtl) {\n\t\t\t\t// RTL: anchor to physical right edge (visual start)\n\t\t\t\tlet right: number = vpWidth - anchor.right;\n\t\t\t\tif (right + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tright = vpWidth - popupWidth - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = anchor.top - popupHeight - offset;\n\t\t\t\t}\n\t\t\t\tif (right < POPUP_MIN_MARGIN) right = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.right = `${right - cbOffset.rightX}px`;\n\t\t\t\tstyles.left = 'auto';\n\t\t\t} else {\n\t\t\t\tlet left: number = anchor.left;\n\t\t\t\tif (left + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tleft = vpWidth - popupWidth - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = anchor.top - popupHeight - offset;\n\t\t\t\t}\n\t\t\t\tif (left < POPUP_MIN_MARGIN) left = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.left = `${left - cbOffset.x}px`;\n\t\t\t\tstyles.right = 'auto';\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 'below-end': {\n\t\t\tlet top: number = anchor.bottom + offset;\n\n\t\t\tif (options.isRtl) {\n\t\t\t\t// RTL: \"end\" = physical left edge\n\t\t\t\tlet left: number = anchor.left;\n\t\t\t\tif (left + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tleft = vpWidth - popupWidth - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = anchor.top - popupHeight - offset;\n\t\t\t\t}\n\t\t\t\tif (left < POPUP_MIN_MARGIN) left = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.left = `${left - cbOffset.x}px`;\n\t\t\t\tstyles.right = 'auto';\n\t\t\t} else {\n\t\t\t\t// LTR: \"end\" = physical right edge\n\t\t\t\tlet right: number = vpWidth - anchor.right;\n\t\t\t\tif (right + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tright = vpWidth - popupWidth - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = anchor.top - popupHeight - offset;\n\t\t\t\t}\n\t\t\t\tif (right < POPUP_MIN_MARGIN) right = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.right = `${right - cbOffset.rightX}px`;\n\t\t\t\tstyles.left = 'auto';\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 'right': {\n\t\t\tlet top: number = anchor.top;\n\n\t\t\tif (options.isRtl) {\n\t\t\t\t// RTL: open submenu to the physical left\n\t\t\t\tlet left: number = anchor.left - popupWidth - offset;\n\t\t\t\tif (left < POPUP_MIN_MARGIN) {\n\t\t\t\t\tleft = anchor.right + offset;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = vpHeight - popupHeight - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (left < POPUP_MIN_MARGIN) left = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.left = `${left - cbOffset.x}px`;\n\t\t\t\tstyles.right = 'auto';\n\t\t\t} else {\n\t\t\t\tlet left: number = anchor.right + offset;\n\t\t\t\tif (left + popupWidth > vpWidth - POPUP_MIN_MARGIN) {\n\t\t\t\t\tleft = anchor.left - popupWidth - offset;\n\t\t\t\t}\n\t\t\t\tif (top + popupHeight > vpHeight - POPUP_MIN_MARGIN) {\n\t\t\t\t\ttop = vpHeight - popupHeight - POPUP_MIN_MARGIN;\n\t\t\t\t}\n\t\t\t\tif (left < POPUP_MIN_MARGIN) left = POPUP_MIN_MARGIN;\n\t\t\t\tif (top < POPUP_MIN_MARGIN) top = POPUP_MIN_MARGIN;\n\t\t\t\tstyles.top = `${top - cbOffset.y}px`;\n\t\t\t\tstyles.left = `${left - cbOffset.x}px`;\n\t\t\t\tstyles.right = 'auto';\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tsetStyleProperties(popup, styles);\n}\n\n/**\n * Appends an element to the appropriate root: the shadow root if the\n * reference node lives inside one, otherwise `document.body`.\n */\nexport function appendToRoot(element: HTMLElement, referenceNode: Node): void {\n\tconst root: Node = referenceNode.getRootNode();\n\tif (root instanceof ShadowRoot) {\n\t\troot.appendChild(element);\n\t} else {\n\t\tdocument.body.appendChild(element);\n\t}\n}\n\n/** Returns the focused element in the reference node's root, including nested shadow roots. */\nexport function getDeepActiveHTMLElement(referenceNode: Node): HTMLElement | null {\n\tconst root: Node = referenceNode.getRootNode();\n\tlet active: Element | null =\n\t\troot instanceof ShadowRoot || root instanceof Document\n\t\t\t? root.activeElement\n\t\t\t: document.activeElement;\n\twhile (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;\n\treturn active instanceof HTMLElement ? active : null;\n}\n\n/**\n * Promotes a popup/overlay to the browser's top layer via the Popover API so it\n * paints above — and receives pointer events ahead of — every stacking context\n * in the host page. A high `z-index` alone is not enough: an ancestor that forms\n * a stacking context (e.g. Starlight's `isolation: isolate` content wrapper)\n * traps the popup below a sibling such as the fixed table-of-contents sidebar,\n * so clicks on the overlapped region hit the sidebar and dismiss the popup.\n *\n * The element keeps living in the editor's shadow DOM, so its registered styles\n * still apply; only its paint layer changes. Must be called while the element is\n * connected to the document and BEFORE positioning, so subsequent\n * `offsetWidth`/containing-block measurements reflect the displayed top-layer\n * box.\n *\n * No-ops when the Popover API is unavailable (older engines, happy-dom in unit\n * tests); callers then fall back to plain `z-index` stacking. Neutralizes the UA\n * popover box styles (`inset: 0; margin: auto`) so the caller's explicit\n * `top`/`left` placement is what positions the element.\n */\nexport function promoteToTopLayer(element: HTMLElement): void {\n\tif (typeof element.showPopover !== 'function') return;\n\telement.setAttribute('popover', 'manual');\n\ttry {\n\t\telement.showPopover();\n\t} catch {\n\t\telement.removeAttribute('popover');\n\t\treturn;\n\t}\n\tsetStyleProperties(element, { margin: '0', inset: 'auto' });\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{a as t,n as e,r as n}from"./HTMLUtils-Bhg3_P8B.mjs";import{a as o,d as r,f as s,h as i,i as a,n as c,r as l,s as u,v as d}from"./ThemeEngine-BUVo_zaT.mjs";import{c as f,o as p}from"./PluginHelpers-KDuTlmXm.mjs";import{i as h,l as m,r as g,s as y}from"./StyleRuntime-DW6omotc.mjs";import{t as b}from"./ShortcutFormatting-TwiufqeV.mjs";import v from"dompurify";var $={label:"Print",tooltip:t=>`Print (${t})`,printingAnnouncement:"Printing"},S=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-Uzo1Azdw.mjs"),"./locales/de.ts":()=>import("./de-DcMhfRBu.mjs"),"./locales/es.ts":()=>import("./es-BJHF95J_.mjs"),"./locales/fr.ts":()=>import("./fr-KXmbys88.mjs"),"./locales/hi.ts":()=>import("./hi-l6DA-aOw.mjs"),"./locales/pt.ts":()=>import("./pt-C8sOyw0V.mjs"),"./locales/ru.ts":()=>import("./ru-B1m8J9dl.mjs"),"./locales/zh.ts":()=>import("./zh-dGSDBBzb.mjs")});async function w(t){return f(S,t,$)}var k=["h1","h2","h3","h4","h5","h6","p","div","span","br","hr","strong","b","em","i","u","s","sub","sup","small","ul","ol","li","table","thead","tbody","tr","th","td","img"],T=["style","class","src","alt","width","height","colspan","rowspan"];function C(t){const e="function"==typeof t?t():t;return v.sanitize(e,{ALLOWED_TAGS:[...k],ALLOWED_ATTR:[...T]})}var j=new Set(["AREA","BASE","BR","COL","EMBED","HR","IMG","INPUT","LINK","META","PARAM","SOURCE","TRACK","WBR"]),A=new Set(["TABLE","THEAD","TBODY","TFOOT","TR"]),L=new Set(["AUDIO","CANVAS","EMBED","IFRAME","IMG","INPUT","METER","OBJECT","PROGRESS","SELECT","TEXTAREA","VIDEO"]);function x(t,e){let n;do{n=`${t}-${crypto.randomUUID()}`}while(e.has(n));return e.add(n),n}function E(t){const e=/* @__PURE__ */new Map;t.matches("[data-block-id][id]")&&""!==t.id&&e.set(t.id,t);for(const n of t.querySelectorAll("[data-block-id][id]")){const t=n.id;""===t||e.has(t)||e.set(t,n)}return e}function M(e,n){for(const o of t(n)){const t=e.get(o);if(t)return t}}function R(t,e,n,o){const r=x("notectl-print-destination",n),s=x("notectl-print-destination-slot",o),i=e.createElement("slot");i.name=s,i.setAttribute("data-notectl-print-destination-slot",""),function(t,e){if(j.has(t.tagName)||L.has(t.tagName))t.before(e);else{if(A.has(t.tagName)){const n=t.querySelector("th, td");if(n)return void n.insertBefore(e,n.firstChild);const o=t.closest("table");if(o?.parentNode)return void o.before(e)}t.insertBefore(e,t.firstChild)}}(t,i);const a=e.createElement("a");return a.id=r,a.setAttribute("href",`#${r}`),a.slot=s,a.tabIndex=-1,a.setAttribute("aria-hidden","true"),a.setAttribute("data-notectl-print-destination",""),function(t){for(const[e,n]of Object.entries({all:"initial",display:"block",position:"absolute",width:"0",height:"0",margin:"0",padding:"0",border:"0",overflow:"hidden","pointer-events":"none","font-size":"0","line-height":"0",color:"transparent",background:"transparent"}))t.style.setProperty(e,n,"important")}(a),{id:r,marker:a}}var B="notectl-host";function N(t){const e=Array.from(t.styleSheets),n=t.adoptedStyleSheets;return n&&e.push(...n),e}function H(t,e){const n=t[e]??'"';let o=e+1;for(;o<t.length;){const e=t[o]??"";if("\\"!==e){if(e===n)return o+1;o++}else o+=2}return t.length}function z(t,e){if("url("!==t.slice(e,e+4).toLowerCase())return!1;const n=e>0?t[e-1]??"":"";return!/[\w-]/.test(n)}function P(t,e){let n=e+4;for(;n<t.length&&/\s/.test(t[n]??"");)n++;const o=t[n]??"";let r;if('"'===o||"'"===o){const e=H(t,n);r=t.slice(n+1,e-1),n=e}else{const e=t.indexOf(")",n);if(-1===e)return null;r=t.slice(n,e).trim(),n=e}for(;n<t.length&&/\s/.test(t[n]??"");)n++;return")"!==t[n]?null:{end:n+1,url:(s=r,s.replace(/\\([0-9a-f]{1,6}\s?|[\s\S])/gi,(t,e)=>{const n=e.trim();if(/^[0-9a-f]{1,6}$/i.test(n)){const t=Number.parseInt(n,16);return t>0&&t<=1114111?String.fromCodePoint(t):"�"}return e}))};var s}function q(t,e,n){if(!e||!function(t){return!t.startsWith("#")&&!t.startsWith("//")&&!/^[a-z][a-z0-9+.-]*:/i.test(t)}(e))return t;try{return`url("${new URL(e,n).href}")`}catch{return t}}function D(t,e){if(!t.toLowerCase().includes("url("))return t;let n="",o=0;for(;o<t.length;){const r=t[o]??"";if('"'===r||"'"===r){const e=H(t,o);n+=t.slice(o,e),o=e;continue}if(z(t,o)){const r=P(t,o);if(r){n+=q(t.slice(o,r.end),r.url,e),o=r.end;continue}}n+=r,o++}return n}function O(t){return t.anonymousLayerCount+=1,`notectl-anonymous-${t.anonymousLayerCount}`}var I={media:[],layers:[],supports:[]};function U(t,e,n,o){const r=e.trim(),s=o?.trim()??"";return{media:r&&"all"!==r?[...t.media,r]:t.media,layers:null===n?t.layers:[...t.layers,""===n?null:n],supports:s?[...t.supports,s]:t.supports}}function W(t,e,n){const o=[B];for(const c of n.layers)o.push(c??O(t));const r=0===(s=n.supports).length?"":1===s.length?` supports(${s[0]})`:` supports(${s.map(t=>`(${t})`).join(" and ")})`;var s;const i=n.media.length?` ${n.media.join(" and ")}`:"";var a;t.segments.push({kind:"import",statement:`@import url("${a=e,a.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}") layer(${o.join(".")})${r}${i};`})}function V(t,e){const n=e.trim();return n&&"all"!==n?`@media ${n} {\n${t}\n}`:t}function G(t,e){if(e.seen.has(t))return;if(e.seen.add(t),t.disabled)return;const n=U(I,t.media.mediaText,null,null);let o;try{o=t.cssRules}catch{return void(t.href&&W(e,t.href,n))}const r=t.href??e.baseURL,s=[];for(const a of o)3!==a.type?s.push(D(a.cssText,r)):F(a,e,s,n);const i=s.join("\n");i&&function(t,e){const n=t.segments[t.segments.length-1];"rules"!==n?.kind?t.segments.push({kind:"rules",css:e}):t.segments[t.segments.length-1]={kind:"rules",css:`${n.css}\n${e}`}}(e,V(i,t.media.mediaText))}function F(t,e,n,o){const r=t.layerName??null,s=t.supportsText??null,i=U(o,t.media.mediaText,r,s),a=t.styleSheet;if(a&&!e.seen.has(a)){let o;try{o=a.cssRules}catch{o=null}if(o){e.seen.add(a);const c=a.href??e.baseURL,l=[];for(const t of o)3!==t.type?l.push(D(t.cssText,c)):F(t,e,l,i);let u=l.join("\n");return void(u&&(null!==r&&(u=""===r?`@layer {\n${u}\n}`:`@layer ${r} {\n${u}\n}`),s?.trim()&&(u=`@supports (${s.trim()}) {\n${u}\n}`),n.push(V(u,t.media.mediaText))))}}const c=a?.href??t.href;c&&W(e,c,i)}var K="notectl-print",Y="notectl-custom";function _(t){return t.replace(/;$/gm," !important;")}function J(t){return _(c(u).replace(":host {",`${t} {`))}function X(t,e){const n=getComputedStyle(t),o=[];for(let r=0;r<n.length;r++){const t=n[r]??"";if(t.startsWith("--notectl-")){const e=n.getPropertyValue(t).trim();e&&o.push(` ${t}: ${e};`)}}return 0===o.length?"":`${e} {\n${o.join("\n")}\n}`}var Q=["","transparent","rgba(0, 0, 0, 0)"];function Z(t){let e=t;for(;e;){const t=getComputedStyle(e).getPropertyValue("background-color").trim();if(!Q.includes(t))return t;const n=e.getRootNode();e=e.parentElement??(n instanceof ShadowRoot?n.host:null)}return"#ffffff"}function tt(t,e,n="#ffffff",o="body"){const r=getComputedStyle(t),s=["font-family","font-size","font-weight","line-height","letter-spacing","word-spacing","color"],i=[" margin: 0;",` background: ${n};`];for(const a of s){if("color"===a&&e){i.push(` color: ${e};`);continue}const t=r.getPropertyValue(a).trim();t&&i.push(` ${a}: ${t};`)}return`${o} {\n${i.join("\n")}\n}`}var et=["display: block","position: static","inset: auto","width: auto","height: auto","min-width: 0","min-height: 0","max-width: none","max-height: none","margin: 0","padding: 0","border: none","border-radius: 0","outline: none","box-shadow: none","background: transparent","overflow: visible","transform: none","filter: none","opacity: 1","contain: none","float: none","visibility: visible","clip: auto","clip-path: none","content-visibility: visible"],nt=["display: block","visibility: visible","opacity: 1","position: static","height: auto","min-height: 0","max-height: none","overflow: visible","transform: none","filter: none","contain: none","clip: auto","clip-path: none","content-visibility: visible"];function ot(t){return[`${t} {`,...et.map(t=>` ${t} !important;`),"}"].join("\n")}function rt(t,e,n){const o=t.tagName.toLowerCase(),r=[],s=!1!==n.forceLightTheme,a=[ot(o),["html, body {",...nt.map(t=>` ${t} !important;`),"}"].join("\n")];if(s&&a.push(J(`:root, ${o}`)),!1!==n.printBackground&&a.push("* {\n -webkit-print-color-adjust: exact !important;\n print-color-adjust: exact !important;\n}"),r.push(`@layer ${K} {\n${a.join("\n\n")}\n}`),!s){const e=X(t,`:root, ${o}`);e&&r.push(e)}const c=s?u.primitives.foreground:void 0,l=s?"#ffffff":Z(e);r.push(tt(t,c,l));const d=function(t){const e=[];if(t.margin?e.push(` margin: ${t.margin};`):t.paperSize&&e.push(" margin: 0;"),t.paperSize||t.orientation){const n=[t.paperSize?i(t.paperSize):"A4"];t.orientation&&n.push(t.orientation),e.push(` size: ${n.join(" ")};`)}return 0===e.length?"":`@page {\n${e.join("\n")}\n}`}(n);return d&&r.push(d),n.customCSS&&(r.push(n.customCSS),r.push(`@layer ${Y} {\n${n.customCSS}\n}`)),r.join("\n\n")}function st(t,e,n,o){const r=`${t.tagName.toLowerCase()}[${o}]`,s=!1!==n.forceLightTheme,i=[ot(r)];s&&i.push(J(r)),!1!==n.printBackground&&i.push(`${r}, ${r} * {\n -webkit-print-color-adjust: exact !important;\n print-color-adjust: exact !important;\n}`);const a=s?u.primitives.foreground:void 0,c=s?"#ffffff":Z(e);i.push(_(tt(t,a,c,r)));const l=[`@layer ${K} {\n${i.join("\n\n")}\n}`];if(!s){const e=X(t,r);e&&l.push(e)}return l.join("\n\n")}var it="data-notectl-print-fallback",at=["(function () {"," var head = document.head;"," if (head && head.querySelector('meta[name=\"notectl-print-export\"]')) {"," var bundles = document.querySelectorAll('template[data-notectl-print-styles]');"," for (var b = 0; b < bundles.length; b++) {"," if (bundles[b].content) head.appendChild(bundles[b].content);"," bundles[b].parentNode.removeChild(bundles[b]);"," }"," }"," var statics = document.querySelectorAll('[data-notectl-static]');"," for (var i = 0; i < statics.length; i++) {"," var host = statics[i];"," if (!host.shadowRoot && host.attachShadow) {"," for (var j = 0; j < host.children.length; j++) {"," var child = host.children[j];"," if (child.tagName !== 'TEMPLATE') continue;"," if (!child.getAttribute('shadowrootmode') || !child.content) continue;"," host.attachShadow({ mode: 'open' }).appendChild(child.content);"," host.removeChild(child);"," break;"," }"," }"," if (!host.shadowRoot) continue;"," var fallbacks = host.querySelectorAll('[data-notectl-print-fallback]');"," for (var k = 0; k < fallbacks.length; k++) {"," fallbacks[k].parentNode.removeChild(fallbacks[k]);"," }"," }","})();"].join("\n");function ct(t){return t.replace(/<\//g,"<\\/")}function lt(t,n){const o=[];for(const r of Array.from(t.attributes))n(r.name)&&o.push(""===r.value?r.name:`${r.name}="${e(r.value)}"`);return o.length>0?` ${o.join(" ")}`:""}function ut(t){return t?lt(t,t=>"class"===t||t.startsWith("data-")):""}function dt(t){const n=function(t){if(!(t instanceof HTMLElement))return"";const e=[];for(let n=0;n<t.style.length;n++){const o=t.style[n]??"";if(!o.startsWith("--notectl-"))continue;const r=t.style.getPropertyValue(o).trim();r&&e.push(`${o}: ${r}`)}return e.join("; ")}(t);return n?` style="${e(n)}"`:""}function ft(t){const o=t.host.ownerDocument,r=t.host.tagName.toLowerCase(),s="export"===t.variant,i=s?["style","id",d]:["style",d],a=(c=t.host,l=i,lt(c,t=>!l.includes(t)));var c,l;const u=t.carryThemeContext?dt(t.host):"",f=t.carryThemeContext?ut(o.documentElement)+dt(o.documentElement):"",p=t.carryThemeContext?ut(o.body)+dt(o.body):"",h=t.styleNonce?` nonce="${e(t.styleNonce)}"`:"",m=['<meta charset="utf-8">',`<title>${n(t.title)}</title>`];s&&m.push('<meta name="notectl-print-export">'),m.push(`<style${h}>@layer ${Y}, ${K}, ${B};</style>`),m.push(`<style${h}>${ct(t.documentCSS)}</style>`);const g=t.hostSegments.map(t=>`<style${h}>${ct("import"===t.kind?t.statement:`@layer ${B} {\n${t.css}\n}`)}</style>`);s||m.push(...g);const y=s?`<template data-notectl-print-styles><style>${ct(t.standaloneCSS)}</style>${g.join("")}</template>`:"",b=s?`<div ${it}><style>@scope ([${it}]) {\n${ct(t.shadowCSS)}\n}</style>${t.fallbackContentHTML}</div>`:"",v=s?`<script>${at}<\/script>`:"",$=[`<${r}${a}${u} ${d}>`,'<template shadowrootmode="open">',`<style${h}>${ct(t.shadowCSS)}</style>`,t.contentHTML,"</template>",...b?[b]:[],...t.destinationMarkersHTML?[t.destinationMarkersHTML]:[],`</${r}>`,...y?[y]:[],...v?[v]:[]];return["<!DOCTYPE html>",`<html lang="${e(t.lang)}"${f}>`,"<head>",...m,"</head>",`<body${p}>`,...$,"</body>","</html>"].join("\n")}function pt(t,e,n,o){const r=/* @__PURE__ */new Set;function s(t){return t??{}}function i(r){const s={options:r,cancelled:!1};if(o.emit(a,s),s.cancelled)return null;const i=s.options,c=function(t,e){const n=[],o=function(t){const e=[],n=[];for(const o of t.adoptedStyleSheets){const t=h(o)?n:e;for(const e of o.cssRules)t.push(e.cssText)}return{base:e.join("\n"),runtime:n.join("\n")}}(t);o.base&&n.push(`@layer notectl-base {\n${o.base}\n}`),o.runtime&&n.push(o.runtime);const r=function(t){const e=[];e.push(".notectl-content { height: auto !important; max-height: none !important; min-height: 0 !important; overflow: visible !important; }"),t.paperSize&&e.push(".notectl-content { padding: 48px 56px !important; }");const n=[];return n.push("[data-notectl-no-print] { display: none !important; }"),n.push(".notectl-code-block { white-space: pre-wrap !important; word-break: break-all !important; page-break-inside: avoid; }"),n.push("img { page-break-inside: avoid; }"),n.push(".notectl-table { break-inside: avoid; }"),!1!==t.printBackground&&n.push("* { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }"),e.push(`@media print {\n ${n.join("\n ")}\n}`),e.join("\n\n")}(e);return r&&n.push(r),e.customCSS&&n.push(e.customCSS),n.join("\n\n")}(t,i),u=function(t){const e={segments:[],seen:/* @__PURE__ */new Set,baseURL:t.ownerDocument.baseURI??"",anonymousLayerCount:0};for(const n of function(t){const e=[];let n=t.getRootNode();for(;n instanceof ShadowRoot;)e.push(n),n=n.host.getRootNode();return e.push(t.ownerDocument),e.reverse()}(t))for(const t of N(n))G(t,e);return e.segments}(e),f=function(t,e){const n=function(t){return(t.querySelector(".notectl-content")??t).cloneNode(!0)}(t);return function(t){t.removeAttribute("contenteditable");for(const e of["notectl-node-selected","notectl-content--empty","notectl-table-cell--selected"]){t.classList.remove(e);for(const n of t.querySelectorAll(`.${e}`))n.classList.remove(e)}t.removeAttribute("data-placeholder")}(n),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 n of e.pageBreakBefore){const e=t.querySelectorAll(`[data-block-type="${n}"]`);for(const t of e)y(t,{breakBefore:"page",pageBreakBefore:"always"})}}(n,e),function(t,e){if(e.header){const n=document.createElement("div");n.className="notectl-print-header",n.innerHTML=C(e.header),t.insertBefore(n,t.firstChild)}if(e.footer){const n=document.createElement("div");n.className="notectl-print-footer",n.innerHTML=C(e.footer),t.appendChild(n)}}(n,e),n}(n,i),p=f.cloneNode(!0);!function(t){const e=E(t);if(0===e.size)return;const n=/* @__PURE__ */new Set;""!==t.id&&n.add(t.id);for(const r of t.querySelectorAll("[id]"))n.add(r.id);const o=/* @__PURE__ */new Map;for(const r of function(t){const e=[];return t.matches("[data-block-id][id]")&&""!==t.id&&e.push(t),e.push(...t.querySelectorAll("[data-block-id][id]")),e}(t)){const t=x("notectl-print-fallback-destination",n);o.set(r,t),r.id=t}for(const r of t.querySelectorAll("a[href]")){const t=M(e,r.getAttribute("href")??""),n=t?o.get(t):void 0;n&&r.setAttribute("href",`#${n}`)}}(p);const m=p.outerHTML,g=function(t){const e=E(t);if(0===e.size)return{markers:[]};const n=t.ownerDocument,o=/* @__PURE__ */new Set;""!==t.id&&o.add(t.id);for(const a of t.querySelectorAll("[id]"))o.add(a.id);const r=/* @__PURE__ */new Set;for(const a of t.querySelectorAll("slot[name]"))r.add(a.name);const s=/* @__PURE__ */new Map,i=[];for(const a of t.querySelectorAll("a[href]")){const t=a.getAttribute("href")??"";if(!t.startsWith("#"))continue;const c=M(e,t);if(!c)continue;let l=s.get(c);l||(l=R(c,n,o,r),s.set(c,l),i.push(l.marker)),a.setAttribute("href",`#${l.id}`)}return{markers:i}}(f),b=f.outerHTML,v=g.markers.map(t=>t.outerHTML).join(""),$=i.title??"",S=e.ownerDocument,w=e.closest("[lang]")?.getAttribute("lang")??(S.documentElement.lang||"en"),k={documentCSS:st(e,n,i,d),standaloneCSS:rt(e,n,i),hostSegments:u,shadowCSS:c,host:e,contentHTML:b,fallbackContentHTML:m,destinationMarkersHTML:v,title:$,lang:w,carryThemeContext:!1===i.forceLightTheme,variant:"export"},T=ft(k),j={html:T};return o.emit(l,j),{html:T,input:k}}return{print(t){const e=i(s(t));if(!e)return;const o=ft({...e.input,documentCSS:e.input.standaloneCSS,variant:"internal",styleNonce:g(n)}),a=document.createElement("iframe");m(a,"position:fixed;left:-9999px;width:0;height:0;border:none"),document.body.appendChild(a);const c=a.contentDocument,l=a.contentWindow;if(!c||!l)return void document.body.removeChild(a);c.open(),c.write(o),c.close();const u=()=>{a.remove()},d=()=>{l.addEventListener("afterprint",u,{once:!0}),l.print()};if("complete"===c.readyState)return void d();let f=!1;const p=()=>{f||(f=!0,r.delete(h),window.clearTimeout(y),d())},h=()=>{f=!0,window.clearTimeout(y),l.removeEventListener("load",p),a.remove()},y=window.setTimeout(p,4e3);r.add(h),l.addEventListener("load",p,{once:!0})},toHTML:t=>i(s(t))?.html??"",dispose(){for(const t of r)t();r.clear()}}}var ht={print(){},toHTML:()=>"",dispose(){}},mt=class{id="print";name="Print";config;service=null;locale;constructor(t){this.config=t??{}}async init(t){this.locale=await p(t,this.config.locale,$,w);const e=t.getContainer(),n=e.getRootNode();if(n instanceof ShadowRoot){const o=n.host,r=t.getEventBus();this.service=pt(n,o,e,r)}else this.service=ht;t.registerService(o,this.service);const r=this.config.defaults??{},s=this.service,i=this.locale;t.registerCommand("print",()=>(t.announce(i.printingAnnouncement),s.print(r),!0));const a=this.config.keyBinding??"Mod-P";if(t.registerKeymap({[a]:()=>(t.executeCommand("print"),!0)}),!1!==this.config.showToolbarItem){const e=b(a);t.registerToolbarItem({id:"print",group:"actions",label:this.locale.label,tooltip:this.locale.tooltip(e),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?.dispose(),this.service=null}};export{$ as n,w as r,mt as t};
2
+ //# sourceMappingURL=PrintPlugin-D2javl_d.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrintPlugin-D2javl_d.mjs","names":[],"sources":["../../src/plugins/print/PrintLocale.ts","../../src/plugins/print/PrintContentPreparer.ts","../../src/plugins/print/PrintDestinationBridge.ts","../../src/plugins/print/PrintHostStyles.ts","../../src/plugins/print/PrintStyleCollector.ts","../../src/plugins/print/PrintServiceImpl.ts","../../src/plugins/print/PrintPlugin.ts"],"sourcesContent":["/** Locale interface and default English locale for the PrintPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\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: LocaleModuleMap<PrintLocale> = import.meta.glob<{\n\tdefault: PrintLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadPrintLocale(lang: string): Promise<PrintLocale> {\n\treturn loadLocaleModule(localeModules, lang, PRINT_LOCALE_EN);\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 DOMPurify from 'dompurify';\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[] = [\n\t\t'notectl-node-selected',\n\t\t'notectl-content--empty',\n\t\t'notectl-table-cell--selected',\n\t];\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/** Tags allowed in print header/footer content. */\nconst HEADER_FOOTER_ALLOWED_TAGS: readonly string[] = [\n\t'h1',\n\t'h2',\n\t'h3',\n\t'h4',\n\t'h5',\n\t'h6',\n\t'p',\n\t'div',\n\t'span',\n\t'br',\n\t'hr',\n\t'strong',\n\t'b',\n\t'em',\n\t'i',\n\t'u',\n\t's',\n\t'sub',\n\t'sup',\n\t'small',\n\t'ul',\n\t'ol',\n\t'li',\n\t'table',\n\t'thead',\n\t'tbody',\n\t'tr',\n\t'th',\n\t'td',\n\t'img',\n];\n\n/** Attributes allowed in print header/footer content. */\nconst HEADER_FOOTER_ALLOWED_ATTRS: readonly string[] = [\n\t'style',\n\t'class',\n\t'src',\n\t'alt',\n\t'width',\n\t'height',\n\t'colspan',\n\t'rowspan',\n];\n\n/** Resolves a header/footer value to a sanitized HTML string. */\nfunction resolveContent(value: string | (() => string)): string {\n\tconst raw: string = typeof value === 'function' ? value() : value;\n\treturn DOMPurify.sanitize(raw, {\n\t\tALLOWED_TAGS: [...HEADER_FOOTER_ALLOWED_TAGS],\n\t\tALLOWED_ATTR: [...HEADER_FOOTER_ALLOWED_ATTRS],\n\t});\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 * Projects fragment targets from the print shadow tree into the document tree.\n * Browser fragment navigation and PDF named destinations cannot resolve IDs\n * whose root is a ShadowRoot, so each linked block target gets a slotted\n * light-DOM marker at the same rendered position.\n */\n\nimport { fragmentIdentifiers } from '../../model/HTMLUtils.js';\n\nexport const PRINT_DESTINATION_ATTRIBUTE = 'data-notectl-print-destination';\nexport const PRINT_DESTINATION_SLOT_ATTRIBUTE = 'data-notectl-print-destination-slot';\n\nexport interface PrintDestinationProjection {\n\treadonly markers: readonly HTMLAnchorElement[];\n}\n\ninterface Destination {\n\treadonly id: string;\n\treadonly marker: HTMLAnchorElement;\n}\n\nconst VOID_ELEMENTS: ReadonlySet<string> = new Set([\n\t'AREA',\n\t'BASE',\n\t'BR',\n\t'COL',\n\t'EMBED',\n\t'HR',\n\t'IMG',\n\t'INPUT',\n\t'LINK',\n\t'META',\n\t'PARAM',\n\t'SOURCE',\n\t'TRACK',\n\t'WBR',\n]);\n\nconst TABLE_STRUCTURAL_ELEMENTS: ReadonlySet<string> = new Set([\n\t'TABLE',\n\t'THEAD',\n\t'TBODY',\n\t'TFOOT',\n\t'TR',\n]);\n\n/** Elements whose rendered replacement/fallback UI does not lay out DOM children. */\nconst REPLACED_ELEMENTS: ReadonlySet<string> = new Set([\n\t'AUDIO',\n\t'CANVAS',\n\t'EMBED',\n\t'IFRAME',\n\t'IMG',\n\t'INPUT',\n\t'METER',\n\t'OBJECT',\n\t'PROGRESS',\n\t'SELECT',\n\t'TEXTAREA',\n\t'VIDEO',\n]);\n\nfunction uniqueToken(prefix: string, used: Set<string>): string {\n\tlet value: string;\n\tdo {\n\t\tvalue = `${prefix}-${crypto.randomUUID()}`;\n\t} while (used.has(value));\n\tused.add(value);\n\treturn value;\n}\n\nfunction firstBlockTargets(content: HTMLElement): ReadonlyMap<string, HTMLElement> {\n\tconst targets = new Map<string, HTMLElement>();\n\tif (content.matches('[data-block-id][id]') && content.id !== '') {\n\t\ttargets.set(content.id, content);\n\t}\n\tfor (const target of content.querySelectorAll<HTMLElement>('[data-block-id][id]')) {\n\t\tconst id: string = target.id;\n\t\tif (id !== '' && !targets.has(id)) targets.set(id, target);\n\t}\n\treturn targets;\n}\n\nfunction blockTargets(content: HTMLElement): HTMLElement[] {\n\tconst targets: HTMLElement[] = [];\n\tif (content.matches('[data-block-id][id]') && content.id !== '') targets.push(content);\n\ttargets.push(...content.querySelectorAll<HTMLElement>('[data-block-id][id]'));\n\treturn targets;\n}\n\nfunction resolveTarget(\n\ttargets: ReadonlyMap<string, HTMLElement>,\n\thref: string,\n): HTMLElement | undefined {\n\tfor (const identifier of fragmentIdentifiers(href)) {\n\t\tconst target: HTMLElement | undefined = targets.get(identifier);\n\t\tif (target) return target;\n\t}\n\treturn undefined;\n}\n\n/** Inserts a slot at the target without emitting invalid children for void or table elements. */\nfunction insertTargetSlot(target: HTMLElement, slot: HTMLSlotElement): void {\n\tif (VOID_ELEMENTS.has(target.tagName) || REPLACED_ELEMENTS.has(target.tagName)) {\n\t\ttarget.before(slot);\n\t\treturn;\n\t}\n\n\tif (TABLE_STRUCTURAL_ELEMENTS.has(target.tagName)) {\n\t\tconst cell: HTMLElement | null = target.querySelector<HTMLElement>('th, td');\n\t\tif (cell) {\n\t\t\tcell.insertBefore(slot, cell.firstChild);\n\t\t\treturn;\n\t\t}\n\t\tconst table: HTMLElement | null = target.closest<HTMLElement>('table');\n\t\tif (table?.parentNode) {\n\t\t\ttable.before(slot);\n\t\t\treturn;\n\t\t}\n\t}\n\n\ttarget.insertBefore(slot, target.firstChild);\n}\n\n/** Makes a zero-area PDF destination resistant to host/custom anchor styling. */\nfunction resetDestinationMarker(marker: HTMLAnchorElement): void {\n\tconst styles: Readonly<Record<string, string>> = {\n\t\tall: 'initial',\n\t\tdisplay: 'block',\n\t\tposition: 'absolute',\n\t\twidth: '0',\n\t\theight: '0',\n\t\tmargin: '0',\n\t\tpadding: '0',\n\t\tborder: '0',\n\t\toverflow: 'hidden',\n\t\t'pointer-events': 'none',\n\t\t'font-size': '0',\n\t\t'line-height': '0',\n\t\tcolor: 'transparent',\n\t\tbackground: 'transparent',\n\t};\n\tfor (const [property, value] of Object.entries(styles)) {\n\t\tmarker.style.setProperty(property, value, 'important');\n\t}\n}\n\nfunction createDestination(\n\ttarget: HTMLElement,\n\tdocument: Document,\n\tusedIds: Set<string>,\n\tusedSlotNames: Set<string>,\n): Destination {\n\tconst id: string = uniqueToken('notectl-print-destination', usedIds);\n\tconst slotName: string = uniqueToken('notectl-print-destination-slot', usedSlotNames);\n\n\tconst slot: HTMLSlotElement = document.createElement('slot');\n\tslot.name = slotName;\n\tslot.setAttribute(PRINT_DESTINATION_SLOT_ATTRIBUTE, '');\n\tinsertTargetSlot(target, slot);\n\n\tconst marker: HTMLAnchorElement = document.createElement('a');\n\tmarker.id = id;\n\tmarker.setAttribute('href', `#${id}`);\n\tmarker.slot = slotName;\n\tmarker.tabIndex = -1;\n\tmarker.setAttribute('aria-hidden', 'true');\n\tmarker.setAttribute(PRINT_DESTINATION_ATTRIBUTE, '');\n\tresetDestinationMarker(marker);\n\n\treturn { id, marker };\n}\n\n/**\n * Namespaces modeled IDs in the no-Shadow-DOM fallback so embedding the print\n * export cannot redirect its links to an earlier same-named consumer element.\n */\nexport function namespacePrintFallbackTargets(content: HTMLElement): void {\n\tconst targetsByOriginal: ReadonlyMap<string, HTMLElement> = firstBlockTargets(content);\n\tif (targetsByOriginal.size === 0) return;\n\n\tconst usedIds = new Set<string>();\n\tif (content.id !== '') usedIds.add(content.id);\n\tfor (const element of content.querySelectorAll<HTMLElement>('[id]')) usedIds.add(element.id);\n\n\tconst projectedIds = new Map<HTMLElement, string>();\n\tfor (const target of blockTargets(content)) {\n\t\tconst id: string = uniqueToken('notectl-print-fallback-destination', usedIds);\n\t\tprojectedIds.set(target, id);\n\t\ttarget.id = id;\n\t}\n\n\tfor (const link of content.querySelectorAll<HTMLAnchorElement>('a[href]')) {\n\t\tconst target: HTMLElement | undefined = resolveTarget(\n\t\t\ttargetsByOriginal,\n\t\t\tlink.getAttribute('href') ?? '',\n\t\t);\n\t\tconst id: string | undefined = target ? projectedIds.get(target) : undefined;\n\t\tif (id) link.setAttribute('href', `#${id}`);\n\t}\n}\n\n/**\n * Mutates only the supplied print shadow clone. Resolvable fragment-only links\n * are redirected to generated document-tree markers; all other links remain\n * byte-for-byte unchanged.\n */\nexport function projectPrintDestinations(content: HTMLElement): PrintDestinationProjection {\n\tconst targets: ReadonlyMap<string, HTMLElement> = firstBlockTargets(content);\n\tif (targets.size === 0) return { markers: [] };\n\n\tconst document: Document = content.ownerDocument;\n\tconst usedIds = new Set<string>();\n\tif (content.id !== '') usedIds.add(content.id);\n\tfor (const element of content.querySelectorAll<HTMLElement>('[id]')) {\n\t\tusedIds.add(element.id);\n\t}\n\tconst usedSlotNames = new Set<string>();\n\tfor (const slot of content.querySelectorAll<HTMLSlotElement>('slot[name]')) {\n\t\tusedSlotNames.add(slot.name);\n\t}\n\n\tconst destinations = new Map<HTMLElement, Destination>();\n\tconst markers: HTMLAnchorElement[] = [];\n\tfor (const link of content.querySelectorAll<HTMLAnchorElement>('a[href]')) {\n\t\tconst href: string = link.getAttribute('href') ?? '';\n\t\tif (!href.startsWith('#')) continue;\n\t\tconst target: HTMLElement | undefined = resolveTarget(targets, href);\n\t\tif (!target) continue;\n\n\t\tlet destination: Destination | undefined = destinations.get(target);\n\t\tif (!destination) {\n\t\t\tdestination = createDestination(target, document, usedIds, usedSlotNames);\n\t\t\tdestinations.set(target, destination);\n\t\t\tmarkers.push(destination.marker);\n\t\t}\n\t\tlink.setAttribute('href', `#${destination.id}`);\n\t}\n\n\treturn { markers };\n}\n","/**\n * Copies the host page's stylesheets verbatim into the print document.\n *\n * The print document preserves the editor's shadow boundary (declarative\n * shadow DOM), so host-authored rules — `::part()`, element selectors, custom\n * properties, `@media`, `@layer`, `@supports`, CSS nesting — apply natively\n * and need no translation or rewriting.\n *\n * All copied CSS is wrapped in the `notectl-host` cascade layer. Layering does\n * not weaken it against the editor's shadow styles, because the cascade\n * compares tree context before layers (an outer normal declaration beats a\n * shadow-tree one regardless). It does keep the print document's own rules in\n * control: its unlayered rules (page setup, body typography, customCSS) win\n * over the copy for normal declarations regardless of specificity, and the\n * print guards (host-element reset, forced light theme) — `!important` inside\n * the earlier-declared `notectl-print` layer — win even against `!important`\n * host rules.\n *\n * Stylesheets whose rules are not readable (cross-origin) are re-referenced\n * via hoisted `@import ... layer(notectl-host)` statements so the print\n * document loads them itself. The copy is produced as an ordered segment list\n * (rule chunks and `@import` statements interleaved in source order) so\n * equal-specificity cascade ties resolve exactly as on the live page.\n * Disabled stylesheets are skipped and stylesheet-level media conditions are\n * preserved as `@media` wrappers.\n */\n\n/** Cascade layer that holds the copied host-page styles in print output. */\nexport const HOST_STYLE_LAYER = 'notectl-host';\n\nconst IMPORT_RULE_TYPE = 3;\n\n/**\n * One source-ordered piece of the host-page CSS copy. `rules` segments hold\n * verbatim rule text destined for the `notectl-host` layer; `import` segments\n * hold hoisted `@import` statements for unreadable (cross-origin) sheets.\n * `@import` must precede every other rule of its stylesheet, so each segment\n * is emitted as its own `<style>` element — keeping the live source order,\n * which decides equal-specificity ties within the layer.\n */\nexport type HostStyleSegment =\n\t| { readonly kind: 'rules'; readonly css: string }\n\t| { readonly kind: 'import'; readonly statement: string };\n\ninterface CopyState {\n\treadonly segments: HostStyleSegment[];\n\treadonly seen: Set<CSSStyleSheet>;\n\t/** Base URL for rules from sheets without an own URL (inline styles). */\n\treadonly baseURL: string;\n\t/** Counter for naming hoisted anonymous import layers uniquely. */\n\tanonymousLayerCount: number;\n}\n\n/**\n * Collects the style roots that can hold rules targeting this editor: the\n * document plus any shadow roots the editor is nested in (outermost first, so\n * later, closer scopes win source-order ties after flattening).\n */\nfunction styleRootsOf(host: HTMLElement): readonly (Document | ShadowRoot)[] {\n\tconst roots: (Document | ShadowRoot)[] = [];\n\tlet node: Node = host.getRootNode();\n\twhile (node instanceof ShadowRoot) {\n\t\troots.push(node);\n\t\tnode = node.host.getRootNode();\n\t}\n\troots.push(host.ownerDocument);\n\treturn roots.reverse();\n}\n\nfunction sheetsOfRoot(root: Document | ShadowRoot): readonly CSSStyleSheet[] {\n\tconst sheets: CSSStyleSheet[] = Array.from(root.styleSheets);\n\tconst adopted: readonly CSSStyleSheet[] | undefined = root.adoptedStyleSheets;\n\tif (adopted) sheets.push(...adopted);\n\treturn sheets;\n}\n\n/** Escapes a URL for embedding in `@import url(\"...\")`. */\nfunction escapeImportURL(url: string): string {\n\treturn url.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/**\n * URLs that must not be rebased: fragment-only references stay document-local\n * (SVG paint servers like `fill: url(#gradient)`), and URLs that already have\n * a scheme or are protocol-relative resolve identically everywhere.\n */\nfunction isRebasableURL(url: string): boolean {\n\tif (url.startsWith('#') || url.startsWith('//')) return false;\n\treturn !/^[a-z][a-z0-9+.-]*:/i.test(url);\n}\n\n/** Returns the index just past the closing quote of the string opening at `start`. */\nfunction skipString(cssText: string, start: number): number {\n\tconst quote: string = cssText[start] ?? '\"';\n\tlet i: number = start + 1;\n\twhile (i < cssText.length) {\n\t\tconst ch: string = cssText[i] ?? '';\n\t\tif (ch === '\\\\') {\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === quote) return i + 1;\n\t\ti++;\n\t}\n\treturn cssText.length;\n}\n\n/**\n * Resolves CSS escape sequences (`\\\"`, `\\2f `, …) in a `url()` argument so the\n * actual URL is rebased, not its escaped serialization.\n */\nfunction unescapeCSSValue(value: string): string {\n\treturn value.replace(\n\t\t/\\\\([0-9a-f]{1,6}\\s?|[\\s\\S])/gi,\n\t\t(_match: string, escaped: string): string => {\n\t\t\tconst hex: string = escaped.trim();\n\t\t\tif (/^[0-9a-f]{1,6}$/i.test(hex)) {\n\t\t\t\tconst code: number = Number.parseInt(hex, 16);\n\t\t\t\treturn code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : '�';\n\t\t\t}\n\t\t\treturn escaped;\n\t\t},\n\t);\n}\n\n/** True when a `url(` function token starts at `index` (not part of a longer identifier). */\nfunction isURLTokenStart(cssText: string, index: number): boolean {\n\tif (cssText.slice(index, index + 4).toLowerCase() !== 'url(') return false;\n\tconst before: string = index > 0 ? (cssText[index - 1] ?? '') : '';\n\treturn !/[\\w-]/.test(before);\n}\n\ninterface URLToken {\n\t/** Index just past the closing `)`. */\n\treadonly end: number;\n\t/** The unescaped URL argument. */\n\treadonly url: string;\n}\n\n/** Parses the `url(...)` token starting at `start`; null when malformed. */\nfunction parseURLToken(cssText: string, start: number): URLToken | null {\n\tlet i: number = start + 4;\n\twhile (i < cssText.length && /\\s/.test(cssText[i] ?? '')) i++;\n\tconst ch: string = cssText[i] ?? '';\n\tlet raw: string;\n\tif (ch === '\"' || ch === \"'\") {\n\t\tconst end: number = skipString(cssText, i);\n\t\traw = cssText.slice(i + 1, end - 1);\n\t\ti = end;\n\t} else {\n\t\tconst close: number = cssText.indexOf(')', i);\n\t\tif (close === -1) return null;\n\t\traw = cssText.slice(i, close).trim();\n\t\ti = close;\n\t}\n\twhile (i < cssText.length && /\\s/.test(cssText[i] ?? '')) i++;\n\tif (cssText[i] !== ')') return null;\n\treturn { end: i + 1, url: unescapeCSSValue(raw) };\n}\n\n/** Rewrites one parsed `url()` token, keeping it verbatim when not rebasable. */\nfunction rebaseURLToken(original: string, url: string, baseURL: string): string {\n\tif (!url || !isRebasableURL(url)) return original;\n\ttry {\n\t\treturn `url(\"${new URL(url, baseURL).href}\")`;\n\t} catch {\n\t\treturn original;\n\t}\n}\n\n/**\n * Rewrites relative `url()` references to absolute URLs against the source\n * stylesheet's URL. Copied `cssText` keeps URLs as authored; in the print\n * document they would re-resolve against the page URL instead of the\n * stylesheet's location, breaking fonts and images from stylesheets that live\n * in another directory. The scan is string-aware: a value that merely mentions\n * `url(...)` inside a CSS string (`content: \"url(info)\"`) is left untouched —\n * rewriting inside it would inject quotes and invalidate the declaration.\n */\nfunction rebaseCSSURLs(cssText: string, baseURL: string): string {\n\tif (!cssText.toLowerCase().includes('url(')) return cssText;\n\tlet result = '';\n\tlet i = 0;\n\twhile (i < cssText.length) {\n\t\tconst ch: string = cssText[i] ?? '';\n\t\tif (ch === '\"' || ch === \"'\") {\n\t\t\tconst end: number = skipString(cssText, i);\n\t\t\tresult += cssText.slice(i, end);\n\t\t\ti = end;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isURLTokenStart(cssText, i)) {\n\t\t\tconst token: URLToken | null = parseURLToken(cssText, i);\n\t\t\tif (token) {\n\t\t\t\tresult += rebaseURLToken(cssText.slice(i, token.end), token.url, baseURL);\n\t\t\t\ti = token.end;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tresult += ch;\n\t\ti++;\n\t}\n\treturn result;\n}\n\n/** Returns a unique sublayer name for a hoisted anonymous import layer. */\nfunction anonymousLayerName(state: CopyState): string {\n\tstate.anonymousLayerCount += 1;\n\treturn `notectl-anonymous-${state.anonymousLayerCount}`;\n}\n\n/** Appends rule text, coalescing with a preceding rules segment. */\nfunction pushRules(state: CopyState, css: string): void {\n\tconst last: HostStyleSegment | undefined = state.segments[state.segments.length - 1];\n\tif (last?.kind === 'rules') {\n\t\tstate.segments[state.segments.length - 1] = { kind: 'rules', css: `${last.css}\\n${css}` };\n\t\treturn;\n\t}\n\tstate.segments.push({ kind: 'rules', css });\n}\n\n/**\n * Accumulated cascade context enclosing a hoisted cross-origin `@import`: the\n * media, cascade-layer, and `supports()` conditions of every stylesheet and\n * import rule between the `notectl-host` layer and the re-referenced sheet. A\n * hoisted `@import` is emitted at the top level, outside the `@layer`/`@media`/\n * `@supports` wrappers its inlined siblings receive, so it must carry this\n * context on the statement itself or the re-referenced sheet lands in the wrong\n * cascade layer and ignores the enclosing conditions.\n */\ninterface ImportContext {\n\t/** Media conditions, outermost first; ANDed on emit. */\n\treadonly media: readonly string[];\n\t/** Layer chain under `notectl-host`, outermost first; `null` = anonymous. */\n\treadonly layers: readonly (string | null)[];\n\t/** `supports()` conditions, outermost first; ANDed on emit. */\n\treadonly supports: readonly string[];\n}\n\nconst EMPTY_IMPORT_CONTEXT: ImportContext = { media: [], layers: [], supports: [] };\n\n/**\n * Extends a context with one nesting level's own media/layer/supports. `all`\n * and empty media impose no condition and are dropped; anonymous layers are\n * kept as `null` placeholders and only named at emit time, so the shared\n * anonymous-layer counter advances solely on real hoists, not on readable\n * imports that are inlined.\n */\nfunction extendImportContext(\n\tparent: ImportContext,\n\tmediaText: string,\n\tlayerName: string | null,\n\tsupportsText: string | null,\n): ImportContext {\n\tconst media: string = mediaText.trim();\n\tconst supports: string = supportsText?.trim() ?? '';\n\treturn {\n\t\tmedia: media && media !== 'all' ? [...parent.media, media] : parent.media,\n\t\tlayers:\n\t\t\tlayerName === null ? parent.layers : [...parent.layers, layerName === '' ? null : layerName],\n\t\tsupports: supports ? [...parent.supports, supports] : parent.supports,\n\t};\n}\n\n/**\n * Combines accumulated `supports()` conditions into one `@import` supports\n * clause. A single condition stays bare (`supports(display: grid)`); multiple\n * conditions are each parenthesized and ANDed, since the `supports()` grammar\n * only permits `and` between parenthesized conditions.\n */\nfunction combineSupports(conditions: readonly string[]): string {\n\tif (conditions.length === 0) return '';\n\tif (conditions.length === 1) return ` supports(${conditions[0]})`;\n\treturn ` supports(${conditions.map((condition: string): string => `(${condition})`).join(' and ')})`;\n}\n\n/**\n * Re-references a stylesheet whose rules are not readable, carrying the\n * enclosing cascade context (media, layer chain, `supports()`) on the hoisted\n * statement so the re-referenced sheet keeps the same layer, media, and feature\n * gating it had live — nested layers order before the parent's direct rules,\n * mirroring how layered import content loses to unlayered page rules. Media\n * conditions are ANDed with `and`; a comma-separated media list at one level is\n * not distributed across the `and` (a rare edge that would need a cartesian\n * expansion). The statement is pushed as an ordered segment so the sheet keeps\n * its live source-order position.\n */\nfunction hoistImport(state: CopyState, href: string, context: ImportContext): void {\n\tconst layerChain: string[] = [HOST_STYLE_LAYER];\n\tfor (const layer of context.layers) {\n\t\tlayerChain.push(layer ?? anonymousLayerName(state));\n\t}\n\tconst supports: string = combineSupports(context.supports);\n\tconst media: string = context.media.length ? ` ${context.media.join(' and ')}` : '';\n\tstate.segments.push({\n\t\tkind: 'import',\n\t\tstatement: `@import url(\"${escapeImportURL(href)}\") layer(${layerChain.join('.')})${supports}${media};`,\n\t});\n}\n\n/** Wraps serialized sheet text in the sheet's own media condition, if any. */\nfunction wrapInSheetMedia(text: string, mediaText: string): string {\n\tconst media: string = mediaText.trim();\n\tif (!media || media === 'all') return text;\n\treturn `@media ${media} {\\n${text}\\n}`;\n}\n\nfunction serializeSheet(sheet: CSSStyleSheet, state: CopyState): void {\n\tif (state.seen.has(sheet)) return;\n\tstate.seen.add(sheet);\n\tif (sheet.disabled) return;\n\n\t// The sheet's own media (from its <link>/@import) is the enclosing context\n\t// for any cross-origin import it holds: its readable rules are wrapped in the\n\t// same @media below, so a hoisted import must carry it too.\n\tconst sheetContext: ImportContext = extendImportContext(\n\t\tEMPTY_IMPORT_CONTEXT,\n\t\tsheet.media.mediaText,\n\t\tnull,\n\t\tnull,\n\t);\n\n\tlet cssRules: CSSRuleList;\n\ttry {\n\t\tcssRules = sheet.cssRules;\n\t} catch {\n\t\t// Cross-origin — rules are not readable. Re-reference so the print\n\t\t// document loads the stylesheet itself.\n\t\tif (sheet.href) hoistImport(state, sheet.href, sheetContext);\n\t\treturn;\n\t}\n\n\tconst base: string = sheet.href ?? state.baseURL;\n\tconst body: string[] = [];\n\tfor (const rule of cssRules) {\n\t\tif (rule.type === IMPORT_RULE_TYPE) {\n\t\t\t// `@import` precedes every other rule of its sheet, so hoisted\n\t\t\t// statements emitted now stay ahead of this sheet's rule chunk.\n\t\t\tserializeImportRule(rule as CSSImportRule, state, body, sheetContext);\n\t\t\tcontinue;\n\t\t}\n\t\tbody.push(rebaseCSSURLs(rule.cssText, base));\n\t}\n\n\tconst text: string = body.join('\\n');\n\tif (text) pushRules(state, wrapInSheetMedia(text, sheet.media.mediaText));\n}\n\n/**\n * Inlines a readable `@import` target in place; unreadable targets are hoisted\n * as layered `@import` statements (`@import` is not valid inside a layer\n * block, so it cannot be copied verbatim). The import's own cascade-layer\n * assignment and `supports()` condition survive inlining as nested `@layer`\n * and `@supports` blocks — without them, layered import content would compete\n * on specificity against page rules it loses to live.\n */\nfunction serializeImportRule(\n\trule: CSSImportRule,\n\tstate: CopyState,\n\tbody: string[],\n\tparentContext: ImportContext,\n): void {\n\tconst layerName: string | null = rule.layerName ?? null;\n\tconst supportsText: string | null = rule.supportsText ?? null;\n\t// This import's own media/layer/supports extend the parent context. Readable\n\t// targets pass it to their nested imports; an unreadable target is hoisted\n\t// under it.\n\tconst context: ImportContext = extendImportContext(\n\t\tparentContext,\n\t\trule.media.mediaText,\n\t\tlayerName,\n\t\tsupportsText,\n\t);\n\tconst imported: CSSStyleSheet | null = rule.styleSheet;\n\tif (imported && !state.seen.has(imported)) {\n\t\tlet importedRules: CSSRuleList | null;\n\t\ttry {\n\t\t\timportedRules = imported.cssRules;\n\t\t} catch {\n\t\t\timportedRules = null;\n\t\t}\n\t\tif (importedRules) {\n\t\t\tstate.seen.add(imported);\n\t\t\tconst base: string = imported.href ?? state.baseURL;\n\t\t\tconst inner: string[] = [];\n\t\t\tfor (const importedRule of importedRules) {\n\t\t\t\tif (importedRule.type === IMPORT_RULE_TYPE) {\n\t\t\t\t\tserializeImportRule(importedRule as CSSImportRule, state, inner, context);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tinner.push(rebaseCSSURLs(importedRule.cssText, base));\n\t\t\t}\n\t\t\tlet text: string = inner.join('\\n');\n\t\t\tif (text) {\n\t\t\t\tif (layerName !== null) {\n\t\t\t\t\t// Anonymous import layers stay anonymous via a nameless block.\n\t\t\t\t\ttext = layerName === '' ? `@layer {\\n${text}\\n}` : `@layer ${layerName} {\\n${text}\\n}`;\n\t\t\t\t}\n\t\t\t\tif (supportsText?.trim()) {\n\t\t\t\t\t// supports(display: grid) allows a bare declaration; the @supports\n\t\t\t\t\t// rule grammar does not, so the condition is parenthesized.\n\t\t\t\t\ttext = `@supports (${supportsText.trim()}) {\\n${text}\\n}`;\n\t\t\t\t}\n\t\t\t\tbody.push(wrapInSheetMedia(text, rule.media.mediaText));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\tconst href: string | null = imported?.href ?? rule.href;\n\tif (href) hoistImport(state, href, context);\n}\n\n/**\n * Copies all stylesheets that can target this editor (document-level plus any\n * enclosing shadow roots, including adopted sheets) into an ordered list of\n * verbatim CSS segments for the print document.\n */\nexport function collectHostStyleSegments(host: HTMLElement): readonly HostStyleSegment[] {\n\tconst state: CopyState = {\n\t\tsegments: [],\n\t\tseen: new Set(),\n\t\tbaseURL: host.ownerDocument.baseURI ?? '',\n\t\tanonymousLayerCount: 0,\n\t};\n\tfor (const root of styleRootsOf(host)) {\n\t\tfor (const sheet of sheetsOfRoot(root)) {\n\t\t\tserializeSheet(sheet, state);\n\t\t}\n\t}\n\treturn state.segments;\n}\n","/**\n * Collects and aggregates CSS for print output.\n *\n * The print document preserves the editor's shadow boundary (declarative\n * shadow DOM), so styles split into two scopes:\n *\n * - Shadow scope (inside the template): the editor's own adopted styles\n * (base styles behind a cascade layer, runtime style-token rules\n * unlayered), print content rules, and `customCSS` as the final same-tree\n * override.\n * - Document scope: print guards (host-element reset, `html`/`body` page\n * reset, and forced light theme — `!important` inside the `notectl-print`\n * layer so they hold even against `!important` host rules such as\n * `@media print { body * { visibility: hidden } }`), the carried\n * theme-token snapshot (unlayered, so it beats the layered host copy), body\n * typography snapshot, `@page` setup, and two `customCSS` copies: unlayered\n * for normal-strength page-level rules (`@page`, `body`) and inside the\n * earliest `notectl-custom` layer so consumer `!important` rules outrank\n * the print guards.\n *\n * Document layer order is `notectl-custom, notectl-print, notectl-host`\n * (declared in {@link buildHTMLDocument}). For normal declarations unlayered\n * rules win over all layers; for `!important` declarations the layer order\n * reverses, so earlier layers win: customCSS > print guards > host copy.\n *\n * Two document-scope builders exist: {@link buildDocumentCSS} for the\n * internal print iframe (full page fidelity — `html`/`body` reset, body\n * typography, `@page`) and {@link buildExportDocumentCSS} for the export\n * variant, whose inline rules are all qualified with the replica marker\n * attribute so embedding the export into a live page (documented\n * innerHTML/setHTMLUnsafe flow) cannot restyle the consumer's document. The\n * export regains full page fidelity in standalone documents through the\n * script-hoisted standalone style bundle (see PrintServiceImpl).\n */\n\nimport { generateThemeCSS } from '../../editor/theme/ThemeEngine.js';\nimport { LIGHT_THEME } from '../../editor/theme/ThemeTokens.js';\nimport {\n\tPAPER_MARGIN_HORIZONTAL_PX,\n\tPAPER_MARGIN_TOP_PX,\n\tgetPaperCSSSize,\n} from '../../model/PaperSize.js';\nimport { isRuntimeStyleSheet } from '../../style/StyleRuntime.js';\nimport type { PrintOptions } from './PrintTypes.js';\n\n/** Cascade layer that holds the editor's own base styles in print output. */\nconst BASE_STYLE_LAYER = 'notectl-base';\n\n/**\n * Document-level cascade layer holding the print guards (host reset, forced\n * light theme). Declared before the host-copy layer, so its `!important`\n * declarations beat `!important` host rules.\n */\nexport const PRINT_STYLE_LAYER = 'notectl-print';\n\n/**\n * Earliest document-level cascade layer, holding a `customCSS` copy. Its\n * `!important` declarations are the strongest in the print document — the\n * consumer's escape hatch over the print guards and host rules.\n */\nexport const CUSTOM_STYLE_LAYER = 'notectl-custom';\n\n/**\n * Appends `!important` to every declaration of generated CSS. Only safe for\n * CSS this module generates itself (one declaration per line, no semicolons\n * inside values).\n */\nfunction markDeclarationsImportant(css: string): string {\n\treturn css.replace(/;$/gm, ' !important;');\n}\n\n/** Adopted shadow styles split by role for print emission. */\nexport interface AdoptedStylePartition {\n\t/** Editor base styles — emitted inside the print cascade layer. */\n\treadonly base: string;\n\t/**\n\t * Runtime style-token rules (strict-CSP mode) carrying user-applied content\n\t * formatting — emitted unlayered so they keep their cascade strength.\n\t */\n\treadonly runtime: string;\n}\n\n/**\n * Extracts CSS text from all adopted stylesheets on a ShadowRoot, separating\n * editor base styles from runtime style-token sheets. The distinction matters\n * for print: base styles go into a cascade layer so consumer overrides win\n * (the documented #202 semantic: `customCSS` overrides built-in element\n * styling regardless of selector specificity — the flip side, also\n * documented, is that broad customCSS resets such as `* { padding: 0 }`\n * override base styling too), but token rules represent user content\n * formatting (inline styles in non-CSP mode) and must not be demoted with\n * them.\n */\nexport function partitionAdoptedStyles(shadowRoot: ShadowRoot): AdoptedStylePartition {\n\tconst base: string[] = [];\n\tconst runtime: string[] = [];\n\tfor (const sheet of shadowRoot.adoptedStyleSheets) {\n\t\tconst target: string[] = isRuntimeStyleSheet(sheet) ? runtime : base;\n\t\tfor (const rule of sheet.cssRules) {\n\t\t\ttarget.push(rule.cssText);\n\t\t}\n\t}\n\treturn { base: base.join('\\n'), runtime: runtime.join('\\n') };\n}\n\n/**\n * Generates light theme custom properties targeting `selector` (a full\n * selector list). The internal print iframe passes `:root` plus the host\n * element, so page-level `customCSS` rules\n * (`body { background: var(--notectl-bg) }`) keep resolving while the host\n * element re-pins the tokens closer than the shadow theme sheet's `:host`\n * defaults; the export variant passes only the marker-qualified replica so\n * nothing can leak into an embedding page. Every declaration is `!important`;\n * emitted inside the `notectl-print` layer, it beats copied host-page token\n * overrides (even `!important` ones) and the shadow theme sheet (tree\n * context), guaranteeing readable print output regardless of the active\n * editor theme.\n */\nexport function generateLightThemeTokens(selector: string): string {\n\tconst css: string = generateThemeCSS(LIGHT_THEME).replace(':host {', `${selector} {`);\n\treturn markDeclarationsImportant(css);\n}\n\n/**\n * Serializes an element's inline `--notectl-*` declarations. Tokens set via\n * the `style` attribute or JS `setProperty` (runtime theme switchers) cannot\n * travel through the stylesheet copy; re-emitting them as inline style on the\n * print document's corresponding element preserves their live cascade\n * strength — inline declarations beat every copied stylesheet rule, exactly\n * as on the live page.\n */\nexport function collectInlineThemeTokens(el: Element | null): string {\n\tif (!(el instanceof HTMLElement)) return '';\n\tconst declarations: string[] = [];\n\tfor (let i = 0; i < el.style.length; i++) {\n\t\tconst prop: string = el.style[i] ?? '';\n\t\tif (!prop.startsWith('--notectl-')) continue;\n\t\tconst value: string = el.style.getPropertyValue(prop).trim();\n\t\tif (value) declarations.push(`${prop}: ${value}`);\n\t}\n\treturn declarations.join('; ');\n}\n\n/**\n * Snapshots all computed `--notectl-*` tokens from the host element when\n * carrying the live theme (`forceLightTheme: false`). The computed values are\n * the ground truth of what the user saw: tokens set via the host's inline\n * `style` attribute (stripped from the print replica), via JS `setProperty`,\n * or via rules scoped to wrapper elements that do not exist in the print\n * document cannot travel through the stylesheet copy. Targeted at `selector`\n * (a full selector list: the host element, plus `:root` in the internal\n * variant so page-level `customCSS` keeps resolving the tokens) and emitted\n * unlayered: unlayered normal declarations beat the layered host copy, so a\n * host-page rule that matches differently in the print document (its wrapper\n * ancestors are not replicated) cannot override the live values.\n * Print-specific token overrides therefore need `!important` in the host\n * page or `customCSS`.\n */\nexport function snapshotThemeTokens(host: HTMLElement, selector: string): 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 `${selector} {\\n${tokens.join('\\n')}\\n}`;\n}\n\n/** Computed background-color values that mean \"no own background\". */\nconst TRANSPARENT_BACKGROUNDS: readonly string[] = ['', 'transparent', 'rgba(0, 0, 0, 0)'];\n\n/**\n * Resolves the background the editor content visually sits on, for carrying\n * the live theme into print (`forceLightTheme: false`). Walks up from the\n * content container (crossing shadow boundaries) through the page body up to\n * the root element — dark themes commonly paint `html` and leave `body`\n * transparent — returning the first non-transparent computed\n * background-color. Falls back to white so print output never inherits an\n * undefined background.\n */\nexport function resolveCarriedBackground(container: HTMLElement): string {\n\tlet el: HTMLElement | null = container;\n\twhile (el) {\n\t\tconst background: string = getComputedStyle(el).getPropertyValue('background-color').trim();\n\t\tif (!TRANSPARENT_BACKGROUNDS.includes(background)) return background;\n\t\tconst root: Node = el.getRootNode();\n\t\tel = el.parentElement ?? (root instanceof ShadowRoot ? (root.host as HTMLElement) : null);\n\t}\n\treturn '#ffffff';\n}\n\n/**\n * Snapshots computed typography from the host element into a rule for\n * `selector` (the page body in the print iframe, the replica host in the\n * export variant). Copied host-page styles are layered and `body` rules from\n * the host page are meant for the host application, so print pins typography\n * explicitly to what the editor computed live. The background is pinned to\n * `background` — white when the light theme is forced, the carried theme\n * background otherwise — so dark-theme output never renders light text on\n * white paper.\n */\nexport function snapshotTypography(\n\thost: HTMLElement,\n\tcolorOverride?: string,\n\tbackground = '#ffffff',\n\tselector = 'body',\n): 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;', ` background: ${background};`];\n\tfor (const prop of props) {\n\t\tif (prop === 'color' && colorOverride) {\n\t\t\trules.push(` color: ${colorOverride};`);\n\t\t\tcontinue;\n\t\t}\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 `${selector} {\\n${rules.join('\\n')}\\n}`;\n}\n\n/** Declarations that neutralize screen-widget chrome on the print host. */\nconst HOST_RESET_DECLARATIONS: readonly string[] = [\n\t'display: block',\n\t'position: static',\n\t'inset: auto',\n\t'width: auto',\n\t'height: auto',\n\t'min-width: 0',\n\t'min-height: 0',\n\t'max-width: none',\n\t'max-height: none',\n\t'margin: 0',\n\t'padding: 0',\n\t'border: none',\n\t'border-radius: 0',\n\t'outline: none',\n\t'box-shadow: none',\n\t'background: transparent',\n\t'overflow: visible',\n\t'transform: none',\n\t'filter: none',\n\t'opacity: 1',\n\t'contain: none',\n\t'float: none',\n\t'visibility: visible',\n\t'clip: auto',\n\t'clip-path: none',\n\t'content-visibility: visible',\n];\n\n/**\n * Declarations that keep the print page itself visible and unclipped. Host\n * pages commonly hide or clip at the page level — the classic\n * `@media print { body * { visibility: hidden } }` trick or app-shell\n * `html, body { height: 100%; overflow: hidden }` — and those rules are\n * copied verbatim into the host layer. Only hide/clip-capable properties are\n * guarded; box properties like `margin` stay overridable via plain customCSS.\n */\nconst PAGE_RESET_DECLARATIONS: readonly string[] = [\n\t'display: block',\n\t'visibility: visible',\n\t'opacity: 1',\n\t'position: static',\n\t'height: auto',\n\t'min-height: 0',\n\t'max-height: none',\n\t'overflow: visible',\n\t'transform: none',\n\t'filter: none',\n\t'contain: none',\n\t'clip: auto',\n\t'clip-path: none',\n\t'content-visibility: visible',\n];\n\n/**\n * Neutralizes page-level hiding and clipping from copied host rules on\n * `html`/`body`. Every declaration is `!important`; emitted inside the\n * `notectl-print` layer it beats the host copy even against `!important`\n * host rules, while `customCSS` (earlier `notectl-custom` layer) still wins.\n */\nexport function generatePageResetCSS(): string {\n\treturn [\n\t\t'html, body {',\n\t\t...PAGE_RESET_DECLARATIONS.map((declaration: string): string => ` ${declaration} !important;`),\n\t\t'}',\n\t].join('\\n');\n}\n\n/**\n * Neutralizes screen-widget chrome on the print host element. Copied\n * host-page rules like `notectl-editor { height: 400px; border: … }` style\n * the live widget but must not constrain the paginated print flow. Every\n * declaration is `!important`; emitted inside the `notectl-print` layer, the\n * reset beats the host copy even against `!important` host rules. Inherited\n * properties (fonts, color) are deliberately not touched; `customCSS` can\n * reclaim any of these via `!important` (earlier `notectl-custom` layer).\n */\nexport function generateHostResetCSS(hostSelector: string): string {\n\treturn [\n\t\t`${hostSelector} {`,\n\t\t...HOST_RESET_DECLARATIONS.map((declaration: string): string => ` ${declaration} !important;`),\n\t\t'}',\n\t].join('\\n');\n}\n\n/** Generates the `@page` rule based on PrintOptions. */\nexport function generatePageCSS(options: PrintOptions): string {\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) return '';\n\treturn `@page {\\n${pageProps.join('\\n')}\\n}`;\n}\n\n/** Generates print-specific content rules; emitted inside the shadow scope. */\nexport function generateContentPrintCSS(options: PrintOptions): string {\n\tconst parts: string[] = [];\n\n\t// Print flows the full document: screen scroll constraints on the content\n\t// area (the --notectl-content-max-height token or host ::part(content)\n\t// height rules) must not clip it to one scroll fold. Shadow-tree\n\t// `!important` beats document-tree `!important`, so this holds even\n\t// against host `::part()` rules; the shadow customCSS copy is emitted\n\t// later in source order and can still override.\n\tparts.push(\n\t\t'.notectl-content { height: auto !important; max-height: none !important; ' +\n\t\t\t'min-height: 0 !important; overflow: visible !important; }',\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/**\n * Builds the CSS placed inside the print document's declarative shadow root:\n * editor base styles behind a cascade layer (so consumer overrides win),\n * runtime style-token rules unlayered, print content rules, and customCSS as\n * the final same-tree override.\n */\nexport function buildShadowCSS(shadowRoot: ShadowRoot, options: PrintOptions): string {\n\tconst parts: string[] = [];\n\n\tconst adopted: AdoptedStylePartition = partitionAdoptedStyles(shadowRoot);\n\tif (adopted.base) parts.push(`@layer ${BASE_STYLE_LAYER} {\\n${adopted.base}\\n}`);\n\tif (adopted.runtime) parts.push(adopted.runtime);\n\n\tconst contentCSS: string = generateContentPrintCSS(options);\n\tif (contentCSS) parts.push(contentCSS);\n\n\tif (options.customCSS) {\n\t\tparts.push(options.customCSS);\n\t}\n\n\treturn parts.join('\\n\\n');\n}\n\n/** The print-color-adjust guard; document-level, because the shadow-scope copy cannot reach document-tree elements. */\nconst COLOR_ADJUST_GUARD: string =\n\t'* {\\n -webkit-print-color-adjust: exact !important;\\n print-color-adjust: exact !important;\\n}';\n\n/**\n * Builds the document-level CSS of the internal print iframe: the print\n * guards (host reset, `html`/`body` page reset, and forced light theme —\n * `!important` inside the `notectl-print` layer), the unlayered theme-token\n * snapshot, body typography, `@page`, and two copies of customCSS. The\n * unlayered copy carries page-level custom rules (`@page`, `body` — they\n * cannot live inside the shadow scope) at normal strength; the\n * `notectl-custom` layer copy makes consumer `!important` rules outrank the\n * print guards and `!important` host rules.\n */\nexport function buildDocumentCSS(\n\thost: HTMLElement,\n\tcontainer: HTMLElement,\n\toptions: PrintOptions,\n): string {\n\tconst hostSelector: string = host.tagName.toLowerCase();\n\tconst parts: string[] = [];\n\n\tconst forceLightTheme: boolean = options.forceLightTheme !== false;\n\tconst guards: string[] = [generateHostResetCSS(hostSelector), generatePageResetCSS()];\n\tif (forceLightTheme) {\n\t\tguards.push(generateLightThemeTokens(`:root, ${hostSelector}`));\n\t}\n\t// Without the document-level copy of this guard, the pinned body background\n\t// (the carried theme background for forceLightTheme: false) is stripped by\n\t// the browser's default \"no background graphics\" print behavior.\n\tif (options.printBackground !== false) {\n\t\tguards.push(COLOR_ADJUST_GUARD);\n\t}\n\tparts.push(`@layer ${PRINT_STYLE_LAYER} {\\n${guards.join('\\n\\n')}\\n}`);\n\n\tif (!forceLightTheme) {\n\t\tconst themeTokens: string = snapshotThemeTokens(host, `:root, ${hostSelector}`);\n\t\tif (themeTokens) parts.push(themeTokens);\n\t}\n\n\tconst colorOverride: string | undefined = forceLightTheme\n\t\t? LIGHT_THEME.primitives.foreground\n\t\t: undefined;\n\tconst background: string = forceLightTheme ? '#ffffff' : resolveCarriedBackground(container);\n\tparts.push(snapshotTypography(host, colorOverride, background));\n\n\tconst pageCSS: string = generatePageCSS(options);\n\tif (pageCSS) parts.push(pageCSS);\n\n\tif (options.customCSS) {\n\t\tparts.push(options.customCSS);\n\t\tparts.push(`@layer ${CUSTOM_STYLE_LAYER} {\\n${options.customCSS}\\n}`);\n\t}\n\n\treturn parts.join('\\n\\n');\n}\n\n/**\n * Builds the inline document-level CSS of the export variant (`toHTML()`,\n * `AFTER_PRINT`). Every selector is qualified with `markerSelector` (the\n * static-replica marker attribute), so the rules can only ever match a\n * replica: embedding the export into a live page via the documented\n * innerHTML/setHTMLUnsafe flow cannot restyle the consumer's document, hide\n * its live editors, or force them light. (`@scope` cannot express this: its\n * implicit `:where(:scope)` descendant prefix excludes the scoping root\n * itself, and shadow content — every `::part()` subject — is outside the\n * scope.) Page-level rules (`html`/`body` reset, `body` typography, `@page`,\n * `:root` tokens, the customCSS document copies) are not emitted here; they\n * ship in the script-gated standalone style bundle and otherwise apply in the\n * `print()` iframe. Instead the typography and background snapshot is emitted\n * `!important` after the host reset in the same layer, so the replica paints\n * its own canvas even without scripts.\n */\nexport function buildExportDocumentCSS(\n\thost: HTMLElement,\n\tcontainer: HTMLElement,\n\toptions: PrintOptions,\n\tmarkerAttribute: string,\n): string {\n\tconst markedSelector: string = `${host.tagName.toLowerCase()}[${markerAttribute}]`;\n\tconst forceLightTheme: boolean = options.forceLightTheme !== false;\n\n\tconst guards: string[] = [generateHostResetCSS(markedSelector)];\n\tif (forceLightTheme) {\n\t\t// No `:root` copy here: `!important` tokens on the embedding page's root\n\t\t// would force every live editor light (they beat the shadow `:host`\n\t\t// theme sheet). The `:root` copy for page-level customCSS var() support\n\t\t// lives in the standalone bundle.\n\t\tguards.push(generateLightThemeTokens(markedSelector));\n\t}\n\tif (options.printBackground !== false) {\n\t\tguards.push(\n\t\t\t`${markedSelector}, ${markedSelector} * {\\n -webkit-print-color-adjust: exact !important;\\n print-color-adjust: exact !important;\\n}`,\n\t\t);\n\t}\n\tconst colorOverride: string | undefined = forceLightTheme\n\t\t? LIGHT_THEME.primitives.foreground\n\t\t: undefined;\n\tconst background: string = forceLightTheme ? '#ffffff' : resolveCarriedBackground(container);\n\t// Emitted after the host reset in the same layer: the source-order tie\n\t// lets the snapshot's background beat the reset's `background: transparent`.\n\tguards.push(\n\t\tmarkDeclarationsImportant(snapshotTypography(host, colorOverride, background, markedSelector)),\n\t);\n\n\tconst parts: string[] = [`@layer ${PRINT_STYLE_LAYER} {\\n${guards.join('\\n\\n')}\\n}`];\n\n\tif (!forceLightTheme) {\n\t\tconst themeTokens: string = snapshotThemeTokens(host, markedSelector);\n\t\tif (themeTokens) parts.push(themeTokens);\n\t}\n\n\treturn parts.join('\\n\\n');\n}\n","/**\n * PrintService implementation.\n *\n * Builds a print document that preserves the editor's shadow boundary via\n * declarative shadow DOM: the host page's stylesheets are copied verbatim\n * (layered), the editor's own styles live inside the shadow template, and the\n * cloned content keeps its `part` attributes. Host `::part()` rules,\n * specificity, custom properties, and conditional rules therefore behave\n * exactly as in the live editor — nothing is translated or re-emulated.\n *\n * Two document variants are built from the same inputs:\n *\n * - The export variant (returned by `toHTML()`, broadcast via `AFTER_PRINT`)\n * is embed-safe: its inline document-level CSS is qualified with the static\n * replica marker, while everything page-level (host-CSS copy, hoisted\n * `@import`s, `html`/`body`/`@page` rules) ships inside an inert\n * `<template>` bundle that the fallback script activates only when the\n * export is rendered as its own document — so injecting the output into a\n * live page (documented innerHTML/setHTMLUnsafe flow) cannot restyle or\n * break the consumer's document. It carries a static light-DOM fallback for\n * parsers without declarative shadow DOM, and never carries the page's CSP\n * nonce, which is a secret that must not be persisted into serialized HTML.\n * - The internal variant (written into the transient print iframe) inlines\n * the full page-fidelity CSS (`html`/`body` reset, body typography,\n * `@page`, unscoped host-CSS copy, hoisted imports) and carries the style\n * nonce so it renders under the inherited CSP. It omits fallback, bundle,\n * and script: the iframe is parsed by the same modern browser, where DSD is\n * guaranteed.\n */\n\nimport { escapeAttr, escapeHTML } from '../../model/HTMLUtils.js';\nimport { getStyleNonceForNode, setStyleText } from '../../style/StyleRuntime.js';\nimport type { PluginEventBus } from '../Plugin.js';\nimport { prepare } from './PrintContentPreparer.js';\nimport {\n\ttype PrintDestinationProjection,\n\tnamespacePrintFallbackTargets,\n\tprojectPrintDestinations,\n} from './PrintDestinationBridge.js';\nimport {\n\tHOST_STYLE_LAYER,\n\ttype HostStyleSegment,\n\tcollectHostStyleSegments,\n} from './PrintHostStyles.js';\nimport {\n\tCUSTOM_STYLE_LAYER,\n\tPRINT_STYLE_LAYER,\n\tbuildDocumentCSS,\n\tbuildExportDocumentCSS,\n\tbuildShadowCSS,\n\tcollectInlineThemeTokens,\n} 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';\nimport { STATIC_HOST_ATTRIBUTE } from './StaticHostMarker.js';\n\n/**\n * Upper bound for waiting on the print iframe's load event. Referenced host\n * stylesheets (hoisted cross-origin `@import`) load asynchronously and are\n * worth a short wait so the first printed paint is styled, but a hanging\n * stylesheet must never block the print dialog indefinitely.\n */\nconst PRINT_LOAD_TIMEOUT_MS = 4000;\n\n/** Marker attribute on the static light-DOM fallback of the export variant. */\nexport const PRINT_FALLBACK_ATTRIBUTE = 'data-notectl-print-fallback';\n\n/**\n * Marker attribute on the inert `<template>` carrying the export variant's\n * standalone style bundle (page-level CSS and the verbatim host-CSS copy).\n */\nexport const PRINT_STYLE_BUNDLE_ATTRIBUTE = 'data-notectl-print-styles';\n\n/**\n * `<meta name>` marking the export document itself. The fallback script only\n * activates the standalone style bundle when this meta sits in\n * `document.head` — true when the export is the document being rendered\n * (file, iframe `srcdoc`, `document.write`, HTML-to-PDF engines), never when\n * it was inlined into a consumer page (fragment parsing keeps the meta inside\n * the injected subtree, outside `document.head`).\n */\nexport const PRINT_EXPORT_META_NAME = 'notectl-print-export';\n\n/**\n * Fallback for consumers that render the export variant with a parser that\n * does not attach declarative shadow roots but does execute scripts (older\n * WebViews, headless HTML-to-PDF engines). When the export is the document\n * itself (its marker meta sits in `document.head`), the inert standalone\n * style bundle (page-level CSS, verbatim host-CSS copy, hoisted imports) is\n * moved into the head, restoring full page fidelity; inlined into a consumer\n * page the meta never reaches the head, so the bundle stays inert and cannot\n * restyle the page. The shadow-attach step is strictly scoped to marked\n * replicas: only a `template[shadowrootmode]` that is a direct child of a\n * `[data-notectl-static]` host is attached — a document-wide sweep would\n * consume declarative templates belonging to the consumer's own components\n * when the export is inlined into a live page. Once a shadow root exists the\n * static light-DOM fallback is removed so extracted text is not doubled;\n * engines without Shadow DOM keep the rendered fallback. Native DSD parsing\n * leaves no template behind, making the attach branch a no-op. Kept ES5-safe\n * for legacy engines; must not contain a literal `</`. Deliberately emitted\n * without a nonce: the export variant never embeds the page's CSP secrets,\n * and if a consumer's CSP blocks the script the static fallback still\n * renders.\n */\nconst DSD_FALLBACK_SCRIPT: string = [\n\t'(function () {',\n\t' var head = document.head;',\n\t' if (head && head.querySelector(\\'meta[name=\"notectl-print-export\"]\\')) {',\n\t\" var bundles = document.querySelectorAll('template[data-notectl-print-styles]');\",\n\t' for (var b = 0; b < bundles.length; b++) {',\n\t' if (bundles[b].content) head.appendChild(bundles[b].content);',\n\t' bundles[b].parentNode.removeChild(bundles[b]);',\n\t' }',\n\t' }',\n\t\" var statics = document.querySelectorAll('[data-notectl-static]');\",\n\t' for (var i = 0; i < statics.length; i++) {',\n\t' var host = statics[i];',\n\t' if (!host.shadowRoot && host.attachShadow) {',\n\t' for (var j = 0; j < host.children.length; j++) {',\n\t' var child = host.children[j];',\n\t\" if (child.tagName !== 'TEMPLATE') continue;\",\n\t\" if (!child.getAttribute('shadowrootmode') || !child.content) continue;\",\n\t\" host.attachShadow({ mode: 'open' }).appendChild(child.content);\",\n\t' host.removeChild(child);',\n\t' break;',\n\t' }',\n\t' }',\n\t' if (!host.shadowRoot) continue;',\n\t\" var fallbacks = host.querySelectorAll('[data-notectl-print-fallback]');\",\n\t' for (var k = 0; k < fallbacks.length; k++) {',\n\t' fallbacks[k].parentNode.removeChild(fallbacks[k]);',\n\t' }',\n\t' }',\n\t'})();',\n].join('\\n');\n\n/**\n * Escapes `</` in CSS embedded into a `<style>` element. The HTML parser ends\n * the element at any literal `</style`, even inside a CSS string such as\n * `content: \"</style>\"`, which would break the print document. `\\/` is a\n * valid CSS escape for `/`, so the stylesheet semantics are unchanged.\n */\nfunction escapeStyleText(css: string): string {\n\treturn css.replace(/<\\//g, '<\\\\/');\n}\n\n/** Serializes an element's attributes matched by `include`, with a leading space. */\nfunction serializeFilteredAttributes(el: Element, include: (name: string) => boolean): string {\n\tconst parts: string[] = [];\n\tfor (const attribute of Array.from(el.attributes)) {\n\t\tif (!include(attribute.name)) continue;\n\t\tparts.push(\n\t\t\tattribute.value === ''\n\t\t\t\t? attribute.name\n\t\t\t\t: `${attribute.name}=\"${escapeAttr(attribute.value)}\"`,\n\t\t);\n\t}\n\treturn parts.length > 0 ? ` ${parts.join(' ')}` : '';\n}\n\n/**\n * Serializes an element's attributes for the print document. The `style`\n * attribute is stripped from the host element: element-attached declarations\n * would beat every stylesheet rule, defeating the print host reset.\n */\nfunction serializeAttributes(el: Element, skip: readonly string[]): string {\n\treturn serializeFilteredAttributes(el, (name: string): boolean => !skip.includes(name));\n}\n\n/**\n * Serializes theme-context attributes (`class` and `data-*`) so selectors\n * like `html.dark notectl-editor::part(x)` keep matching when the live theme\n * is carried into print (`forceLightTheme: false`).\n */\nfunction serializeThemeContextAttributes(el: Element | null): string {\n\tif (!el) return '';\n\treturn serializeFilteredAttributes(\n\t\tel,\n\t\t(name: string): boolean => name === 'class' || name.startsWith('data-'),\n\t);\n}\n\n/**\n * Serializes an element's inline `--notectl-*` tokens as a `style` attribute\n * (empty string when the element carries none). Used when the live theme is\n * carried: inline tokens beat every copied stylesheet rule, exactly as live.\n */\nfunction serializeInlineTokenStyle(el: Element | null): string {\n\tconst declarations: string = collectInlineThemeTokens(el);\n\treturn declarations ? ` style=\"${escapeAttr(declarations)}\"` : '';\n}\n\n/** Everything needed to assemble the print document. */\nexport interface PrintDocumentInput {\n\t/**\n\t * Document-level CSS matching the variant: full page fidelity for\n\t * `internal` ({@link buildDocumentCSS}), marker-qualified inline baseline\n\t * for `export` ({@link buildExportDocumentCSS}).\n\t */\n\treadonly documentCSS: string;\n\t/**\n\t * Full-fidelity page CSS ({@link buildDocumentCSS}) shipped by the export\n\t * variant inside the inert standalone style bundle; the fallback script\n\t * activates it only when the export is rendered as its own document.\n\t */\n\treadonly standaloneCSS: string;\n\t/** Source-ordered host-page CSS copy (rule chunks and hoisted `@import`s). */\n\treadonly hostSegments: readonly HostStyleSegment[];\n\t/** CSS placed inside the declarative shadow root. */\n\treadonly shadowCSS: string;\n\t/** The live editor host element; its tag and attributes are replicated. */\n\treadonly host: HTMLElement;\n\t/** Serialized print content projected into the declarative shadow root. */\n\treadonly contentHTML: string;\n\t/** Unmodified prepared content used by the export's no-DSD light-DOM fallback. */\n\treadonly fallbackContentHTML: string;\n\t/** Slotted document-tree markers for fragment navigation and PDF destinations. */\n\treadonly destinationMarkersHTML: string;\n\treadonly title: string;\n\treadonly lang: string;\n\t/** Copy html/body theme-context attributes (only when the live theme is carried). */\n\treadonly carryThemeContext: boolean;\n\t/**\n\t * `export` (`toHTML()`, `AFTER_PRINT`) is embed-safe: its inline styles are\n\t * marker-qualified, and everything page-level — the host-CSS copy, hoisted\n\t * `@import`s, and `standaloneCSS` — ships inside an inert `<template>`\n\t * bundle that the replica-scoped fallback script activates only when the\n\t * export is rendered as its own document. A consumer page embedding the\n\t * output can neither load foreign stylesheets nor have its own elements\n\t * restyled. `internal` (the transient print iframe) inlines the unscoped\n\t * copy and the imports directly and omits fallback, bundle, and script: the\n\t * iframe is parsed by the same modern browser, where declarative shadow DOM\n\t * is guaranteed.\n\t */\n\treadonly variant: 'export' | 'internal';\n\t/**\n\t * CSP nonce applied to every embedded `<style>` element so the internal\n\t * print iframe renders under an inherited `style-src` nonce policy. Never\n\t * set on the export variant: serialized HTML must not persist the page's\n\t * live nonce.\n\t */\n\treadonly styleNonce?: string;\n}\n\n/** Builds the complete print document as an HTML string. */\nexport function buildHTMLDocument(input: PrintDocumentInput): string {\n\tconst doc: Document = input.host.ownerDocument;\n\tconst hostTag: string = input.host.tagName.toLowerCase();\n\tconst isExport: boolean = input.variant === 'export';\n\t// The static marker keeps the replica from booting a live editor when the\n\t// document is injected into a page where the component is registered. The\n\t// export variant also drops the id: embedded next to the live editor it\n\t// would be a duplicate, and getElementById would resolve to the replica.\n\t// The internal iframe is its own document, so it keeps the id and host\n\t// rules like `#editor::part(cell)` stay matching.\n\tconst skippedHostAttributes: readonly string[] = isExport\n\t\t? ['style', 'id', STATIC_HOST_ATTRIBUTE]\n\t\t: ['style', STATIC_HOST_ATTRIBUTE];\n\tconst hostAttributes: string = serializeAttributes(input.host, skippedHostAttributes);\n\tconst hostTokens: string = input.carryThemeContext ? serializeInlineTokenStyle(input.host) : '';\n\n\tconst htmlContext: string = input.carryThemeContext\n\t\t? serializeThemeContextAttributes(doc.documentElement) +\n\t\t\tserializeInlineTokenStyle(doc.documentElement)\n\t\t: '';\n\tconst bodyContext: string = input.carryThemeContext\n\t\t? serializeThemeContextAttributes(doc.body) + serializeInlineTokenStyle(doc.body)\n\t\t: '';\n\n\tconst nonceAttribute: string = input.styleNonce ? ` nonce=\"${escapeAttr(input.styleNonce)}\"` : '';\n\tconst head: string[] = ['<meta charset=\"utf-8\">', `<title>${escapeHTML(input.title)}</title>`];\n\tif (isExport) {\n\t\t// Standalone marker: only reachable inside document.head when this\n\t\t// export IS the rendered document (see PRINT_EXPORT_META_NAME).\n\t\thead.push(`<meta name=\"${PRINT_EXPORT_META_NAME}\">`);\n\t}\n\t// The layer-order statement must be the document's first style rule: layer\n\t// order is fixed by first appearance, and for `!important` declarations\n\t// earlier layers win — customCSS > print guards > host copy. It stays\n\t// inline even in the export variant; on an embedding page it merely pins\n\t// the relative order of these notectl-prefixed layers, which only ever\n\t// hold marker-qualified rules there.\n\thead.push(\n\t\t`<style${nonceAttribute}>@layer ${CUSTOM_STYLE_LAYER}, ${PRINT_STYLE_LAYER}, ${HOST_STYLE_LAYER};</style>`,\n\t);\n\thead.push(`<style${nonceAttribute}>${escapeStyleText(input.documentCSS)}</style>`);\n\t// One `<style>` per segment: `@import` must precede every other rule of its\n\t// stylesheet, so interleaving imports and rule chunks as separate elements\n\t// is the only way to keep the live source order — which decides\n\t// equal-specificity cascade ties inside the `notectl-host` layer. The\n\t// export variant ships all segments (and the page-level standaloneCSS)\n\t// inside the inert style bundle instead: copied host selectors and hoisted\n\t// imports must never act on a page that merely embeds the export.\n\tconst segmentStyles: string[] = input.hostSegments.map((segment: HostStyleSegment): string => {\n\t\tconst css: string =\n\t\t\tsegment.kind === 'import'\n\t\t\t\t? segment.statement\n\t\t\t\t: `@layer ${HOST_STYLE_LAYER} {\\n${segment.css}\\n}`;\n\t\treturn `<style${nonceAttribute}>${escapeStyleText(css)}</style>`;\n\t});\n\tif (!isExport) head.push(...segmentStyles);\n\n\tconst styleBundle: string = isExport\n\t\t? `<template ${PRINT_STYLE_BUNDLE_ATTRIBUTE}><style>${escapeStyleText(input.standaloneCSS)}</style>${segmentStyles.join('')}</template>`\n\t\t: '';\n\n\t// The static fallback renders only when no shadow root is attached (a\n\t// shadow host's unslotted light DOM is never rendered): consumers that\n\t// inject via innerHTML — no DSD parsing, no script execution — get\n\t// readable, statically styled output instead of a blank page. Its style\n\t// copy is wrapped in @scope: a <style> element applies document-wide even\n\t// while its subtree is not rendered, and without the scope the shadow CSS\n\t// (including customCSS body rules) would leak onto a consumer page that\n\t// embeds this document via setHTMLUnsafe. Engines without @scope drop the\n\t// block and render the fallback unstyled but readable.\n\tconst fallback: string = isExport\n\t\t? `<div ${PRINT_FALLBACK_ATTRIBUTE}><style>@scope ([${PRINT_FALLBACK_ATTRIBUTE}]) {\\n${escapeStyleText(input.shadowCSS)}\\n}</style>${input.fallbackContentHTML}</div>`\n\t\t: '';\n\tconst fallbackScript: string = isExport ? `<script>${DSD_FALLBACK_SCRIPT}</script>` : '';\n\n\tconst body: string[] = [\n\t\t`<${hostTag}${hostAttributes}${hostTokens} ${STATIC_HOST_ATTRIBUTE}>`,\n\t\t'<template shadowrootmode=\"open\">',\n\t\t`<style${nonceAttribute}>${escapeStyleText(input.shadowCSS)}</style>`,\n\t\tinput.contentHTML,\n\t\t'</template>',\n\t\t...(fallback ? [fallback] : []),\n\t\t...(input.destinationMarkersHTML ? [input.destinationMarkersHTML] : []),\n\t\t`</${hostTag}>`,\n\t\t...(styleBundle ? [styleBundle] : []),\n\t\t...(fallbackScript ? [fallbackScript] : []),\n\t];\n\n\treturn [\n\t\t'<!DOCTYPE html>',\n\t\t`<html lang=\"${escapeAttr(input.lang)}\"${htmlContext}>`,\n\t\t'<head>',\n\t\t...head,\n\t\t'</head>',\n\t\t`<body${bodyContext}>`,\n\t\t...body,\n\t\t'</body>',\n\t\t'</html>',\n\t].join('\\n');\n}\n\n/** PrintService plus internal lifecycle hooks (not part of the public service API). */\nexport interface ManagedPrintService extends PrintService {\n\t/** Cancels pending print triggers and removes parked print iframes. */\n\tdispose(): void;\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): ManagedPrintService {\n\t/** Cancel callbacks for prints still waiting on their iframe's load event. */\n\tconst pendingPrints = new Set<() => void>();\n\n\tfunction mergeOptions(options?: PrintOptions): PrintOptions {\n\t\treturn options ?? {};\n\t}\n\n\t/** The export document plus the inputs to rebuild the internal variant. */\n\tinterface PrintDocumentBuild {\n\t\treadonly html: string;\n\t\treadonly input: PrintDocumentInput;\n\t}\n\n\tfunction executePrint(options: PrintOptions): PrintDocumentBuild | 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 for both scopes\n\t\tconst shadowCSS: string = buildShadowCSS(shadowRoot, finalOptions);\n\t\tconst hostSegments: readonly HostStyleSegment[] = collectHostStyleSegments(host);\n\n\t\t// 3. Prepare content\n\t\tconst clone: HTMLElement = prepare(container, finalOptions);\n\t\tconst fallbackClone: HTMLElement = clone.cloneNode(true) as HTMLElement;\n\t\tnamespacePrintFallbackTargets(fallbackClone);\n\t\tconst fallbackContentHTML: string = fallbackClone.outerHTML;\n\t\tconst projection: PrintDestinationProjection = projectPrintDestinations(clone);\n\t\tconst contentHTML: string = clone.outerHTML;\n\t\tconst destinationMarkersHTML: string = projection.markers\n\t\t\t.map((marker: HTMLAnchorElement): string => marker.outerHTML)\n\t\t\t.join('');\n\n\t\t// 4. Build the export document (no nonce — serialized output must not\n\t\t// persist the page's CSP secret; inline document CSS marker-qualified,\n\t\t// page-level CSS in the inert standalone bundle — embedding the output\n\t\t// must not restyle the consumer's page)\n\t\tconst title: string = finalOptions.title ?? '';\n\t\tconst ownerDocument: Document = host.ownerDocument;\n\t\tconst lang: string =\n\t\t\thost.closest('[lang]')?.getAttribute('lang') ?? (ownerDocument.documentElement.lang || 'en');\n\t\tconst input: PrintDocumentInput = {\n\t\t\tdocumentCSS: buildExportDocumentCSS(host, container, finalOptions, STATIC_HOST_ATTRIBUTE),\n\t\t\tstandaloneCSS: buildDocumentCSS(host, container, finalOptions),\n\t\t\thostSegments,\n\t\t\tshadowCSS,\n\t\t\thost,\n\t\t\tcontentHTML,\n\t\t\tfallbackContentHTML,\n\t\t\tdestinationMarkersHTML,\n\t\t\ttitle,\n\t\t\tlang,\n\t\t\tcarryThemeContext: finalOptions.forceLightTheme === false,\n\t\t\tvariant: 'export',\n\t\t};\n\t\tconst html: string = buildHTMLDocument(input);\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, input };\n\t}\n\n\treturn {\n\t\tprint(options?: PrintOptions): void {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\tconst build: PrintDocumentBuild | null = executePrint(resolved);\n\t\t\tif (!build) return;\n\n\t\t\t// The iframe is parsed by the same browser, so the fallback is dead\n\t\t\t// weight there; the nonce keeps the styles alive under a CSP\n\t\t\t// inherited by the about:blank iframe. The internal variant inlines\n\t\t\t// the full-fidelity page CSS (html/body reset, body typography,\n\t\t\t// @page) that the embed-safe export ships only in its inert bundle.\n\t\t\tconst printHTML: string = buildHTMLDocument({\n\t\t\t\t...build.input,\n\t\t\t\tdocumentCSS: build.input.standaloneCSS,\n\t\t\t\tvariant: 'internal',\n\t\t\t\tstyleNonce: getStyleNonceForNode(container),\n\t\t\t});\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\tconst iframeWindow: Window | null = iframe.contentWindow;\n\t\t\tif (!iframeDoc || !iframeWindow) {\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(printHTML);\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\tconst triggerPrint = (): void => {\n\t\t\t\tiframeWindow.addEventListener('afterprint', cleanup, { once: true });\n\t\t\t\tiframeWindow.print();\n\t\t\t};\n\n\t\t\t// Referenced host stylesheets (cross-origin @import) load\n\t\t\t// asynchronously; wait for them so the first paint printed is styled.\n\t\t\t// A hanging stylesheet must not block the dialog forever, so the wait\n\t\t\t// is bounded — on timeout, printing proceeds with the styles loaded\n\t\t\t// so far. The pending trigger is cancellable: after the editor is\n\t\t\t// destroyed the dialog must not pop up over an unrelated view.\n\t\t\tif (iframeDoc.readyState === 'complete') {\n\t\t\t\ttriggerPrint();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet triggered = false;\n\t\t\tconst triggerOnce = (): void => {\n\t\t\t\tif (triggered) return;\n\t\t\t\ttriggered = true;\n\t\t\t\tpendingPrints.delete(cancelPending);\n\t\t\t\twindow.clearTimeout(timeoutId);\n\t\t\t\ttriggerPrint();\n\t\t\t};\n\t\t\tconst cancelPending = (): void => {\n\t\t\t\ttriggered = true;\n\t\t\t\twindow.clearTimeout(timeoutId);\n\t\t\t\tiframeWindow.removeEventListener('load', triggerOnce);\n\t\t\t\tiframe.remove();\n\t\t\t};\n\t\t\tconst timeoutId: number = window.setTimeout(triggerOnce, PRINT_LOAD_TIMEOUT_MS);\n\t\t\tpendingPrints.add(cancelPending);\n\t\t\tiframeWindow.addEventListener('load', triggerOnce, { once: true });\n\t\t},\n\n\t\ttoHTML(options?: PrintOptions): string {\n\t\t\tconst resolved: PrintOptions = mergeOptions(options);\n\t\t\treturn executePrint(resolved)?.html ?? '';\n\t\t},\n\n\t\tdispose(): void {\n\t\t\tfor (const cancel of pendingPrints) {\n\t\t\t\tcancel();\n\t\t\t}\n\t\t\tpendingPrints.clear();\n\t\t},\n\t};\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 { type ManagedPrintService, 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: ManagedPrintService = {\n\tprint(): void {},\n\ttoHTML(): string {\n\t\treturn '';\n\t},\n\tdispose(): void {},\n};\n\nexport class PrintPlugin implements Plugin {\n\treadonly id = 'print';\n\treadonly name = 'Print';\n\n\tprivate readonly config: PrintPluginConfig;\n\tprivate service: ManagedPrintService | 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\t// A print still waiting on its iframe's load event must not pop the\n\t\t// dialog after the editor is gone (e.g. after an SPA navigation).\n\t\tthis.service?.dispose();\n\t\tthis.service = null;\n\t}\n}\n"],"mappings":"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"}