@notectl/core 2.3.1 → 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 (197) hide show
  1. package/README.md +1 -1
  2. package/THIRD-PARTY-NOTICES.md +129 -0
  3. package/dist/chunks/{AlignmentPlugin--xAFlRqE.mjs → AlignmentPlugin-C9Rr_R-g.mjs} +2 -2
  4. package/dist/chunks/{AlignmentPlugin--xAFlRqE.mjs.map → AlignmentPlugin-C9Rr_R-g.mjs.map} +1 -1
  5. package/dist/chunks/{AttributedMarkCommands-bagbH8Qt.mjs → AttributedMarkCommands-BCvmqeFZ.mjs} +2 -2
  6. package/dist/chunks/{AttributedMarkCommands-bagbH8Qt.mjs.map → AttributedMarkCommands-BCvmqeFZ.mjs.map} +1 -1
  7. package/dist/chunks/{BidiIsolationPlugin-DBXyXpgm.mjs → BidiIsolationPlugin-Cw2KMk-H.mjs} +2 -2
  8. package/dist/chunks/{BidiIsolationPlugin-DBXyXpgm.mjs.map → BidiIsolationPlugin-Cw2KMk-H.mjs.map} +1 -1
  9. package/dist/chunks/{BlockInsertion-CJusvrDL.mjs → BlockInsertion-CYH2gRkY.mjs} +2 -2
  10. package/dist/chunks/{BlockInsertion-CJusvrDL.mjs.map → BlockInsertion-CYH2gRkY.mjs.map} +1 -1
  11. package/dist/chunks/{BlockquotePlugin-Bz2glHwX.mjs → BlockquotePlugin-0bZSbkyo.mjs} +2 -2
  12. package/dist/chunks/{BlockquotePlugin-Bz2glHwX.mjs.map → BlockquotePlugin-0bZSbkyo.mjs.map} +1 -1
  13. package/dist/chunks/CaretNavigationPlugin-BPZ9b6XR.mjs +2 -0
  14. package/dist/chunks/CaretNavigationPlugin-BPZ9b6XR.mjs.map +1 -0
  15. package/dist/chunks/CodeBlockPlugin-BCJ3faXx.mjs +2 -0
  16. package/dist/chunks/{CodeBlockPlugin-C1hrdbSZ.mjs.map → CodeBlockPlugin-BCJ3faXx.mjs.map} +1 -1
  17. package/dist/chunks/{ColorGrid-C9RQoEWF.mjs → ColorGrid-DQEkJ-0y.mjs} +2 -2
  18. package/dist/chunks/{ColorGrid-C9RQoEWF.mjs.map → ColorGrid-DQEkJ-0y.mjs.map} +1 -1
  19. package/dist/chunks/ColorPickerPopup-CyF26zIU.mjs +2 -0
  20. package/dist/chunks/{ColorPickerPopup-DiA68Pzz.mjs.map → ColorPickerPopup-CyF26zIU.mjs.map} +1 -1
  21. package/dist/chunks/Commands-D5ND50PQ.mjs +2 -0
  22. package/dist/chunks/{Commands-1dFFldi7.mjs.map → Commands-D5ND50PQ.mjs.map} +1 -1
  23. package/dist/chunks/{Decoration-BpoEOANl.mjs → Decoration-BOP1TAUd.mjs} +2 -2
  24. package/dist/chunks/{Decoration-BpoEOANl.mjs.map → Decoration-BOP1TAUd.mjs.map} +1 -1
  25. package/dist/chunks/{FontPlugin-By-TGrQo.mjs → FontPlugin-D041tiLe.mjs} +2 -2
  26. package/dist/chunks/{FontPlugin-By-TGrQo.mjs.map → FontPlugin-D041tiLe.mjs.map} +1 -1
  27. package/dist/chunks/{FontSizePlugin-Dln-tYXV.mjs → FontSizePlugin-8CAvj1RD.mjs} +2 -2
  28. package/dist/chunks/{FontSizePlugin-Dln-tYXV.mjs.map → FontSizePlugin-8CAvj1RD.mjs.map} +1 -1
  29. package/dist/chunks/{FormulaPlugin-By1befrR.mjs → FormulaPlugin-DJ39BtqV.mjs} +2 -2
  30. package/dist/chunks/FormulaPlugin-DJ39BtqV.mjs.map +1 -0
  31. package/dist/chunks/GapCursorNavigation-DCWOmopl.mjs +2 -0
  32. package/dist/chunks/{GapCursorNavigation-BuXngVu-.mjs.map → GapCursorNavigation-DCWOmopl.mjs.map} +1 -1
  33. package/dist/chunks/GapCursorPlugin-2iR6506y.mjs +2 -0
  34. package/dist/chunks/{GapCursorPlugin-DAxVzXRs.mjs.map → GapCursorPlugin-2iR6506y.mjs.map} +1 -1
  35. package/dist/chunks/{HardBreakPlugin-DlbSlrdq.mjs → HardBreakPlugin-vniSvTgq.mjs} +2 -2
  36. package/dist/chunks/{HardBreakPlugin-DlbSlrdq.mjs.map → HardBreakPlugin-vniSvTgq.mjs.map} +1 -1
  37. package/dist/chunks/{HeadingPlugin-uMAjPOk5.mjs → HeadingPlugin-DUKsLuMd.mjs} +2 -2
  38. package/dist/chunks/{HeadingPlugin-uMAjPOk5.mjs.map → HeadingPlugin-DUKsLuMd.mjs.map} +1 -1
  39. package/dist/chunks/{HighlightPlugin-Bj7FPkIQ.mjs → HighlightPlugin-DRTAE1N5.mjs} +2 -2
  40. package/dist/chunks/{HighlightPlugin-Bj7FPkIQ.mjs.map → HighlightPlugin-DRTAE1N5.mjs.map} +1 -1
  41. package/dist/chunks/HorizontalRulePlugin-B9OvwrKB.mjs +2 -0
  42. package/dist/chunks/{HorizontalRulePlugin-DUVmTQpX.mjs.map → HorizontalRulePlugin-B9OvwrKB.mjs.map} +1 -1
  43. package/dist/chunks/{ImagePlugin-FToCOjd5.mjs → ImagePlugin-CwxTRr6d.mjs} +2 -2
  44. package/dist/chunks/{ImagePlugin-FToCOjd5.mjs.map → ImagePlugin-CwxTRr6d.mjs.map} +1 -1
  45. package/dist/chunks/{InlineCodePlugin-pISIoGQE.mjs → InlineCodePlugin-uxgMUX_E.mjs} +2 -2
  46. package/dist/chunks/{InlineCodePlugin-pISIoGQE.mjs.map → InlineCodePlugin-uxgMUX_E.mjs.map} +1 -1
  47. package/dist/chunks/{LinkPlugin-Ct5Z180S.mjs → LinkPlugin-CvWHbSkb.mjs} +2 -2
  48. package/dist/chunks/{LinkPlugin-Ct5Z180S.mjs.map → LinkPlugin-CvWHbSkb.mjs.map} +1 -1
  49. package/dist/chunks/{ListPlugin-DAY5ezNs.mjs → ListPlugin-BchSFWVn.mjs} +2 -2
  50. package/dist/chunks/{ListPlugin-DAY5ezNs.mjs.map → ListPlugin-BchSFWVn.mjs.map} +1 -1
  51. package/dist/chunks/{MarkdownHTMLRegistry-CKEx7LkR.mjs → MarkdownHTMLRegistry-Q7l0d6Ma.mjs} +2 -2
  52. package/dist/chunks/{MarkdownHTMLRegistry-CKEx7LkR.mjs.map → MarkdownHTMLRegistry-Q7l0d6Ma.mjs.map} +1 -1
  53. package/dist/chunks/{MarkdownParser-CWt3M6jR.mjs → MarkdownParser-Dp62mfUq.mjs} +2 -2
  54. package/dist/chunks/{MarkdownParser-CWt3M6jR.mjs.map → MarkdownParser-Dp62mfUq.mjs.map} +1 -1
  55. package/dist/chunks/{MarkdownSerializer-J-i28out.mjs → MarkdownSerializer-DBELFAeo.mjs} +2 -2
  56. package/dist/chunks/{MarkdownSerializer-J-i28out.mjs.map → MarkdownSerializer-DBELFAeo.mjs.map} +1 -1
  57. package/dist/chunks/MathFont-BS8IwYh2.mjs +2 -0
  58. package/dist/chunks/MathFont-BS8IwYh2.mjs.map +1 -0
  59. package/dist/chunks/NodeSelectionCommands-WH5snxr_.mjs +2 -0
  60. package/dist/chunks/{NodeSelectionCommands-1PjwUDTJ.mjs.map → NodeSelectionCommands-WH5snxr_.mjs.map} +1 -1
  61. package/dist/chunks/PluginHelpers-KDuTlmXm.mjs +2 -0
  62. package/dist/chunks/{PluginHelpers-Dx_0hfDe.mjs.map → PluginHelpers-KDuTlmXm.mjs.map} +1 -1
  63. package/dist/chunks/{PopupManager-CT-fMZJn.mjs → PopupManager-Cj86uDEB.mjs} +2 -2
  64. package/dist/chunks/{PopupManager-CT-fMZJn.mjs.map → PopupManager-Cj86uDEB.mjs.map} +1 -1
  65. package/dist/chunks/PrintPlugin-D2javl_d.mjs +2 -0
  66. package/dist/chunks/{PrintPlugin-7zz9mhhU.mjs.map → PrintPlugin-D2javl_d.mjs.map} +1 -1
  67. package/dist/chunks/SimpleMark-gTQaSJcO.mjs +2 -0
  68. package/dist/chunks/{SimpleMark-7CQcA4RK.mjs.map → SimpleMark-gTQaSJcO.mjs.map} +1 -1
  69. package/dist/chunks/SmartPastePlugin-BvJQ-fOz.mjs +2 -0
  70. package/dist/chunks/SmartPastePlugin-BvJQ-fOz.mjs.map +1 -0
  71. package/dist/chunks/StarterFonts-BDQPg-cu.mjs +2 -0
  72. package/dist/chunks/StarterFonts-BDQPg-cu.mjs.map +1 -0
  73. package/dist/chunks/{StrikethroughPlugin-C2oWvGc3.mjs → StrikethroughPlugin-BdrG1TTY.mjs} +2 -2
  74. package/dist/chunks/{StrikethroughPlugin-C2oWvGc3.mjs.map → StrikethroughPlugin-BdrG1TTY.mjs.map} +1 -1
  75. package/dist/chunks/{SuperSubPlugin-D1xaKrSu.mjs → SuperSubPlugin-DTZB0Y3D.mjs} +2 -2
  76. package/dist/chunks/{SuperSubPlugin-D1xaKrSu.mjs.map → SuperSubPlugin-DTZB0Y3D.mjs.map} +1 -1
  77. package/dist/chunks/{TablePlugin-PJe3zwr-.mjs → TablePlugin-CPvg9YZS.mjs} +2 -2
  78. package/dist/chunks/{TablePlugin-PJe3zwr-.mjs.map → TablePlugin-CPvg9YZS.mjs.map} +1 -1
  79. package/dist/chunks/{TextColorPlugin-CTd9tfeG.mjs → TextColorPlugin-Ckg3KWvb.mjs} +2 -2
  80. package/dist/chunks/{TextColorPlugin-CTd9tfeG.mjs.map → TextColorPlugin-Ckg3KWvb.mjs.map} +1 -1
  81. package/dist/chunks/{TextDirectionAutoPlugin-CPnKVVuI.mjs → TextDirectionAutoPlugin-DRGbgTlx.mjs} +2 -2
  82. package/dist/chunks/{TextDirectionAutoPlugin-CPnKVVuI.mjs.map → TextDirectionAutoPlugin-DRGbgTlx.mjs.map} +1 -1
  83. package/dist/chunks/TextDirectionPlugin-BCeYyJHo.mjs +2 -0
  84. package/dist/chunks/{TextDirectionPlugin-Bns_03vL.mjs.map → TextDirectionPlugin-BCeYyJHo.mjs.map} +1 -1
  85. package/dist/chunks/TextDirectionService-OFOU6r_s.mjs +2 -0
  86. package/dist/chunks/{TextDirectionService-BcX07mw2.mjs.map → TextDirectionService-OFOU6r_s.mjs.map} +1 -1
  87. package/dist/chunks/TextFormattingPlugin-BhRxSC8q.mjs +2 -0
  88. package/dist/chunks/{TextFormattingPlugin-DBVlePqj.mjs.map → TextFormattingPlugin-BhRxSC8q.mjs.map} +1 -1
  89. package/dist/chunks/ThemeEngine-BUVo_zaT.mjs +3 -0
  90. package/dist/chunks/ThemeEngine-BUVo_zaT.mjs.map +1 -0
  91. package/dist/chunks/ToolbarPlugin-dmTj1jIz.mjs +2 -0
  92. package/dist/chunks/{ToolbarPlugin-DtfGTO_V.mjs.map → ToolbarPlugin-dmTj1jIz.mjs.map} +1 -1
  93. package/dist/chunks/{VideoPlugin-BrR8g6Rz.mjs → VideoPlugin-BugkI7-m.mjs} +2 -2
  94. package/dist/chunks/{VideoPlugin-BrR8g6Rz.mjs.map → VideoPlugin-BugkI7-m.mjs.map} +1 -1
  95. package/dist/chunks/XmlSupport-DIXH5on9.mjs +2 -0
  96. package/dist/chunks/XmlSupport-DIXH5on9.mjs.map +1 -0
  97. package/dist/chunks/full-JM0-SwWy.mjs +2 -0
  98. package/dist/chunks/{full-DSWM4cKQ.mjs.map → full-JM0-SwWy.mjs.map} +1 -1
  99. package/dist/chunks/minimal-DSlR2A27.mjs +2 -0
  100. package/dist/chunks/{minimal-CFkkPXef.mjs.map → minimal-DSlR2A27.mjs.map} +1 -1
  101. package/dist/chunks/register-BjsdJ3Aq.mjs +2 -0
  102. package/dist/chunks/register-BjsdJ3Aq.mjs.map +1 -0
  103. package/dist/chunks/src-5GKFQ2mQ.mjs +2 -0
  104. package/dist/chunks/src-5GKFQ2mQ.mjs.map +1 -0
  105. package/dist/chunks/xml-BsV44TrJ.mjs +2 -0
  106. package/dist/chunks/xml-BsV44TrJ.mjs.map +1 -0
  107. package/dist/editor/NotectlEditor.d.ts.map +1 -1
  108. package/dist/fonts/math.d.ts +3 -0
  109. package/dist/fonts/math.d.ts.map +1 -0
  110. package/dist/fonts/math.mjs +1 -0
  111. package/dist/fonts/starter.d.ts +3 -0
  112. package/dist/fonts/starter.d.ts.map +1 -0
  113. package/dist/fonts/starter.mjs +1 -0
  114. package/dist/fonts.d.ts +4 -4
  115. package/dist/fonts.mjs +1 -1
  116. package/dist/full.d.ts +1 -1
  117. package/dist/full.mjs +1 -1
  118. package/dist/index.d.ts +2 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/markdown.mjs +1 -1
  121. package/dist/notectl-core.mjs +1 -1
  122. package/dist/notectl-core.umd.js +1 -1
  123. package/dist/notectl-core.umd.js.map +1 -1
  124. package/dist/plugins/alignment.mjs +1 -1
  125. package/dist/plugins/bidi-isolation.mjs +1 -1
  126. package/dist/plugins/blockquote.mjs +1 -1
  127. package/dist/plugins/caret-navigation.mjs +1 -1
  128. package/dist/plugins/code-block/CodeBlockHighlighting.d.ts.map +1 -1
  129. package/dist/plugins/code-block.mjs +1 -1
  130. package/dist/plugins/font-size.mjs +1 -1
  131. package/dist/plugins/font.mjs +1 -1
  132. package/dist/plugins/formula/FormulaTypes.d.ts +1 -1
  133. package/dist/plugins/formula.mjs +1 -1
  134. package/dist/plugins/gap-cursor.mjs +1 -1
  135. package/dist/plugins/hard-break.mjs +1 -1
  136. package/dist/plugins/heading.mjs +1 -1
  137. package/dist/plugins/highlight.mjs +1 -1
  138. package/dist/plugins/horizontal-rule.mjs +1 -1
  139. package/dist/plugins/image.mjs +1 -1
  140. package/dist/plugins/inline-code.mjs +1 -1
  141. package/dist/plugins/language.mjs +1 -1
  142. package/dist/plugins/link.mjs +1 -1
  143. package/dist/plugins/list.mjs +1 -1
  144. package/dist/plugins/print.mjs +1 -1
  145. package/dist/plugins/shared.mjs +1 -1
  146. package/dist/plugins/smart-paste/SmartPastePlugin.d.ts.map +1 -1
  147. package/dist/plugins/smart-paste.mjs +1 -1
  148. package/dist/plugins/strikethrough.mjs +1 -1
  149. package/dist/plugins/super-sub.mjs +1 -1
  150. package/dist/plugins/table.mjs +1 -1
  151. package/dist/plugins/text-color.mjs +1 -1
  152. package/dist/plugins/text-direction-auto.mjs +1 -1
  153. package/dist/plugins/text-direction.mjs +1 -1
  154. package/dist/plugins/text-formatting.mjs +1 -1
  155. package/dist/plugins/toolbar.mjs +1 -1
  156. package/dist/plugins/video.mjs +1 -1
  157. package/dist/presets/full.d.ts +1 -1
  158. package/dist/presets/full.mjs +1 -1
  159. package/dist/presets/minimal.d.ts +1 -1
  160. package/dist/presets/minimal.mjs +1 -1
  161. package/dist/presets.d.ts +1 -1
  162. package/dist/presets.mjs +1 -1
  163. package/dist/register.d.ts +3 -0
  164. package/dist/register.d.ts.map +1 -0
  165. package/dist/register.mjs +1 -0
  166. package/package.json +24 -223
  167. package/dist/chunks/CaretNavigationPlugin-CNsT0eb4.mjs +0 -2
  168. package/dist/chunks/CaretNavigationPlugin-CNsT0eb4.mjs.map +0 -1
  169. package/dist/chunks/CodeBlockPlugin-C1hrdbSZ.mjs +0 -2
  170. package/dist/chunks/ColorPickerPopup-DiA68Pzz.mjs +0 -2
  171. package/dist/chunks/Commands-1dFFldi7.mjs +0 -2
  172. package/dist/chunks/FormulaPlugin-By1befrR.mjs.map +0 -1
  173. package/dist/chunks/GapCursorNavigation-BuXngVu-.mjs +0 -2
  174. package/dist/chunks/GapCursorPlugin-DAxVzXRs.mjs +0 -2
  175. package/dist/chunks/HorizontalRulePlugin-DUVmTQpX.mjs +0 -2
  176. package/dist/chunks/NodeSelectionCommands-1PjwUDTJ.mjs +0 -2
  177. package/dist/chunks/PluginHelpers-Dx_0hfDe.mjs +0 -2
  178. package/dist/chunks/PrintPlugin-7zz9mhhU.mjs +0 -2
  179. package/dist/chunks/PrintTypes-CxU69qu3.mjs +0 -3
  180. package/dist/chunks/PrintTypes-CxU69qu3.mjs.map +0 -1
  181. package/dist/chunks/SimpleMark-7CQcA4RK.mjs +0 -2
  182. package/dist/chunks/SmartPastePlugin-CYa_nD9v.mjs +0 -2
  183. package/dist/chunks/SmartPastePlugin-CYa_nD9v.mjs.map +0 -1
  184. package/dist/chunks/TextDirectionPlugin-Bns_03vL.mjs +0 -2
  185. package/dist/chunks/TextDirectionService-BcX07mw2.mjs +0 -2
  186. package/dist/chunks/TextFormattingPlugin-DBVlePqj.mjs +0 -2
  187. package/dist/chunks/ToolbarPlugin-DtfGTO_V.mjs +0 -2
  188. package/dist/chunks/XmlDetector-D7TQpw-e.mjs +0 -2
  189. package/dist/chunks/XmlDetector-D7TQpw-e.mjs.map +0 -1
  190. package/dist/chunks/XmlSupport-BYiRwlkK.mjs +0 -2
  191. package/dist/chunks/XmlSupport-BYiRwlkK.mjs.map +0 -1
  192. package/dist/chunks/fonts-DQC6Uj4r.mjs +0 -2
  193. package/dist/chunks/fonts-DQC6Uj4r.mjs.map +0 -1
  194. package/dist/chunks/full-DSWM4cKQ.mjs +0 -2
  195. package/dist/chunks/minimal-CFkkPXef.mjs +0 -2
  196. package/dist/chunks/src-DiAOfuOT.mjs +0 -2
  197. package/dist/chunks/src-DiAOfuOT.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"}
@@ -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-1PjwUDTJ.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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"}
@@ -0,0 +1,2 @@
1
+ import{l as e,u as n}from"./Selection-HYoVFpAx.mjs";import{n as t}from"./TypedKeys-CA4bfw9O.mjs";var o=class{resolvedLocale;constructor(e){this.resolvedLocale="browser"===e?"undefined"!=typeof navigator?navigator.language.split("-")[0]??"en":"en":e}getLocale(){return this.resolvedLocale}},r=new t("locale");async function c(e,n,t){if("en"===n)return t;const o=e[`./locales/${n}.ts`];if(!o)return t;try{return(await o()).default}catch{return t}}function s(e,n){return!!n&&(e.dispatch(n),!0)}function a(e){return e.charAt(0).toUpperCase()+e.slice(1)}function i(e){return`toggle${a(e)}`}async function l(e,n,t,o){if(n)return n;const c=e.getService(r)?.getLocale()??"en";return"en"===c?t:o(c)}function u(t){const o=t.selection;return e(o)?t.getBlock(o.nodeId):n(o)?t.getBlock(o.anchor.blockId):void 0}function d(t){const o=t.selection;return e(o)?o.nodeId:n(o)?o.anchor.blockId:void 0}function f(t){const o=t.selection;if(e(o))return[o.nodeId];if(!n(o))return[];const r=o.anchor.blockId,c=o.head.blockId;if(r===c)return[r];const s=t.getBlockOrder(),a=s.indexOf(r),i=s.indexOf(c);if(-1===a||-1===i)return[];const l=Math.min(a,i),u=Math.max(a,i);return s.slice(l,u+1)}export{f as a,c,d as i,o as l,s as n,l as o,u as r,i as s,a as t,r as u};
2
+ //# sourceMappingURL=PluginHelpers-KDuTlmXm.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"PluginHelpers-Dx_0hfDe.mjs","names":[],"sources":["../../src/i18n/LocaleService.ts","../../src/plugins/shared/LocaleLoader.ts","../../src/plugins/shared/PluginHelpers.ts"],"sourcesContent":["/**\n * Global locale service that resolves the active language.\n * Registered as a system-level service before plugin init.\n */\n\nimport { ServiceKey } from '../model/TypedKeys.js';\n\nexport class LocaleService {\n\tprivate readonly resolvedLocale: string;\n\n\tconstructor(locale: string) {\n\t\tthis.resolvedLocale =\n\t\t\tlocale === 'browser'\n\t\t\t\t? typeof navigator !== 'undefined'\n\t\t\t\t\t? (navigator.language.split('-')[0] ?? 'en')\n\t\t\t\t\t: 'en'\n\t\t\t\t: locale;\n\t}\n\n\tgetLocale(): string {\n\t\treturn this.resolvedLocale;\n\t}\n}\n\nexport const LocaleServiceKey = new ServiceKey<LocaleService>('locale');\n","/**\n * Shared helper for loading plugin locale bundles.\n *\n * Rationale:\n * Every notectl plugin used to ship its own copy of a ~15-line locale\n * loader: English shortcut, glob lookup, lazy import, try/catch fallback.\n * The logic is identical across ~23 plugins — only the locale type and\n * the default value change. This helper centralizes the pattern so each\n * plugin's `XxxLocale.ts` shrinks to a handful of lines.\n *\n * Why the glob map still lives in the plugin:\n * `import.meta.glob` is statically resolved by the bundler **relative to\n * the file that calls it**. The helper therefore cannot build the glob\n * itself — each plugin must pass in its own `import.meta.glob(...)`\n * result, and the helper takes care of everything else.\n */\n\n/**\n * Signature of a single locale loader as produced by `import.meta.glob`.\n * The bundler wraps each matched module in a thunk returning a Promise\n * that resolves to an ES module whose default export is the locale.\n */\nexport type LocaleModuleLoader<TLocale> = () => Promise<{ default: TLocale }>;\n\n/**\n * Map from the path string emitted by `import.meta.glob` (e.g.\n * `./locales/de.ts`) to its corresponding lazy loader.\n */\nexport type LocaleModuleMap<TLocale> = Record<string, LocaleModuleLoader<TLocale>>;\n\n/**\n * Loads a plugin locale for the requested language with three fallbacks:\n *\n * 1. `lang === 'en'` — returns the default locale immediately, no import.\n * 2. No matching module in the map — returns the default locale.\n * 3. Module import throws — returns the default locale.\n *\n * This is the exact behavior every plugin needs; sharing it removes ~15\n * lines of boilerplate per plugin and guarantees consistent fallback\n * semantics across the entire editor.\n *\n * @param modules The `import.meta.glob('./locales/*.ts', ...)` map from\n * the caller's module. Passing this in from the plugin\n * is mandatory — globs are resolved at the call site.\n * @param lang IETF-style language tag, e.g. `'de'`, `'zh'`, `'en'`.\n * @param fallback English default locale to return when lookup or\n * import fails. Must already be a fully-formed locale.\n */\nexport async function loadLocaleModule<TLocale>(\n\tmodules: LocaleModuleMap<TLocale>,\n\tlang: string,\n\tfallback: TLocale,\n): Promise<TLocale> {\n\tif (lang === 'en') return fallback;\n\n\tconst loader: LocaleModuleLoader<TLocale> | undefined = modules[`./locales/${lang}.ts`];\n\tif (!loader) return fallback;\n\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn fallback;\n\t}\n}\n","/**\n * Shared helper utilities for plugins.\n * Common operations extracted to avoid code duplication across plugins.\n */\n\nimport { LocaleServiceKey } from '../../i18n/LocaleService.js';\nimport type { BlockNode } from '../../model/Document.js';\nimport { isNodeSelection, isTextSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { PluginContext } from '../Plugin.js';\n\n/**\n * Dispatches `tr` when it is non-null and reports whether anything happened.\n * Collapses the command body `if (tr) { dispatch(tr); return true; } return false;`\n * shared by mark toggle commands and attributed-mark operations into a single\n * call: `return dispatchIfPresent(context, tr);`.\n */\nexport function dispatchIfPresent(context: PluginContext, tr: Transaction | null): boolean {\n\tif (!tr) return false;\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Capitalizes the first character of a string. */\nexport function capitalize(s: string): string {\n\treturn s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/** Converts a mark type to its toggle command name (e.g. 'bold' → 'toggleBold'). */\nexport function toCommandName(markType: string): string {\n\treturn `toggle${capitalize(markType)}`;\n}\n\n/**\n * Resolves the locale for a plugin, using config override, default, or dynamic loader.\n * Plugins provide their config locale, a default English locale, and a loader for other languages.\n */\nexport async function resolveLocale<T>(\n\tcontext: PluginContext,\n\tconfigLocale: T | undefined,\n\tdefaultLocale: T,\n\tloader: (lang: string) => Promise<T>,\n): Promise<T> {\n\tif (configLocale) return configLocale;\n\tconst service = context.getService(LocaleServiceKey);\n\tconst lang: string = service?.getLocale() ?? 'en';\n\treturn lang === 'en' ? defaultLocale : loader(lang);\n}\n\n/** Returns the block under the cursor, handling both TextSelection and NodeSelection. */\nexport function getSelectedBlock(state: EditorState): BlockNode | undefined {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return state.getBlock(sel.nodeId);\n\tif (isTextSelection(sel)) return state.getBlock(sel.anchor.blockId);\n\treturn undefined;\n}\n\n/** Returns the block ID under the cursor, handling both TextSelection and NodeSelection. */\nexport function getSelectedBlockId(state: EditorState): BlockId | undefined {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return sel.nodeId;\n\tif (isTextSelection(sel)) return sel.anchor.blockId;\n\treturn undefined;\n}\n\n/**\n * Returns every leaf-block ID covered by the current selection, in document\n * order. A NodeSelection yields its single node; a collapsed or single-block\n * TextSelection yields one ID; a multi-block TextSelection yields the full\n * inclusive range from anchor to head. Used by block-attribute commands\n * (alignment, text direction) that must apply to the whole selection.\n */\nexport function getSelectedBlockIds(state: EditorState): BlockId[] {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) return [sel.nodeId];\n\tif (!isTextSelection(sel)) return [];\n\n\tconst anchorId: BlockId = sel.anchor.blockId;\n\tconst headId: BlockId = sel.head.blockId;\n\tif (anchorId === headId) return [anchorId];\n\n\tconst order: readonly BlockId[] = state.getBlockOrder();\n\tconst anchorIdx: number = order.indexOf(anchorId);\n\tconst headIdx: number = order.indexOf(headId);\n\tif (anchorIdx === -1 || headIdx === -1) return [];\n\n\tconst from: number = Math.min(anchorIdx, headIdx);\n\tconst to: number = Math.max(anchorIdx, headIdx);\n\treturn order.slice(from, to + 1) as BlockId[];\n}\n"],"mappings":"iGAOA,IAAa,EAAb,MACC,eAEA,WAAA,CAAY,GACX,KAAK,eACO,YAAX,EACwB,oBAAd,UACL,UAAU,SAAS,MAAM,KAAK,IAAM,KACrC,KACD,CACL,CAEA,SAAA,GACC,OAAO,KAAK,cACb,GAGY,EAAmB,IAAI,EAA0B,UCwB9D,eAAsB,EACrB,EACA,EACA,GAEA,GAAa,OAAT,EAAe,OAAO,EAE1B,MAAM,EAAkD,EAAQ,aAAa,QAC7E,IAAK,EAAQ,OAAO,EAEpB,IAEC,aADkB,KACP,OACZ,CAAA,MACC,OAAO,CACR,CACD,CC7CA,SAAgB,EAAkB,EAAwB,GACzD,QAAK,IACL,EAAQ,SAAS,IACV,EACR,CAGA,SAAgB,EAAW,GAC1B,OAAO,EAAE,OAAO,GAAG,cAAgB,EAAE,MAAM,EAC5C,CAGA,SAAgB,EAAc,GAC7B,MAAO,SAAS,EAAW,IAC5B,CAMA,eAAsB,EACrB,EACA,EACA,EACA,GAEA,GAAI,EAAc,OAAO,EAEzB,MAAM,EADU,EAAQ,WAAW,IACL,aAAe,KAC7C,MAAgB,OAAT,EAAgB,EAAgB,EAAO,EAC/C,CAGA,SAAgB,EAAiB,GAChC,MAAM,EAAM,EAAM,UAClB,OAAI,EAAgB,GAAa,EAAM,SAAS,EAAI,QAChD,EAAgB,GAAa,EAAM,SAAS,EAAI,OAAO,cAA3D,CAED,CAGA,SAAgB,EAAmB,GAClC,MAAM,EAAM,EAAM,UAClB,OAAI,EAAgB,GAAa,EAAI,OACjC,EAAgB,GAAa,EAAI,OAAO,aAA5C,CAED,CASA,SAAgB,EAAoB,GACnC,MAAM,EAAM,EAAM,UAElB,GAAI,EAAgB,GAAM,MAAO,CAAC,EAAI,QACtC,IAAK,EAAgB,GAAM,MAAO,GAElC,MAAM,EAAoB,EAAI,OAAO,QAC/B,EAAkB,EAAI,KAAK,QACjC,GAAI,IAAa,EAAQ,MAAO,CAAC,GAEjC,MAAM,EAA4B,EAAM,gBAClC,EAAoB,EAAM,QAAQ,GAClC,EAAkB,EAAM,QAAQ,GACtC,IAAkB,IAAd,IAAgC,IAAZ,EAAgB,MAAO,GAE/C,MAAM,EAAe,KAAK,IAAI,EAAW,GACnC,EAAa,KAAK,IAAI,EAAW,GACvC,OAAO,EAAM,MAAM,EAAM,EAAK,EAC/B"}
1
+ {"version":3,"file":"PluginHelpers-KDuTlmXm.mjs","names":[],"sources":["../../src/i18n/LocaleService.ts","../../src/plugins/shared/LocaleLoader.ts","../../src/plugins/shared/PluginHelpers.ts"],"sourcesContent":["/**\n * Global locale service that resolves the active language.\n * Registered as a system-level service before plugin init.\n */\n\nimport { ServiceKey } from '../model/TypedKeys.js';\n\nexport class LocaleService {\n\tprivate readonly resolvedLocale: string;\n\n\tconstructor(locale: string) {\n\t\tthis.resolvedLocale =\n\t\t\tlocale === 'browser'\n\t\t\t\t? typeof navigator !== 'undefined'\n\t\t\t\t\t? (navigator.language.split('-')[0] ?? 'en')\n\t\t\t\t\t: 'en'\n\t\t\t\t: locale;\n\t}\n\n\tgetLocale(): string {\n\t\treturn this.resolvedLocale;\n\t}\n}\n\nexport const LocaleServiceKey = new ServiceKey<LocaleService>('locale');\n","/**\n * Shared helper for loading plugin locale bundles.\n *\n * Rationale:\n * Every notectl plugin used to ship its own copy of a ~15-line locale\n * loader: English shortcut, glob lookup, lazy import, try/catch fallback.\n * The logic is identical across ~23 plugins — only the locale type and\n * the default value change. This helper centralizes the pattern so each\n * plugin's `XxxLocale.ts` shrinks to a handful of lines.\n *\n * Why the glob map still lives in the plugin:\n * `import.meta.glob` is statically resolved by the bundler **relative to\n * the file that calls it**. The helper therefore cannot build the glob\n * itself — each plugin must pass in its own `import.meta.glob(...)`\n * result, and the helper takes care of everything else.\n */\n\n/**\n * Signature of a single locale loader as produced by `import.meta.glob`.\n * The bundler wraps each matched module in a thunk returning a Promise\n * that resolves to an ES module whose default export is the locale.\n */\nexport type LocaleModuleLoader<TLocale> = () => Promise<{ default: TLocale }>;\n\n/**\n * Map from the path string emitted by `import.meta.glob` (e.g.\n * `./locales/de.ts`) to its corresponding lazy loader.\n */\nexport type LocaleModuleMap<TLocale> = Record<string, LocaleModuleLoader<TLocale>>;\n\n/**\n * Loads a plugin locale for the requested language with three fallbacks:\n *\n * 1. `lang === 'en'` — returns the default locale immediately, no import.\n * 2. No matching module in the map — returns the default locale.\n * 3. Module import throws — returns the default locale.\n *\n * This is the exact behavior every plugin needs; sharing it removes ~15\n * lines of boilerplate per plugin and guarantees consistent fallback\n * semantics across the entire editor.\n *\n * @param modules The `import.meta.glob('./locales/*.ts', ...)` map from\n * the caller's module. Passing this in from the plugin\n * is mandatory — globs are resolved at the call site.\n * @param lang IETF-style language tag, e.g. `'de'`, `'zh'`, `'en'`.\n * @param fallback English default locale to return when lookup or\n * import fails. Must already be a fully-formed locale.\n */\nexport async function loadLocaleModule<TLocale>(\n\tmodules: LocaleModuleMap<TLocale>,\n\tlang: string,\n\tfallback: TLocale,\n): Promise<TLocale> {\n\tif (lang === 'en') return fallback;\n\n\tconst loader: LocaleModuleLoader<TLocale> | undefined = modules[`./locales/${lang}.ts`];\n\tif (!loader) return fallback;\n\n\ttry {\n\t\tconst mod = await loader();\n\t\treturn mod.default;\n\t} catch {\n\t\treturn fallback;\n\t}\n}\n","/**\n * Shared helper utilities for plugins.\n * Common operations extracted to avoid code duplication across plugins.\n */\n\nimport { LocaleServiceKey } from '../../i18n/LocaleService.js';\nimport type { BlockNode } from '../../model/Document.js';\nimport { isNodeSelection, isTextSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Transaction } from '../../state/Transaction.js';\nimport type { PluginContext } from '../Plugin.js';\n\n/**\n * Dispatches `tr` when it is non-null and reports whether anything happened.\n * Collapses the command body `if (tr) { dispatch(tr); return true; } return false;`\n * shared by mark toggle commands and attributed-mark operations into a single\n * call: `return dispatchIfPresent(context, tr);`.\n */\nexport function dispatchIfPresent(context: PluginContext, tr: Transaction | null): boolean {\n\tif (!tr) return false;\n\tcontext.dispatch(tr);\n\treturn true;\n}\n\n/** Capitalizes the first character of a string. */\nexport function capitalize(s: string): string {\n\treturn s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/** Converts a mark type to its toggle command name (e.g. 'bold' → 'toggleBold'). */\nexport function toCommandName(markType: string): string {\n\treturn `toggle${capitalize(markType)}`;\n}\n\n/**\n * Resolves the locale for a plugin, using config override, default, or dynamic loader.\n * Plugins provide their config locale, a default English locale, and a loader for other languages.\n */\nexport async function resolveLocale<T>(\n\tcontext: PluginContext,\n\tconfigLocale: T | undefined,\n\tdefaultLocale: T,\n\tloader: (lang: string) => Promise<T>,\n): Promise<T> {\n\tif (configLocale) return configLocale;\n\tconst service = context.getService(LocaleServiceKey);\n\tconst lang: string = service?.getLocale() ?? 'en';\n\treturn lang === 'en' ? defaultLocale : loader(lang);\n}\n\n/** Returns the block under the cursor, handling both TextSelection and NodeSelection. */\nexport function getSelectedBlock(state: EditorState): BlockNode | undefined {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return state.getBlock(sel.nodeId);\n\tif (isTextSelection(sel)) return state.getBlock(sel.anchor.blockId);\n\treturn undefined;\n}\n\n/** Returns the block ID under the cursor, handling both TextSelection and NodeSelection. */\nexport function getSelectedBlockId(state: EditorState): BlockId | undefined {\n\tconst sel = state.selection;\n\tif (isNodeSelection(sel)) return sel.nodeId;\n\tif (isTextSelection(sel)) return sel.anchor.blockId;\n\treturn undefined;\n}\n\n/**\n * Returns every leaf-block ID covered by the current selection, in document\n * order. A NodeSelection yields its single node; a collapsed or single-block\n * TextSelection yields one ID; a multi-block TextSelection yields the full\n * inclusive range from anchor to head. Used by block-attribute commands\n * (alignment, text direction) that must apply to the whole selection.\n */\nexport function getSelectedBlockIds(state: EditorState): BlockId[] {\n\tconst sel = state.selection;\n\n\tif (isNodeSelection(sel)) return [sel.nodeId];\n\tif (!isTextSelection(sel)) return [];\n\n\tconst anchorId: BlockId = sel.anchor.blockId;\n\tconst headId: BlockId = sel.head.blockId;\n\tif (anchorId === headId) return [anchorId];\n\n\tconst order: readonly BlockId[] = state.getBlockOrder();\n\tconst anchorIdx: number = order.indexOf(anchorId);\n\tconst headIdx: number = order.indexOf(headId);\n\tif (anchorIdx === -1 || headIdx === -1) return [];\n\n\tconst from: number = Math.min(anchorIdx, headIdx);\n\tconst to: number = Math.max(anchorIdx, headIdx);\n\treturn order.slice(from, to + 1) as BlockId[];\n}\n"],"mappings":"iGAOA,IAAa,EAAb,MACC,eAEA,WAAA,CAAY,GACX,KAAK,eACO,YAAX,EACwB,oBAAd,UACL,UAAU,SAAS,MAAM,KAAK,IAAM,KACrC,KACD,CACL,CAEA,SAAA,GACC,OAAO,KAAK,cACb,GAGY,EAAmB,IAAI,EAA0B,UCwB9D,eAAsB,EACrB,EACA,EACA,GAEA,GAAa,OAAT,EAAe,OAAO,EAE1B,MAAM,EAAkD,EAAQ,aAAa,QAC7E,IAAK,EAAQ,OAAO,EAEpB,IAEC,aADkB,KACP,OACZ,CAAA,MACC,OAAO,CACR,CACD,CC7CA,SAAgB,EAAkB,EAAwB,GACzD,QAAK,IACL,EAAQ,SAAS,IACV,EACR,CAGA,SAAgB,EAAW,GAC1B,OAAO,EAAE,OAAO,GAAG,cAAgB,EAAE,MAAM,EAC5C,CAGA,SAAgB,EAAc,GAC7B,MAAO,SAAS,EAAW,IAC5B,CAMA,eAAsB,EACrB,EACA,EACA,EACA,GAEA,GAAI,EAAc,OAAO,EAEzB,MAAM,EADU,EAAQ,WAAW,IACL,aAAe,KAC7C,MAAgB,OAAT,EAAgB,EAAgB,EAAO,EAC/C,CAGA,SAAgB,EAAiB,GAChC,MAAM,EAAM,EAAM,UAClB,OAAI,EAAgB,GAAa,EAAM,SAAS,EAAI,QAChD,EAAgB,GAAa,EAAM,SAAS,EAAI,OAAO,cAA3D,CAED,CAGA,SAAgB,EAAmB,GAClC,MAAM,EAAM,EAAM,UAClB,OAAI,EAAgB,GAAa,EAAI,OACjC,EAAgB,GAAa,EAAI,OAAO,aAA5C,CAED,CASA,SAAgB,EAAoB,GACnC,MAAM,EAAM,EAAM,UAElB,GAAI,EAAgB,GAAM,MAAO,CAAC,EAAI,QACtC,IAAK,EAAgB,GAAM,MAAO,GAElC,MAAM,EAAoB,EAAI,OAAO,QAC/B,EAAkB,EAAI,KAAK,QACjC,GAAI,IAAa,EAAQ,MAAO,CAAC,GAEjC,MAAM,EAA4B,EAAM,gBAClC,EAAoB,EAAM,QAAQ,GAClC,EAAkB,EAAM,QAAQ,GACtC,IAAkB,IAAd,IAAgC,IAAZ,EAAgB,MAAO,GAE/C,MAAM,EAAe,KAAK,IAAI,EAAW,GACnC,EAAa,KAAK,IAAI,EAAW,GACvC,OAAO,EAAM,MAAM,EAAM,EAAK,EAC/B"}
@@ -1,2 +1,2 @@
1
- import{i as e}from"./Platform-ByobkiCc.mjs";import{n as t}from"./TypedKeys-CA4bfw9O.mjs";import{a as s,i as n,t as o}from"./PopupPositioning-BFh6Ed1D.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-CT-fMZJn.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-CT-fMZJn.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{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