@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
@@ -1,2 +1,2 @@
1
- import{c as e,o}from"./PluginHelpers-Dx_0hfDe.mjs";import{a as t,t as r}from"./ColorValidation-DAijTjG9.mjs";import{t as a}from"./InlineStyleMarkSpec-CjSRj4f_.mjs";import{t as s}from"./color-picker-C9B2rYw-.mjs";import{a as l,i as c,t as i}from"./ColorPickerPopup-DiA68Pzz.mjs";var f={label:"Text Color",tooltip:"Text Color",resetLabel:"Default",ariaLabelPrefix:"Text color"},m=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-Dcl3kgtd.mjs"),"./locales/de.ts":()=>import("./de-DHs9i4af.mjs"),"./locales/es.ts":()=>import("./es-DHxdoEzR.mjs"),"./locales/fr.ts":()=>import("./fr-SbpHNrQ-.mjs"),"./locales/hi.ts":()=>import("./hi-By8YwVIX.mjs"),"./locales/pt.ts":()=>import("./pt-DgfMoLWR.mjs"),"./locales/ru.ts":()=>import("./ru-C-APN_dm.mjs"),"./locales/zh.ts":()=>import("./zh-CYV-db-K.mjs")});async function d(o){return e(m,o,f)}var p=["#000000","#434343","#666666","#999999","#b7b7b7","#cccccc","#d9d9d9","#efefef","#f3f3f3","#ffffff","#980000","#ff0000","#ff9900","#ffff00","#00ff00","#00ffff","#4a86e8","#0000ff","#9900ff","#ff00ff","#e6b8af","#f4cccc","#fce5cd","#fff2cc","#d9ead3","#d0e0e3","#c9daf8","#cfe2f3","#d9d2e9","#ead1dc","#dd7e6b","#ea9999","#f9cb9c","#ffe599","#b6d7a8","#a2c4c9","#a4c2f4","#9fc5e8","#b4a7d6","#d5a6bd","#cc4125","#e06666","#f6b26b","#ffd966","#93c47d","#76a5af","#6d9eeb","#6fa8dc","#8e7cc3","#c27ba0","#a61c00","#cc0000","#e69138","#f1c232","#6aa84f","#45818e","#3c78d8","#3d85c6","#674ea7","#a64d79","#85200c","#990000","#b45f06","#bf9000","#38761d","#134f5c","#1155cc","#0b5394","#351c75","#741b47"],n=class{id="textColor";name="Text Color";priority=23;config;colors;locale;constructor(e){this.config={...e},this.colors=t(e?.colors,p,"TextColorPlugin")}async init(e){this.locale=await o(e,this.config.locale,f,d),e.registerStyleSheet(s),this.registerMarkSpec(e),this.registerCommands(e),this.registerToolbarItem(e)}registerMarkSpec(e){e.registerMarkSpec(a({type:"textColor",rank:5,valueAttr:"color",domStyleProperty:"color",cssProperty:"color",validate:r,validateOnParse:!0}))}registerCommands(e){e.registerCommand("removeTextColor",()=>l(e,e.getState(),"textColor"))}registerToolbarItem(e){const o=['<svg xmlns="http://www.w3.org/2000/svg"',' viewBox="0 0 24 24">','<path d="M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2zm-1.38 9L12 5.67 14.38 12H9.62z"/>','<rect x="3" y="19.5" width="18" height="3"',' rx="0.5" fill="#e53935"/>',"</svg>"].join("");e.registerToolbarItem({id:"textColor",group:"format",icon:o,label:this.locale.label,tooltip:this.locale.tooltip,command:"removeTextColor",popupType:"custom",renderPopup:(e,o,t)=>{i(e,o,{markType:"textColor",colors:this.colors,columns:10,resetLabel:this.locale.resetLabel,resetCommand:"removeTextColor",ariaLabelPrefix:this.locale.ariaLabelPrefix,onClose:t})},isActive:e=>c(e,"textColor")})}};export{f as n,d as r,n as t};
2
- //# sourceMappingURL=TextColorPlugin-CTd9tfeG.mjs.map
1
+ import{c as e,o}from"./PluginHelpers-KDuTlmXm.mjs";import{a as t,t as r}from"./ColorValidation-DAijTjG9.mjs";import{t as a}from"./InlineStyleMarkSpec-CjSRj4f_.mjs";import{t as s}from"./color-picker-C9B2rYw-.mjs";import{a as l,i as c,t as i}from"./ColorPickerPopup-CyF26zIU.mjs";var f={label:"Text Color",tooltip:"Text Color",resetLabel:"Default",ariaLabelPrefix:"Text color"},m=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-Dcl3kgtd.mjs"),"./locales/de.ts":()=>import("./de-DHs9i4af.mjs"),"./locales/es.ts":()=>import("./es-DHxdoEzR.mjs"),"./locales/fr.ts":()=>import("./fr-SbpHNrQ-.mjs"),"./locales/hi.ts":()=>import("./hi-By8YwVIX.mjs"),"./locales/pt.ts":()=>import("./pt-DgfMoLWR.mjs"),"./locales/ru.ts":()=>import("./ru-C-APN_dm.mjs"),"./locales/zh.ts":()=>import("./zh-CYV-db-K.mjs")});async function d(o){return e(m,o,f)}var p=["#000000","#434343","#666666","#999999","#b7b7b7","#cccccc","#d9d9d9","#efefef","#f3f3f3","#ffffff","#980000","#ff0000","#ff9900","#ffff00","#00ff00","#00ffff","#4a86e8","#0000ff","#9900ff","#ff00ff","#e6b8af","#f4cccc","#fce5cd","#fff2cc","#d9ead3","#d0e0e3","#c9daf8","#cfe2f3","#d9d2e9","#ead1dc","#dd7e6b","#ea9999","#f9cb9c","#ffe599","#b6d7a8","#a2c4c9","#a4c2f4","#9fc5e8","#b4a7d6","#d5a6bd","#cc4125","#e06666","#f6b26b","#ffd966","#93c47d","#76a5af","#6d9eeb","#6fa8dc","#8e7cc3","#c27ba0","#a61c00","#cc0000","#e69138","#f1c232","#6aa84f","#45818e","#3c78d8","#3d85c6","#674ea7","#a64d79","#85200c","#990000","#b45f06","#bf9000","#38761d","#134f5c","#1155cc","#0b5394","#351c75","#741b47"],n=class{id="textColor";name="Text Color";priority=23;config;colors;locale;constructor(e){this.config={...e},this.colors=t(e?.colors,p,"TextColorPlugin")}async init(e){this.locale=await o(e,this.config.locale,f,d),e.registerStyleSheet(s),this.registerMarkSpec(e),this.registerCommands(e),this.registerToolbarItem(e)}registerMarkSpec(e){e.registerMarkSpec(a({type:"textColor",rank:5,valueAttr:"color",domStyleProperty:"color",cssProperty:"color",validate:r,validateOnParse:!0}))}registerCommands(e){e.registerCommand("removeTextColor",()=>l(e,e.getState(),"textColor"))}registerToolbarItem(e){const o=['<svg xmlns="http://www.w3.org/2000/svg"',' viewBox="0 0 24 24">','<path d="M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2zm-1.38 9L12 5.67 14.38 12H9.62z"/>','<rect x="3" y="19.5" width="18" height="3"',' rx="0.5" fill="#e53935"/>',"</svg>"].join("");e.registerToolbarItem({id:"textColor",group:"format",icon:o,label:this.locale.label,tooltip:this.locale.tooltip,command:"removeTextColor",popupType:"custom",renderPopup:(e,o,t)=>{i(e,o,{markType:"textColor",colors:this.colors,columns:10,resetLabel:this.locale.resetLabel,resetCommand:"removeTextColor",ariaLabelPrefix:this.locale.ariaLabelPrefix,onClose:t})},isActive:e=>c(e,"textColor")})}};export{f as n,d as r,n as t};
2
+ //# sourceMappingURL=TextColorPlugin-Ckg3KWvb.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextColorPlugin-CTd9tfeG.mjs","names":[],"sources":["../../src/plugins/text-color/TextColorLocale.ts","../../src/plugins/text-color/TextColorPalette.ts","../../src/plugins/text-color/TextColorPlugin.ts"],"sourcesContent":["/** Locale interface and default English locale for the TextColorPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\n// --- Locale Interface ---\n\nexport interface TextColorLocale {\n\treadonly label: string;\n\treadonly tooltip: string;\n\treadonly resetLabel: string;\n\treadonly ariaLabelPrefix: string;\n}\n\n// --- Default English Locale ---\n\nexport const TEXT_COLOR_LOCALE_EN: TextColorLocale = {\n\tlabel: 'Text Color',\n\ttooltip: 'Text Color',\n\tresetLabel: 'Default',\n\tariaLabelPrefix: 'Text color',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: LocaleModuleMap<TextColorLocale> = import.meta.glob<{\n\tdefault: TextColorLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadTextColorLocale(lang: string): Promise<TextColorLocale> {\n\treturn loadLocaleModule(localeModules, lang, TEXT_COLOR_LOCALE_EN);\n}\n","/**\n * Default text-color palette (Google Docs style: 10 columns x 7 rows).\n * Used by TextColorPlugin when no `colors` override is provided.\n */\nexport const COLOR_PALETTE: readonly string[] = [\n\t// Row 1 — dark\n\t'#000000',\n\t'#434343',\n\t'#666666',\n\t'#999999',\n\t'#b7b7b7',\n\t'#cccccc',\n\t'#d9d9d9',\n\t'#efefef',\n\t'#f3f3f3',\n\t'#ffffff',\n\t// Row 2 — vivid\n\t'#980000',\n\t'#ff0000',\n\t'#ff9900',\n\t'#ffff00',\n\t'#00ff00',\n\t'#00ffff',\n\t'#4a86e8',\n\t'#0000ff',\n\t'#9900ff',\n\t'#ff00ff',\n\t// Row 3 — light 3\n\t'#e6b8af',\n\t'#f4cccc',\n\t'#fce5cd',\n\t'#fff2cc',\n\t'#d9ead3',\n\t'#d0e0e3',\n\t'#c9daf8',\n\t'#cfe2f3',\n\t'#d9d2e9',\n\t'#ead1dc',\n\t// Row 4 — light 2\n\t'#dd7e6b',\n\t'#ea9999',\n\t'#f9cb9c',\n\t'#ffe599',\n\t'#b6d7a8',\n\t'#a2c4c9',\n\t'#a4c2f4',\n\t'#9fc5e8',\n\t'#b4a7d6',\n\t'#d5a6bd',\n\t// Row 5 — light 1\n\t'#cc4125',\n\t'#e06666',\n\t'#f6b26b',\n\t'#ffd966',\n\t'#93c47d',\n\t'#76a5af',\n\t'#6d9eeb',\n\t'#6fa8dc',\n\t'#8e7cc3',\n\t'#c27ba0',\n\t// Row 6 — dark 1\n\t'#a61c00',\n\t'#cc0000',\n\t'#e69138',\n\t'#f1c232',\n\t'#6aa84f',\n\t'#45818e',\n\t'#3c78d8',\n\t'#3d85c6',\n\t'#674ea7',\n\t'#a64d79',\n\t// Row 7 — dark 2\n\t'#85200c',\n\t'#990000',\n\t'#b45f06',\n\t'#bf9000',\n\t'#38761d',\n\t'#134f5c',\n\t'#1155cc',\n\t'#0b5394',\n\t'#351c75',\n\t'#741b47',\n];\n","/**\n * TextColorPlugin: registers a text color mark with attrs,\n * toolbar button with a color picker popup, and removeTextColor command.\n */\n\nimport { COLOR_PICKER_CSS } from '../../editor/styles/color-picker.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { isColorMarkActive, removeColorMark } from '../shared/ColorMarkOperations.js';\nimport { renderColorPickerPopup } from '../shared/ColorPickerPopup.js';\nimport { isValidCSSColor, resolveColors } from '../shared/ColorValidation.js';\nimport { createInlineStyleMarkSpec } from '../shared/InlineStyleMarkSpec.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport {\n\tTEXT_COLOR_LOCALE_EN,\n\ttype TextColorLocale,\n\tloadTextColorLocale,\n} from './TextColorLocale.js';\nimport { COLOR_PALETTE } from './TextColorPalette.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\ttextColor: { color: string };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface TextColorConfig {\n\t/**\n\t * Restricts the color picker to a specific set of hex colors.\n\t * Each value must be a valid hex color code (`#RGB` or `#RRGGBB`).\n\t * Duplicates are removed automatically (case-insensitive).\n\t * When omitted, the full default palette is shown.\n\t */\n\treadonly colors?: readonly string[];\n\treadonly locale?: TextColorLocale;\n}\n\n// --- Plugin ---\n\nexport class TextColorPlugin implements Plugin {\n\treadonly id = 'textColor';\n\treadonly name = 'Text Color';\n\treadonly priority = 23;\n\n\tprivate readonly config: TextColorConfig;\n\tprivate readonly colors: readonly string[];\n\tprivate locale!: TextColorLocale;\n\n\tconstructor(config?: Partial<TextColorConfig>) {\n\t\tthis.config = { ...config };\n\t\tthis.colors = resolveColors(config?.colors, COLOR_PALETTE, 'TextColorPlugin');\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tTEXT_COLOR_LOCALE_EN,\n\t\t\tloadTextColorLocale,\n\t\t);\n\n\t\tcontext.registerStyleSheet(COLOR_PICKER_CSS);\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tcontext.registerMarkSpec(\n\t\t\tcreateInlineStyleMarkSpec({\n\t\t\t\ttype: 'textColor',\n\t\t\t\trank: 5,\n\t\t\t\tvalueAttr: 'color',\n\t\t\t\tdomStyleProperty: 'color',\n\t\t\t\tcssProperty: 'color',\n\t\t\t\tvalidate: isValidCSSColor,\n\t\t\t\tvalidateOnParse: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('removeTextColor', () => {\n\t\t\treturn removeColorMark(context, context.getState(), 'textColor');\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst pathD =\n\t\t\t'M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2z' + 'm-1.38 9L12 5.67 14.38 12H9.62z';\n\t\tconst icon: string = [\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\"',\n\t\t\t' viewBox=\"0 0 24 24\">',\n\t\t\t`<path d=\"${pathD}\"/>`,\n\t\t\t'<rect x=\"3\" y=\"19.5\" width=\"18\" height=\"3\"',\n\t\t\t' rx=\"0.5\" fill=\"#e53935\"/>',\n\t\t\t'</svg>',\n\t\t].join('');\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'textColor',\n\t\t\tgroup: 'format',\n\t\t\ticon,\n\t\t\tlabel: this.locale.label,\n\t\t\ttooltip: this.locale.tooltip,\n\t\t\tcommand: 'removeTextColor',\n\t\t\tpopupType: 'custom',\n\t\t\trenderPopup: (container, ctx, onClose) => {\n\t\t\t\trenderColorPickerPopup(container, ctx, {\n\t\t\t\t\tmarkType: 'textColor',\n\t\t\t\t\tcolors: this.colors,\n\t\t\t\t\tcolumns: 10,\n\t\t\t\t\tresetLabel: this.locale.resetLabel,\n\t\t\t\t\tresetCommand: 'removeTextColor',\n\t\t\t\t\tariaLabelPrefix: this.locale.ariaLabelPrefix,\n\t\t\t\t\tonClose,\n\t\t\t\t});\n\t\t\t},\n\t\t\tisActive: (state: EditorState) => isColorMarkActive(state, 'textColor'),\n\t\t});\n\t}\n}\n"],"mappings":"sRAeA,IAAa,EAAwC,CACpD,MAAO,aACP,QAAS,aACT,WAAY,UACZ,gBAAiB,cAKZ,iBAAkD,OAAA,OAAA,CAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,uBAIxD,eAAsB,EAAoB,GACzC,OAAO,EAAiB,EAAe,EAAM,EAC9C,CC1BA,IAAa,EAAmC,CAE/C,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,WCtCY,EAAb,MACC,GAAc,YACd,KAAgB,aAChB,SAAoB,GAEpB,OACA,OACA,OAEA,WAAA,CAAY,GACX,KAAK,OAAS,IAAK,GACnB,KAAK,OAAS,EAAc,GAAQ,OAAQ,EAAe,kBAC5D,CAEA,UAAM,CAAK,GACV,KAAK,aAAe,EACnB,EACA,KAAK,OAAO,OACZ,EACA,GAGD,EAAQ,mBAAmB,GAC3B,KAAK,iBAAiB,GACtB,KAAK,iBAAiB,GACtB,KAAK,oBAAoB,EAC1B,CAEA,gBAAA,CAAyB,GACxB,EAAQ,iBACP,EAA0B,CACzB,KAAM,YACN,KAAM,EACN,UAAW,QACX,iBAAkB,QAClB,YAAa,QACb,SAAU,EACV,iBAAiB,IAGpB,CAEA,gBAAA,CAAyB,GACxB,EAAQ,gBAAgB,kBAAA,IAChB,EAAgB,EAAS,EAAQ,WAAY,aAEtD,CAEA,mBAAA,CAA4B,GAG3B,MAAM,EAAe,CACpB,0CACA,wBACA,gGACA,6CACA,6BACA,UACC,KAAK,IAEP,EAAQ,oBAAoB,CAC3B,GAAI,YACJ,MAAO,SACP,OACA,MAAO,KAAK,OAAO,MACnB,QAAS,KAAK,OAAO,QACrB,QAAS,kBACT,UAAW,SACX,YAAA,CAAc,EAAW,EAAK,KAC7B,EAAuB,EAAW,EAAK,CACtC,SAAU,YACV,OAAQ,KAAK,OACb,QAAS,GACT,WAAY,KAAK,OAAO,WACxB,aAAc,kBACd,gBAAiB,KAAK,OAAO,gBAC7B,aAGF,SAAW,GAAuB,EAAkB,EAAO,cAE7D"}
1
+ {"version":3,"file":"TextColorPlugin-Ckg3KWvb.mjs","names":[],"sources":["../../src/plugins/text-color/TextColorLocale.ts","../../src/plugins/text-color/TextColorPalette.ts","../../src/plugins/text-color/TextColorPlugin.ts"],"sourcesContent":["/** Locale interface and default English locale for the TextColorPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\n// --- Locale Interface ---\n\nexport interface TextColorLocale {\n\treadonly label: string;\n\treadonly tooltip: string;\n\treadonly resetLabel: string;\n\treadonly ariaLabelPrefix: string;\n}\n\n// --- Default English Locale ---\n\nexport const TEXT_COLOR_LOCALE_EN: TextColorLocale = {\n\tlabel: 'Text Color',\n\ttooltip: 'Text Color',\n\tresetLabel: 'Default',\n\tariaLabelPrefix: 'Text color',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: LocaleModuleMap<TextColorLocale> = import.meta.glob<{\n\tdefault: TextColorLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadTextColorLocale(lang: string): Promise<TextColorLocale> {\n\treturn loadLocaleModule(localeModules, lang, TEXT_COLOR_LOCALE_EN);\n}\n","/**\n * Default text-color palette (Google Docs style: 10 columns x 7 rows).\n * Used by TextColorPlugin when no `colors` override is provided.\n */\nexport const COLOR_PALETTE: readonly string[] = [\n\t// Row 1 — dark\n\t'#000000',\n\t'#434343',\n\t'#666666',\n\t'#999999',\n\t'#b7b7b7',\n\t'#cccccc',\n\t'#d9d9d9',\n\t'#efefef',\n\t'#f3f3f3',\n\t'#ffffff',\n\t// Row 2 — vivid\n\t'#980000',\n\t'#ff0000',\n\t'#ff9900',\n\t'#ffff00',\n\t'#00ff00',\n\t'#00ffff',\n\t'#4a86e8',\n\t'#0000ff',\n\t'#9900ff',\n\t'#ff00ff',\n\t// Row 3 — light 3\n\t'#e6b8af',\n\t'#f4cccc',\n\t'#fce5cd',\n\t'#fff2cc',\n\t'#d9ead3',\n\t'#d0e0e3',\n\t'#c9daf8',\n\t'#cfe2f3',\n\t'#d9d2e9',\n\t'#ead1dc',\n\t// Row 4 — light 2\n\t'#dd7e6b',\n\t'#ea9999',\n\t'#f9cb9c',\n\t'#ffe599',\n\t'#b6d7a8',\n\t'#a2c4c9',\n\t'#a4c2f4',\n\t'#9fc5e8',\n\t'#b4a7d6',\n\t'#d5a6bd',\n\t// Row 5 — light 1\n\t'#cc4125',\n\t'#e06666',\n\t'#f6b26b',\n\t'#ffd966',\n\t'#93c47d',\n\t'#76a5af',\n\t'#6d9eeb',\n\t'#6fa8dc',\n\t'#8e7cc3',\n\t'#c27ba0',\n\t// Row 6 — dark 1\n\t'#a61c00',\n\t'#cc0000',\n\t'#e69138',\n\t'#f1c232',\n\t'#6aa84f',\n\t'#45818e',\n\t'#3c78d8',\n\t'#3d85c6',\n\t'#674ea7',\n\t'#a64d79',\n\t// Row 7 — dark 2\n\t'#85200c',\n\t'#990000',\n\t'#b45f06',\n\t'#bf9000',\n\t'#38761d',\n\t'#134f5c',\n\t'#1155cc',\n\t'#0b5394',\n\t'#351c75',\n\t'#741b47',\n];\n","/**\n * TextColorPlugin: registers a text color mark with attrs,\n * toolbar button with a color picker popup, and removeTextColor command.\n */\n\nimport { COLOR_PICKER_CSS } from '../../editor/styles/color-picker.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { isColorMarkActive, removeColorMark } from '../shared/ColorMarkOperations.js';\nimport { renderColorPickerPopup } from '../shared/ColorPickerPopup.js';\nimport { isValidCSSColor, resolveColors } from '../shared/ColorValidation.js';\nimport { createInlineStyleMarkSpec } from '../shared/InlineStyleMarkSpec.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport {\n\tTEXT_COLOR_LOCALE_EN,\n\ttype TextColorLocale,\n\tloadTextColorLocale,\n} from './TextColorLocale.js';\nimport { COLOR_PALETTE } from './TextColorPalette.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\ttextColor: { color: string };\n\t}\n}\n\n// --- Configuration ---\n\nexport interface TextColorConfig {\n\t/**\n\t * Restricts the color picker to a specific set of hex colors.\n\t * Each value must be a valid hex color code (`#RGB` or `#RRGGBB`).\n\t * Duplicates are removed automatically (case-insensitive).\n\t * When omitted, the full default palette is shown.\n\t */\n\treadonly colors?: readonly string[];\n\treadonly locale?: TextColorLocale;\n}\n\n// --- Plugin ---\n\nexport class TextColorPlugin implements Plugin {\n\treadonly id = 'textColor';\n\treadonly name = 'Text Color';\n\treadonly priority = 23;\n\n\tprivate readonly config: TextColorConfig;\n\tprivate readonly colors: readonly string[];\n\tprivate locale!: TextColorLocale;\n\n\tconstructor(config?: Partial<TextColorConfig>) {\n\t\tthis.config = { ...config };\n\t\tthis.colors = resolveColors(config?.colors, COLOR_PALETTE, 'TextColorPlugin');\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tTEXT_COLOR_LOCALE_EN,\n\t\t\tloadTextColorLocale,\n\t\t);\n\n\t\tcontext.registerStyleSheet(COLOR_PICKER_CSS);\n\t\tthis.registerMarkSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerMarkSpec(context: PluginContext): void {\n\t\tcontext.registerMarkSpec(\n\t\t\tcreateInlineStyleMarkSpec({\n\t\t\t\ttype: 'textColor',\n\t\t\t\trank: 5,\n\t\t\t\tvalueAttr: 'color',\n\t\t\t\tdomStyleProperty: 'color',\n\t\t\t\tcssProperty: 'color',\n\t\t\t\tvalidate: isValidCSSColor,\n\t\t\t\tvalidateOnParse: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('removeTextColor', () => {\n\t\t\treturn removeColorMark(context, context.getState(), 'textColor');\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst pathD =\n\t\t\t'M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2z' + 'm-1.38 9L12 5.67 14.38 12H9.62z';\n\t\tconst icon: string = [\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\"',\n\t\t\t' viewBox=\"0 0 24 24\">',\n\t\t\t`<path d=\"${pathD}\"/>`,\n\t\t\t'<rect x=\"3\" y=\"19.5\" width=\"18\" height=\"3\"',\n\t\t\t' rx=\"0.5\" fill=\"#e53935\"/>',\n\t\t\t'</svg>',\n\t\t].join('');\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'textColor',\n\t\t\tgroup: 'format',\n\t\t\ticon,\n\t\t\tlabel: this.locale.label,\n\t\t\ttooltip: this.locale.tooltip,\n\t\t\tcommand: 'removeTextColor',\n\t\t\tpopupType: 'custom',\n\t\t\trenderPopup: (container, ctx, onClose) => {\n\t\t\t\trenderColorPickerPopup(container, ctx, {\n\t\t\t\t\tmarkType: 'textColor',\n\t\t\t\t\tcolors: this.colors,\n\t\t\t\t\tcolumns: 10,\n\t\t\t\t\tresetLabel: this.locale.resetLabel,\n\t\t\t\t\tresetCommand: 'removeTextColor',\n\t\t\t\t\tariaLabelPrefix: this.locale.ariaLabelPrefix,\n\t\t\t\t\tonClose,\n\t\t\t\t});\n\t\t\t},\n\t\t\tisActive: (state: EditorState) => isColorMarkActive(state, 'textColor'),\n\t\t});\n\t}\n}\n"],"mappings":"sRAeA,IAAa,EAAwC,CACpD,MAAO,aACP,QAAS,aACT,WAAY,UACZ,gBAAiB,cAKZ,iBAAkD,OAAA,OAAA,CAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,uBAIxD,eAAsB,EAAoB,GACzC,OAAO,EAAiB,EAAe,EAAM,EAC9C,CC1BA,IAAa,EAAmC,CAE/C,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UAEA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,WCtCY,EAAb,MACC,GAAc,YACd,KAAgB,aAChB,SAAoB,GAEpB,OACA,OACA,OAEA,WAAA,CAAY,GACX,KAAK,OAAS,IAAK,GACnB,KAAK,OAAS,EAAc,GAAQ,OAAQ,EAAe,kBAC5D,CAEA,UAAM,CAAK,GACV,KAAK,aAAe,EACnB,EACA,KAAK,OAAO,OACZ,EACA,GAGD,EAAQ,mBAAmB,GAC3B,KAAK,iBAAiB,GACtB,KAAK,iBAAiB,GACtB,KAAK,oBAAoB,EAC1B,CAEA,gBAAA,CAAyB,GACxB,EAAQ,iBACP,EAA0B,CACzB,KAAM,YACN,KAAM,EACN,UAAW,QACX,iBAAkB,QAClB,YAAa,QACb,SAAU,EACV,iBAAiB,IAGpB,CAEA,gBAAA,CAAyB,GACxB,EAAQ,gBAAgB,kBAAA,IAChB,EAAgB,EAAS,EAAQ,WAAY,aAEtD,CAEA,mBAAA,CAA4B,GAG3B,MAAM,EAAe,CACpB,0CACA,wBACA,gGACA,6CACA,6BACA,UACC,KAAK,IAEP,EAAQ,oBAAoB,CAC3B,GAAI,YACJ,MAAO,SACP,OACA,MAAO,KAAK,OAAO,MACnB,QAAS,KAAK,OAAO,QACrB,QAAS,kBACT,UAAW,SACX,YAAA,CAAc,EAAW,EAAK,KAC7B,EAAuB,EAAW,EAAK,CACtC,SAAU,YACV,OAAQ,KAAK,OACb,QAAS,GACT,WAAY,KAAK,OAAO,WACxB,aAAc,kBACd,gBAAiB,KAAK,OAAO,gBAC7B,aAGF,SAAW,GAAuB,EAAkB,EAAO,cAE7D"}
@@ -1,2 +1,2 @@
1
- import{_ as t,h as e,i as r}from"./Document-827l3P80.mjs";import{t as i}from"./TextDirectionService-BcX07mw2.mjs";import{n,r as o,t as s}from"./DirectionDetection-CDVSEWQ6.mjs";function c(t,e,r){const i=t.getNodePath(e.id);if(i)return{type:"setNodeAttr",path:i,attrs:{...e.attrs,dir:r},previousAttrs:e.attrs}}function a(i,n,a,d){const u=n.getBlock(i.blockId);if(!u||!a.has(u.type))return;if("auto"!==o(u)&&e(u)>0)return;const f=t(u),p=r(u,i.offset),l=s(f.slice(0,p)+i.text+f.slice(p));if(!l)return;const h=c(n,u,l);h&&d.push(h)}function d(e,i,n,a){const d=i.getBlock(e.blockId);if(!d||!n.has(d.type))return;const u=o(d);if("auto"===u)return;const f=t(d),p=r(d,e.from),l=r(d,e.to),h=f.slice(0,p)+f.slice(l);if(0===h.length){const t=c(i,d,"auto");return void(t&&a.push(t))}const g=s(h);if(!g||g===u)return;const m=c(i,d,g);m&&a.push(m)}var u={autoDetect:!0,inherit:!0,preserve:!0},f=class{id="text-direction-auto";name="Text Direction Auto-detect";priority=93;dependencies=["text-direction"];config;constructor(t){this.config={...u,...t}}init(e){const r=e.getService(i);if(!r)throw new Error("TextDirectionAutoPlugin requires TextDirectionPlugin to be registered first.");const{directableTypes:o}=r;this.config.preserve&&function(t,e){t.registerMiddleware((t,r,i)=>{let n=!1;const o=t.steps.map(t=>{if("setBlockType"!==t.type)return t;if(!e.has(t.nodeType))return t;const r=t.previousAttrs?.dir;return r&&"auto"!==r?(n=!0,{...t,attrs:{...t.attrs,dir:r}}):t});i(n?{...t,steps:o}:t)},{name:"text-direction:preserve-dir"})}(e,o),this.config.autoDetect&&function(t,e){t.registerMiddleware((t,r,i)=>{const n=function(t){const e=/* @__PURE__ */new Set;for(const r of t)if("setBlockType"===r.type)e.add(r.blockId);else if("setNodeAttr"===r.type){const t=r.path[r.path.length-1];t&&e.add(t)}return e}(t.steps),o=[];for(const s of t.steps)if("insertText"===s.type){if(n.has(s.blockId))continue;a(s,r,e,o)}else if("deleteText"===s.type){if(n.has(s.blockId))continue;d(s,r,e,o)}i(o.length>0?{...t,steps:[...t.steps,...o]}:t)},{name:"text-direction:auto-detect"})}(e,o),this.config.inherit&&function(e,r){e.registerMiddleware((e,i,o)=>{let c=!1;const a=e.steps.map(e=>{if("insertNode"!==e.type)return e;if(!r.has(e.node.type))return e;if("auto"!==String(e.node.attrs?.dir??"auto"))return e;const o=t(e.node);if(o.length>0){const t=s(o);if(t)return c=!0,{...e,node:{...e.node,attrs:{...e.node.attrs,dir:t}}}}const a=n(i,e.parentPath,e.index);return a&&"auto"!==a?(c=!0,{...e,node:{...e.node,attrs:{...e.node.attrs,dir:a}}}):e});o(c?{...e,steps:a}:e)},{name:"text-direction:inherit-dir"})}(e,o)}};export{f as t};
2
- //# sourceMappingURL=TextDirectionAutoPlugin-CPnKVVuI.mjs.map
1
+ import{_ as t,h as e,i as r}from"./Document-827l3P80.mjs";import{t as i}from"./TextDirectionService-OFOU6r_s.mjs";import{n,r as o,t as s}from"./DirectionDetection-CDVSEWQ6.mjs";function c(t,e,r){const i=t.getNodePath(e.id);if(i)return{type:"setNodeAttr",path:i,attrs:{...e.attrs,dir:r},previousAttrs:e.attrs}}function a(i,n,a,d){const u=n.getBlock(i.blockId);if(!u||!a.has(u.type))return;if("auto"!==o(u)&&e(u)>0)return;const f=t(u),p=r(u,i.offset),l=s(f.slice(0,p)+i.text+f.slice(p));if(!l)return;const h=c(n,u,l);h&&d.push(h)}function d(e,i,n,a){const d=i.getBlock(e.blockId);if(!d||!n.has(d.type))return;const u=o(d);if("auto"===u)return;const f=t(d),p=r(d,e.from),l=r(d,e.to),h=f.slice(0,p)+f.slice(l);if(0===h.length){const t=c(i,d,"auto");return void(t&&a.push(t))}const g=s(h);if(!g||g===u)return;const m=c(i,d,g);m&&a.push(m)}var u={autoDetect:!0,inherit:!0,preserve:!0},f=class{id="text-direction-auto";name="Text Direction Auto-detect";priority=93;dependencies=["text-direction"];config;constructor(t){this.config={...u,...t}}init(e){const r=e.getService(i);if(!r)throw new Error("TextDirectionAutoPlugin requires TextDirectionPlugin to be registered first.");const{directableTypes:o}=r;this.config.preserve&&function(t,e){t.registerMiddleware((t,r,i)=>{let n=!1;const o=t.steps.map(t=>{if("setBlockType"!==t.type)return t;if(!e.has(t.nodeType))return t;const r=t.previousAttrs?.dir;return r&&"auto"!==r?(n=!0,{...t,attrs:{...t.attrs,dir:r}}):t});i(n?{...t,steps:o}:t)},{name:"text-direction:preserve-dir"})}(e,o),this.config.autoDetect&&function(t,e){t.registerMiddleware((t,r,i)=>{const n=function(t){const e=/* @__PURE__ */new Set;for(const r of t)if("setBlockType"===r.type)e.add(r.blockId);else if("setNodeAttr"===r.type){const t=r.path[r.path.length-1];t&&e.add(t)}return e}(t.steps),o=[];for(const s of t.steps)if("insertText"===s.type){if(n.has(s.blockId))continue;a(s,r,e,o)}else if("deleteText"===s.type){if(n.has(s.blockId))continue;d(s,r,e,o)}i(o.length>0?{...t,steps:[...t.steps,...o]}:t)},{name:"text-direction:auto-detect"})}(e,o),this.config.inherit&&function(e,r){e.registerMiddleware((e,i,o)=>{let c=!1;const a=e.steps.map(e=>{if("insertNode"!==e.type)return e;if(!r.has(e.node.type))return e;if("auto"!==String(e.node.attrs?.dir??"auto"))return e;const o=t(e.node);if(o.length>0){const t=s(o);if(t)return c=!0,{...e,node:{...e.node,attrs:{...e.node.attrs,dir:t}}}}const a=n(i,e.parentPath,e.index);return a&&"auto"!==a?(c=!0,{...e,node:{...e.node,attrs:{...e.node.attrs,dir:a}}}):e});o(c?{...e,steps:a}:e)},{name:"text-direction:inherit-dir"})}(e,o)}};export{f as t};
2
+ //# sourceMappingURL=TextDirectionAutoPlugin-DRGbgTlx.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextDirectionAutoPlugin-CPnKVVuI.mjs","names":[],"sources":["../../src/plugins/text-direction-auto/TextDirectionAutoMiddleware.ts","../../src/plugins/text-direction-auto/TextDirectionAutoPlugin.ts"],"sourcesContent":["/**\n * Middleware registrations for the TextDirectionAutoPlugin.\n *\n * Three independent middlewares that all operate on the block-level `dir`\n * attribute owned by the {@link TextDirectionPlugin}:\n *\n * - **preserveDir**: keeps `dir` when another plugin replaces a block's\n * attrs (e.g. `setBlockType` paragraph → heading).\n * - **autoDetect**: on `insertText` / `deleteText`, detects direction from\n * the first strong directional character and updates `dir`.\n * - **inheritDir**: on `insertNode`, inherits the new block's `dir` from\n * the nearest sibling (or auto-detects from inserted text content).\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { blockOffsetToTextOffset, getBlockLength, getBlockText } from '../../model/Document.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Step } from '../../state/Transaction.js';\nimport type { PluginContext } from '../Plugin.js';\nimport {\n\tdetectTextDirection,\n\tfindSiblingDirection,\n\tgetBlockDir,\n} from '../text-direction/DirectionDetection.js';\nimport type { TextDirection } from '../text-direction/TextDirectionService.js';\n\nexport function registerPreserveDirMiddleware(\n\tcontext: PluginContext,\n\tdirectableTypes: ReadonlySet<string>,\n): void {\n\tcontext.registerMiddleware(\n\t\t(tr, _state, next) => {\n\t\t\tlet patched = false;\n\n\t\t\tconst patchedSteps = tr.steps.map((step) => {\n\t\t\t\tif (step.type !== 'setBlockType') return step;\n\t\t\t\tif (!directableTypes.has(step.nodeType)) return step;\n\n\t\t\t\tconst prevDir = step.previousAttrs?.dir;\n\t\t\t\tif (!prevDir || prevDir === 'auto') return step;\n\n\t\t\t\tpatched = true;\n\t\t\t\treturn {\n\t\t\t\t\t...step,\n\t\t\t\t\tattrs: { ...step.attrs, dir: prevDir },\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tnext(patched ? { ...tr, steps: patchedSteps } : tr);\n\t\t},\n\t\t{ name: 'text-direction:preserve-dir' },\n\t);\n}\n\nexport function registerAutoDetectMiddleware(\n\tcontext: PluginContext,\n\tdirectableTypes: ReadonlySet<string>,\n): void {\n\tcontext.registerMiddleware(\n\t\t(tr, state, next) => {\n\t\t\tconst attrTouched: ReadonlySet<string> = collectAttrTouchedBlocks(tr.steps);\n\t\t\tconst extraSteps: Step[] = [];\n\n\t\t\tfor (const step of tr.steps) {\n\t\t\t\tif (step.type === 'insertText') {\n\t\t\t\t\tif (attrTouched.has(step.blockId)) continue;\n\t\t\t\t\thandleInsertText(step, state, directableTypes, extraSteps);\n\t\t\t\t} else if (step.type === 'deleteText') {\n\t\t\t\t\tif (attrTouched.has(step.blockId)) continue;\n\t\t\t\t\thandleDeleteText(step, state, directableTypes, extraSteps);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extraSteps.length > 0) {\n\t\t\t\tnext({ ...tr, steps: [...tr.steps, ...extraSteps] });\n\t\t\t} else {\n\t\t\t\tnext(tr);\n\t\t\t}\n\t\t},\n\t\t{ name: 'text-direction:auto-detect' },\n\t);\n}\n\n/**\n * Collects IDs of blocks whose attrs are already mutated by `setBlockType`\n * or `setNodeAttr` steps in the transaction. The auto-detect pass must skip\n * these blocks: its `setNodeAttr` is built from a pre-transaction snapshot\n * and would clobber freshly written attrs (full-replace step semantics).\n */\nfunction collectAttrTouchedBlocks(steps: readonly Step[]): ReadonlySet<string> {\n\tconst touched: Set<string> = new Set();\n\tfor (const step of steps) {\n\t\tif (step.type === 'setBlockType') {\n\t\t\ttouched.add(step.blockId);\n\t\t} else if (step.type === 'setNodeAttr') {\n\t\t\tconst blockId: string | undefined = step.path[step.path.length - 1];\n\t\t\tif (blockId) touched.add(blockId);\n\t\t}\n\t}\n\treturn touched;\n}\n\nfunction buildDirChangeStep(\n\tstate: EditorState,\n\tblock: BlockNode,\n\tdir: TextDirection | 'auto',\n): Step | undefined {\n\tconst path = state.getNodePath(block.id);\n\tif (!path) return undefined;\n\n\treturn {\n\t\ttype: 'setNodeAttr',\n\t\tpath,\n\t\tattrs: { ...block.attrs, dir },\n\t\tpreviousAttrs: block.attrs,\n\t};\n}\n\nfunction handleInsertText(\n\tstep: Extract<Step, { type: 'insertText' }>,\n\tstate: EditorState,\n\tdirectableTypes: ReadonlySet<string>,\n\textraSteps: Step[],\n): void {\n\tconst block = state.getBlock(step.blockId);\n\tif (!block || !directableTypes.has(block.type)) return;\n\n\tif (getBlockDir(block) !== 'auto' && getBlockLength(block) > 0) return;\n\n\tconst existingText: string = getBlockText(block);\n\tconst textOffset: number = blockOffsetToTextOffset(block, step.offset);\n\tconst textAfter: string =\n\t\texistingText.slice(0, textOffset) + step.text + existingText.slice(textOffset);\n\n\tconst detected: TextDirection | null = detectTextDirection(textAfter);\n\tif (!detected) return;\n\n\tconst dirStep: Step | undefined = buildDirChangeStep(state, block, detected);\n\tif (dirStep) extraSteps.push(dirStep);\n}\n\nfunction handleDeleteText(\n\tstep: Extract<Step, { type: 'deleteText' }>,\n\tstate: EditorState,\n\tdirectableTypes: ReadonlySet<string>,\n\textraSteps: Step[],\n): void {\n\tconst block = state.getBlock(step.blockId);\n\tif (!block || !directableTypes.has(block.type)) return;\n\n\tconst currentDir: TextDirection = getBlockDir(block);\n\tif (currentDir === 'auto') return;\n\n\tconst existingText: string = getBlockText(block);\n\tconst fromText: number = blockOffsetToTextOffset(block, step.from);\n\tconst toText: number = blockOffsetToTextOffset(block, step.to);\n\tconst textAfter: string = existingText.slice(0, fromText) + existingText.slice(toText);\n\n\tif (textAfter.length === 0) {\n\t\tconst dirStep: Step | undefined = buildDirChangeStep(state, block, 'auto');\n\t\tif (dirStep) extraSteps.push(dirStep);\n\t\treturn;\n\t}\n\n\tconst detected: TextDirection | null = detectTextDirection(textAfter);\n\tif (!detected || detected === currentDir) return;\n\n\tconst dirStep: Step | undefined = buildDirChangeStep(state, block, detected);\n\tif (dirStep) extraSteps.push(dirStep);\n}\n\nexport function registerInheritDirMiddleware(\n\tcontext: PluginContext,\n\tdirectableTypes: ReadonlySet<string>,\n): void {\n\tcontext.registerMiddleware(\n\t\t(tr, state, next) => {\n\t\t\tlet patched = false;\n\n\t\t\tconst patchedSteps = tr.steps.map((step) => {\n\t\t\t\tif (step.type !== 'insertNode') return step;\n\t\t\t\tif (!directableTypes.has(step.node.type)) return step;\n\n\t\t\t\tconst newDir: string = String(step.node.attrs?.dir ?? 'auto');\n\t\t\t\tif (newDir !== 'auto') return step;\n\n\t\t\t\tconst nodeText: string = getBlockText(step.node);\n\t\t\t\tif (nodeText.length > 0) {\n\t\t\t\t\tconst detected: TextDirection | null = detectTextDirection(nodeText);\n\t\t\t\t\tif (detected) {\n\t\t\t\t\t\tpatched = true;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...step,\n\t\t\t\t\t\t\tnode: {\n\t\t\t\t\t\t\t\t...step.node,\n\t\t\t\t\t\t\t\tattrs: { ...step.node.attrs, dir: detected },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst siblingDir: string | undefined = findSiblingDirection(\n\t\t\t\t\tstate,\n\t\t\t\t\tstep.parentPath,\n\t\t\t\t\tstep.index,\n\t\t\t\t);\n\t\t\t\tif (!siblingDir || siblingDir === 'auto') return step;\n\n\t\t\t\tpatched = true;\n\t\t\t\treturn {\n\t\t\t\t\t...step,\n\t\t\t\t\tnode: {\n\t\t\t\t\t\t...step.node,\n\t\t\t\t\t\tattrs: { ...step.node.attrs, dir: siblingDir },\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tnext(patched ? { ...tr, steps: patchedSteps } : tr);\n\t\t},\n\t\t{ name: 'text-direction:inherit-dir' },\n\t);\n}\n","/**\n * Text direction auto-detection / inheritance / preservation plugin.\n *\n * Registers three transaction middlewares that keep block-level `dir`\n * attributes in sync with content changes. Strictly requires\n * {@link TextDirectionPlugin} (declared via `dependencies`) — without it,\n * the patched `dir` attribute does not exist on NodeSpecs and the\n * `directableTypes` service is unavailable.\n */\n\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { TEXT_DIRECTION_SERVICE_KEY } from '../text-direction/TextDirectionService.js';\nimport {\n\tregisterAutoDetectMiddleware,\n\tregisterInheritDirMiddleware,\n\tregisterPreserveDirMiddleware,\n} from './TextDirectionAutoMiddleware.js';\n\nexport interface TextDirectionAutoConfig {\n\t/**\n\t * Whether to register the auto-detect middleware (insertText / deleteText).\n\t * @default true\n\t */\n\treadonly autoDetect?: boolean;\n\t/**\n\t * Whether to register the inherit-dir middleware (insertNode).\n\t * @default true\n\t */\n\treadonly inherit?: boolean;\n\t/**\n\t * Whether to register the preserve-dir middleware (setBlockType).\n\t * @default true\n\t */\n\treadonly preserve?: boolean;\n}\n\nconst DEFAULT_CONFIG: Required<TextDirectionAutoConfig> = {\n\tautoDetect: true,\n\tinherit: true,\n\tpreserve: true,\n};\n\nexport class TextDirectionAutoPlugin implements Plugin {\n\treadonly id = 'text-direction-auto';\n\treadonly name = 'Text Direction Auto-detect';\n\treadonly priority = 93;\n\treadonly dependencies = ['text-direction'] as const;\n\n\tprivate readonly config: Required<TextDirectionAutoConfig>;\n\n\tconstructor(config?: TextDirectionAutoConfig) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tconst service = context.getService(TEXT_DIRECTION_SERVICE_KEY);\n\t\tif (!service) {\n\t\t\tthrow new Error(\n\t\t\t\t'TextDirectionAutoPlugin requires TextDirectionPlugin to be registered first.',\n\t\t\t);\n\t\t}\n\n\t\tconst { directableTypes } = service;\n\n\t\tif (this.config.preserve) {\n\t\t\tregisterPreserveDirMiddleware(context, directableTypes);\n\t\t}\n\t\tif (this.config.autoDetect) {\n\t\t\tregisterAutoDetectMiddleware(context, directableTypes);\n\t\t}\n\t\tif (this.config.inherit) {\n\t\t\tregisterInheritDirMiddleware(context, directableTypes);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TextDirectionAutoPlugin-DRGbgTlx.mjs","names":[],"sources":["../../src/plugins/text-direction-auto/TextDirectionAutoMiddleware.ts","../../src/plugins/text-direction-auto/TextDirectionAutoPlugin.ts"],"sourcesContent":["/**\n * Middleware registrations for the TextDirectionAutoPlugin.\n *\n * Three independent middlewares that all operate on the block-level `dir`\n * attribute owned by the {@link TextDirectionPlugin}:\n *\n * - **preserveDir**: keeps `dir` when another plugin replaces a block's\n * attrs (e.g. `setBlockType` paragraph → heading).\n * - **autoDetect**: on `insertText` / `deleteText`, detects direction from\n * the first strong directional character and updates `dir`.\n * - **inheritDir**: on `insertNode`, inherits the new block's `dir` from\n * the nearest sibling (or auto-detects from inserted text content).\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { blockOffsetToTextOffset, getBlockLength, getBlockText } from '../../model/Document.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Step } from '../../state/Transaction.js';\nimport type { PluginContext } from '../Plugin.js';\nimport {\n\tdetectTextDirection,\n\tfindSiblingDirection,\n\tgetBlockDir,\n} from '../text-direction/DirectionDetection.js';\nimport type { TextDirection } from '../text-direction/TextDirectionService.js';\n\nexport function registerPreserveDirMiddleware(\n\tcontext: PluginContext,\n\tdirectableTypes: ReadonlySet<string>,\n): void {\n\tcontext.registerMiddleware(\n\t\t(tr, _state, next) => {\n\t\t\tlet patched = false;\n\n\t\t\tconst patchedSteps = tr.steps.map((step) => {\n\t\t\t\tif (step.type !== 'setBlockType') return step;\n\t\t\t\tif (!directableTypes.has(step.nodeType)) return step;\n\n\t\t\t\tconst prevDir = step.previousAttrs?.dir;\n\t\t\t\tif (!prevDir || prevDir === 'auto') return step;\n\n\t\t\t\tpatched = true;\n\t\t\t\treturn {\n\t\t\t\t\t...step,\n\t\t\t\t\tattrs: { ...step.attrs, dir: prevDir },\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tnext(patched ? { ...tr, steps: patchedSteps } : tr);\n\t\t},\n\t\t{ name: 'text-direction:preserve-dir' },\n\t);\n}\n\nexport function registerAutoDetectMiddleware(\n\tcontext: PluginContext,\n\tdirectableTypes: ReadonlySet<string>,\n): void {\n\tcontext.registerMiddleware(\n\t\t(tr, state, next) => {\n\t\t\tconst attrTouched: ReadonlySet<string> = collectAttrTouchedBlocks(tr.steps);\n\t\t\tconst extraSteps: Step[] = [];\n\n\t\t\tfor (const step of tr.steps) {\n\t\t\t\tif (step.type === 'insertText') {\n\t\t\t\t\tif (attrTouched.has(step.blockId)) continue;\n\t\t\t\t\thandleInsertText(step, state, directableTypes, extraSteps);\n\t\t\t\t} else if (step.type === 'deleteText') {\n\t\t\t\t\tif (attrTouched.has(step.blockId)) continue;\n\t\t\t\t\thandleDeleteText(step, state, directableTypes, extraSteps);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (extraSteps.length > 0) {\n\t\t\t\tnext({ ...tr, steps: [...tr.steps, ...extraSteps] });\n\t\t\t} else {\n\t\t\t\tnext(tr);\n\t\t\t}\n\t\t},\n\t\t{ name: 'text-direction:auto-detect' },\n\t);\n}\n\n/**\n * Collects IDs of blocks whose attrs are already mutated by `setBlockType`\n * or `setNodeAttr` steps in the transaction. The auto-detect pass must skip\n * these blocks: its `setNodeAttr` is built from a pre-transaction snapshot\n * and would clobber freshly written attrs (full-replace step semantics).\n */\nfunction collectAttrTouchedBlocks(steps: readonly Step[]): ReadonlySet<string> {\n\tconst touched: Set<string> = new Set();\n\tfor (const step of steps) {\n\t\tif (step.type === 'setBlockType') {\n\t\t\ttouched.add(step.blockId);\n\t\t} else if (step.type === 'setNodeAttr') {\n\t\t\tconst blockId: string | undefined = step.path[step.path.length - 1];\n\t\t\tif (blockId) touched.add(blockId);\n\t\t}\n\t}\n\treturn touched;\n}\n\nfunction buildDirChangeStep(\n\tstate: EditorState,\n\tblock: BlockNode,\n\tdir: TextDirection | 'auto',\n): Step | undefined {\n\tconst path = state.getNodePath(block.id);\n\tif (!path) return undefined;\n\n\treturn {\n\t\ttype: 'setNodeAttr',\n\t\tpath,\n\t\tattrs: { ...block.attrs, dir },\n\t\tpreviousAttrs: block.attrs,\n\t};\n}\n\nfunction handleInsertText(\n\tstep: Extract<Step, { type: 'insertText' }>,\n\tstate: EditorState,\n\tdirectableTypes: ReadonlySet<string>,\n\textraSteps: Step[],\n): void {\n\tconst block = state.getBlock(step.blockId);\n\tif (!block || !directableTypes.has(block.type)) return;\n\n\tif (getBlockDir(block) !== 'auto' && getBlockLength(block) > 0) return;\n\n\tconst existingText: string = getBlockText(block);\n\tconst textOffset: number = blockOffsetToTextOffset(block, step.offset);\n\tconst textAfter: string =\n\t\texistingText.slice(0, textOffset) + step.text + existingText.slice(textOffset);\n\n\tconst detected: TextDirection | null = detectTextDirection(textAfter);\n\tif (!detected) return;\n\n\tconst dirStep: Step | undefined = buildDirChangeStep(state, block, detected);\n\tif (dirStep) extraSteps.push(dirStep);\n}\n\nfunction handleDeleteText(\n\tstep: Extract<Step, { type: 'deleteText' }>,\n\tstate: EditorState,\n\tdirectableTypes: ReadonlySet<string>,\n\textraSteps: Step[],\n): void {\n\tconst block = state.getBlock(step.blockId);\n\tif (!block || !directableTypes.has(block.type)) return;\n\n\tconst currentDir: TextDirection = getBlockDir(block);\n\tif (currentDir === 'auto') return;\n\n\tconst existingText: string = getBlockText(block);\n\tconst fromText: number = blockOffsetToTextOffset(block, step.from);\n\tconst toText: number = blockOffsetToTextOffset(block, step.to);\n\tconst textAfter: string = existingText.slice(0, fromText) + existingText.slice(toText);\n\n\tif (textAfter.length === 0) {\n\t\tconst dirStep: Step | undefined = buildDirChangeStep(state, block, 'auto');\n\t\tif (dirStep) extraSteps.push(dirStep);\n\t\treturn;\n\t}\n\n\tconst detected: TextDirection | null = detectTextDirection(textAfter);\n\tif (!detected || detected === currentDir) return;\n\n\tconst dirStep: Step | undefined = buildDirChangeStep(state, block, detected);\n\tif (dirStep) extraSteps.push(dirStep);\n}\n\nexport function registerInheritDirMiddleware(\n\tcontext: PluginContext,\n\tdirectableTypes: ReadonlySet<string>,\n): void {\n\tcontext.registerMiddleware(\n\t\t(tr, state, next) => {\n\t\t\tlet patched = false;\n\n\t\t\tconst patchedSteps = tr.steps.map((step) => {\n\t\t\t\tif (step.type !== 'insertNode') return step;\n\t\t\t\tif (!directableTypes.has(step.node.type)) return step;\n\n\t\t\t\tconst newDir: string = String(step.node.attrs?.dir ?? 'auto');\n\t\t\t\tif (newDir !== 'auto') return step;\n\n\t\t\t\tconst nodeText: string = getBlockText(step.node);\n\t\t\t\tif (nodeText.length > 0) {\n\t\t\t\t\tconst detected: TextDirection | null = detectTextDirection(nodeText);\n\t\t\t\t\tif (detected) {\n\t\t\t\t\t\tpatched = true;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...step,\n\t\t\t\t\t\t\tnode: {\n\t\t\t\t\t\t\t\t...step.node,\n\t\t\t\t\t\t\t\tattrs: { ...step.node.attrs, dir: detected },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst siblingDir: string | undefined = findSiblingDirection(\n\t\t\t\t\tstate,\n\t\t\t\t\tstep.parentPath,\n\t\t\t\t\tstep.index,\n\t\t\t\t);\n\t\t\t\tif (!siblingDir || siblingDir === 'auto') return step;\n\n\t\t\t\tpatched = true;\n\t\t\t\treturn {\n\t\t\t\t\t...step,\n\t\t\t\t\tnode: {\n\t\t\t\t\t\t...step.node,\n\t\t\t\t\t\tattrs: { ...step.node.attrs, dir: siblingDir },\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tnext(patched ? { ...tr, steps: patchedSteps } : tr);\n\t\t},\n\t\t{ name: 'text-direction:inherit-dir' },\n\t);\n}\n","/**\n * Text direction auto-detection / inheritance / preservation plugin.\n *\n * Registers three transaction middlewares that keep block-level `dir`\n * attributes in sync with content changes. Strictly requires\n * {@link TextDirectionPlugin} (declared via `dependencies`) — without it,\n * the patched `dir` attribute does not exist on NodeSpecs and the\n * `directableTypes` service is unavailable.\n */\n\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { TEXT_DIRECTION_SERVICE_KEY } from '../text-direction/TextDirectionService.js';\nimport {\n\tregisterAutoDetectMiddleware,\n\tregisterInheritDirMiddleware,\n\tregisterPreserveDirMiddleware,\n} from './TextDirectionAutoMiddleware.js';\n\nexport interface TextDirectionAutoConfig {\n\t/**\n\t * Whether to register the auto-detect middleware (insertText / deleteText).\n\t * @default true\n\t */\n\treadonly autoDetect?: boolean;\n\t/**\n\t * Whether to register the inherit-dir middleware (insertNode).\n\t * @default true\n\t */\n\treadonly inherit?: boolean;\n\t/**\n\t * Whether to register the preserve-dir middleware (setBlockType).\n\t * @default true\n\t */\n\treadonly preserve?: boolean;\n}\n\nconst DEFAULT_CONFIG: Required<TextDirectionAutoConfig> = {\n\tautoDetect: true,\n\tinherit: true,\n\tpreserve: true,\n};\n\nexport class TextDirectionAutoPlugin implements Plugin {\n\treadonly id = 'text-direction-auto';\n\treadonly name = 'Text Direction Auto-detect';\n\treadonly priority = 93;\n\treadonly dependencies = ['text-direction'] as const;\n\n\tprivate readonly config: Required<TextDirectionAutoConfig>;\n\n\tconstructor(config?: TextDirectionAutoConfig) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tinit(context: PluginContext): void {\n\t\tconst service = context.getService(TEXT_DIRECTION_SERVICE_KEY);\n\t\tif (!service) {\n\t\t\tthrow new Error(\n\t\t\t\t'TextDirectionAutoPlugin requires TextDirectionPlugin to be registered first.',\n\t\t\t);\n\t\t}\n\n\t\tconst { directableTypes } = service;\n\n\t\tif (this.config.preserve) {\n\t\t\tregisterPreserveDirMiddleware(context, directableTypes);\n\t\t}\n\t\tif (this.config.autoDetect) {\n\t\t\tregisterAutoDetectMiddleware(context, directableTypes);\n\t\t}\n\t\tif (this.config.inherit) {\n\t\t\tregisterInheritDirMiddleware(context, directableTypes);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{a as t,c as e,n as i,o,r}from"./PluginHelpers-KDuTlmXm.mjs";import{r as s}from"./Platform-ByobkiCc.mjs";import{t as n}from"./ShortcutFormatting-TwiufqeV.mjs";import{t as a}from"./NodeSpecPatching-B_yLknTl.mjs";import{t as c}from"./DirectionIcons-Bbawl9ei.mjs";import{t as l}from"./TextDirectionService-OFOU6r_s.mjs";import{r as h}from"./DirectionDetection-CDVSEWQ6.mjs";var m=class{context;pendingDir=null;container=null;constructor(t){this.context=t}attach(t){this.container=t,t.addEventListener("keydown",this.onKeydown),t.addEventListener("keyup",this.onKeyup)}detach(){this.container&&(this.container.removeEventListener("keydown",this.onKeydown),this.container.removeEventListener("keyup",this.onKeyup),this.container=null)}onKeydown=t=>{"Shift"!==t.key||!t.ctrlKey||t.altKey||t.metaKey?this.pendingDir=null:"ShiftLeft"===t.code?this.pendingDir="ltr":"ShiftRight"===t.code&&(this.pendingDir="rtl")};onKeyup=t=>{if("Shift"!==t.key||!this.pendingDir)return;const e=this.pendingDir;this.pendingDir=null;const i="ltr"===e?"setDirectionLTR":"setDirectionRTL";this.context.executeCommand(i)}},u={ltr:"Left to Right",rtl:"Right to Left",auto:"Auto",toolbarLabel:"Text Direction",toolbarTooltip:"Text Direction",announceLTR:"Text direction set to left-to-right",announceRTL:"Text direction set to right-to-left",announceAuto:"Text direction set to automatic"},d=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-BwaoCUVN.mjs"),"./locales/de.ts":()=>import("./de-BdD3DpUB.mjs"),"./locales/es.ts":()=>import("./es-kfKiqpyD.mjs"),"./locales/fr.ts":()=>import("./fr-BSUKEtTk.mjs"),"./locales/hi.ts":()=>import("./hi-Dt89SxNy.mjs"),"./locales/pt.ts":()=>import("./pt-CMrFpUWS.mjs"),"./locales/ru.ts":()=>import("./ru-C9yFslEG.mjs"),"./locales/zh.ts":()=>import("./zh-CnW44JEw.mjs")});async function p(t){return e(d,t,u)}var g={directableTypes:["paragraph","heading","title","subtitle","table_cell","blockquote","list_item"]},D=["ltr","rtl","auto"],f=class{id="text-direction";name="Text Direction";priority=91;config;locale;directableTypes;shiftDirHandler=null;constructor(t){this.config={...g,...t}}async init(t){this.locale=await o(t,this.config.locale,u,p),this.directableTypes=new Set(this.config.directableTypes),this.patchNodeSpecs(t),this.registerCommands(t),this.registerKeymaps(t),this.registerToolbarItem(t),this.registerService(t),s()||(this.shiftDirHandler=new m(t),this.shiftDirHandler.attach(t.getContainer()))}destroy(){this.shiftDirHandler?.detach(),this.shiftDirHandler=null}registerService(t){const e={directableTypes:this.directableTypes,getBlockDir:h};t.registerService(l,e)}patchNodeSpecs(t){a(t.getSchemaRegistry(),this.config.directableTypes,{attrName:"dir",getDefault:()=>"auto",applyToDOM:y})}registerCommands(t){t.registerCommand("setDirectionLTR",()=>{const e=this.setDirection(t,"ltr");return e&&t.announce(this.locale.announceLTR),e}),t.registerCommand("setDirectionRTL",()=>{const e=this.setDirection(t,"rtl");return e&&t.announce(this.locale.announceRTL),e}),t.registerCommand("setDirectionAuto",()=>{const e=this.setDirection(t,"auto");return e&&t.announce(this.locale.announceAuto),e}),t.registerCommand("toggleDirection",()=>{const e=r(t.getState());if(!e||!this.directableTypes.has(e.type))return!1;const i=h(e),o="auto"===i?"rtl":"rtl"===i?"ltr":"auto";return this.setDirection(t,o)})}registerKeymaps(t){t.registerKeymap({"Mod-Shift-D":()=>t.executeCommand("toggleDirection")})}registerToolbarItem(t){const e={ltr:"setDirectionLTR",rtl:"setDirectionRTL",auto:"setDirectionAuto"},i=D.map(t=>({label:this.getDirectionLabel(t),command:e[t],icon:c[t]}));t.registerToolbarItem({id:"text-direction",group:"block",icon:c.auto,label:this.locale.toolbarLabel,tooltip:`${this.locale.toolbarTooltip} (${n("Mod-Shift-D")})`,command:"setDirectionAuto",popupType:"dropdown",popupConfig:{items:i},isActive:t=>this.isNonDefaultDirection(t),isEnabled:t=>this.isDirectable(t),getIcon:t=>{const e=r(t);return e?c[h(e)]??c.auto:c.auto}})}getDirectionLabel(t){return"ltr"===t?this.locale.ltr:"rtl"===t?this.locale.rtl:this.locale.auto}setDirection(e,o){const r=e.getState(),s=t(r);if(0===s.length)return!1;const n=r.transaction("command");let a=!1;for(const t of s){const e=r.getBlock(t);if(!e||!this.directableTypes.has(e.type))continue;const i=r.getNodePath(t);i&&(n.setNodeAttr(i,{...e.attrs,dir:o}),a=!0)}return!!a&&i(e,n.setSelection(r.selection).build())}isNonDefaultDirection(t){const e=r(t);if(!e||!this.directableTypes.has(e.type))return!1;const i=e.attrs?.dir;return null!=i&&"auto"!==i}isDirectable(t){const e=r(t);return null!=e&&this.directableTypes.has(e.type)}};function y(t,e){const i=e.attrs?.dir;"ltr"!==i&&"rtl"!==i&&"auto"!==i||t.setAttribute("dir",i)}export{u as n,p as r,f as t};
2
+ //# sourceMappingURL=TextDirectionPlugin-BCeYyJHo.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextDirectionPlugin-Bns_03vL.mjs","names":[],"sources":["../../src/plugins/text-direction/ShiftDirectionHandler.ts","../../src/plugins/text-direction/TextDirectionLocale.ts","../../src/plugins/text-direction/TextDirectionPlugin.ts"],"sourcesContent":["/**\n * Handles Ctrl+Left-Shift → LTR and Ctrl+Right-Shift → RTL shortcuts.\n *\n * Uses a deferred pattern: sets a pending direction on Ctrl+Shift keydown,\n * and applies it on Shift keyup only if no other key was pressed in between.\n * This prevents conflicts with Ctrl+Shift+<key> shortcuts like Ctrl+Shift+D.\n */\n\nimport type { PluginContext } from '../Plugin.js';\n\nexport class ShiftDirectionHandler {\n\tprivate pendingDir: 'ltr' | 'rtl' | null = null;\n\tprivate container: HTMLElement | null = null;\n\n\tconstructor(private readonly context: PluginContext) {}\n\n\tattach(container: HTMLElement): void {\n\t\tthis.container = container;\n\t\tcontainer.addEventListener('keydown', this.onKeydown);\n\t\tcontainer.addEventListener('keyup', this.onKeyup);\n\t}\n\n\tdetach(): void {\n\t\tif (!this.container) return;\n\t\tthis.container.removeEventListener('keydown', this.onKeydown);\n\t\tthis.container.removeEventListener('keyup', this.onKeyup);\n\t\tthis.container = null;\n\t}\n\n\tprivate readonly onKeydown = (e: KeyboardEvent): void => {\n\t\tif (e.key === 'Shift' && e.ctrlKey && !e.altKey && !e.metaKey) {\n\t\t\tif (e.code === 'ShiftLeft') {\n\t\t\t\tthis.pendingDir = 'ltr';\n\t\t\t} else if (e.code === 'ShiftRight') {\n\t\t\t\tthis.pendingDir = 'rtl';\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\t// Any other keydown cancels the pending direction change\n\t\tthis.pendingDir = null;\n\t};\n\n\tprivate readonly onKeyup = (e: KeyboardEvent): void => {\n\t\tif (e.key !== 'Shift' || !this.pendingDir) return;\n\t\tconst dir: 'ltr' | 'rtl' = this.pendingDir;\n\t\tthis.pendingDir = null;\n\t\tconst command: string = dir === 'ltr' ? 'setDirectionLTR' : 'setDirectionRTL';\n\t\tthis.context.executeCommand(command);\n\t};\n}\n","/** Locale interface and default English locale for the TextDirectionPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\nexport interface TextDirectionLocale {\n\treadonly ltr: string;\n\treadonly rtl: string;\n\treadonly auto: string;\n\treadonly toolbarLabel: string;\n\treadonly toolbarTooltip: string;\n\treadonly announceLTR: string;\n\treadonly announceRTL: string;\n\treadonly announceAuto: string;\n}\n\nexport const TEXT_DIRECTION_LOCALE_EN: TextDirectionLocale = {\n\tltr: 'Left to Right',\n\trtl: 'Right to Left',\n\tauto: 'Auto',\n\ttoolbarLabel: 'Text Direction',\n\ttoolbarTooltip: 'Text Direction',\n\tannounceLTR: 'Text direction set to left-to-right',\n\tannounceRTL: 'Text direction set to right-to-left',\n\tannounceAuto: 'Text direction set to automatic',\n};\n\nconst localeModules: LocaleModuleMap<TextDirectionLocale> = import.meta.glob<{\n\tdefault: TextDirectionLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadTextDirectionLocale(lang: string): Promise<TextDirectionLocale> {\n\treturn loadLocaleModule(localeModules, lang, TEXT_DIRECTION_LOCALE_EN);\n}\n","/**\n * Block-level text direction plugin.\n *\n * Patches NodeSpecs of directable block types to add a `dir` attribute\n * (`'ltr' | 'rtl' | 'auto'`), exposes commands and a toolbar dropdown\n * for changing block direction, registers a `Mod-Shift-D` keymap, and\n * (on Windows/Linux) attaches a `Ctrl+Shift` direction handler.\n *\n * Inline `<bdi>` isolation lives in {@link BidiIsolationPlugin}; the\n * auto-detect / inherit / preserve middlewares live in\n * {@link TextDirectionAutoPlugin}. Both consume the\n * {@link TextDirectionService} that this plugin registers.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport { isMac } from '../../platform/Platform.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { patchNodeSpecAttr } from '../shared/NodeSpecPatching.js';\nimport {\n\tdispatchIfPresent,\n\tgetSelectedBlock,\n\tgetSelectedBlockIds,\n\tresolveLocale,\n} from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { getBlockDir } from './DirectionDetection.js';\nimport { DIRECTION_ICONS } from './DirectionIcons.js';\nimport { ShiftDirectionHandler } from './ShiftDirectionHandler.js';\nimport {\n\tTEXT_DIRECTION_LOCALE_EN,\n\ttype TextDirectionLocale,\n\tloadTextDirectionLocale,\n} from './TextDirectionLocale.js';\nimport {\n\tTEXT_DIRECTION_SERVICE_KEY,\n\ttype TextDirection,\n\ttype TextDirectionService,\n} from './TextDirectionService.js';\n\nexport type { TextDirection };\n\nexport interface TextDirectionConfig {\n\t/** Block types that support direction. */\n\treadonly directableTypes: readonly string[];\n\treadonly locale?: TextDirectionLocale;\n}\n\nconst DEFAULT_CONFIG: TextDirectionConfig = {\n\tdirectableTypes: [\n\t\t'paragraph',\n\t\t'heading',\n\t\t'title',\n\t\t'subtitle',\n\t\t'table_cell',\n\t\t'blockquote',\n\t\t'list_item',\n\t],\n};\n\nconst ALL_DIRECTIONS: readonly TextDirection[] = ['ltr', 'rtl', 'auto'];\n\nexport class TextDirectionPlugin implements Plugin {\n\treadonly id = 'text-direction';\n\treadonly name = 'Text Direction';\n\treadonly priority = 91;\n\n\tprivate readonly config: TextDirectionConfig;\n\tprivate locale!: TextDirectionLocale;\n\tprivate directableTypes!: ReadonlySet<string>;\n\tprivate shiftDirHandler: ShiftDirectionHandler | null = null;\n\n\tconstructor(config?: Partial<TextDirectionConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tTEXT_DIRECTION_LOCALE_EN,\n\t\t\tloadTextDirectionLocale,\n\t\t);\n\n\t\tthis.directableTypes = new Set(this.config.directableTypes);\n\t\tthis.patchNodeSpecs(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerToolbarItem(context);\n\t\tthis.registerService(context);\n\n\t\tif (!isMac()) {\n\t\t\tthis.shiftDirHandler = new ShiftDirectionHandler(context);\n\t\t\tthis.shiftDirHandler.attach(context.getContainer());\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.shiftDirHandler?.detach();\n\t\tthis.shiftDirHandler = null;\n\t}\n\n\tprivate registerService(context: PluginContext): void {\n\t\tconst service: TextDirectionService = {\n\t\t\tdirectableTypes: this.directableTypes,\n\t\t\tgetBlockDir,\n\t\t};\n\t\tcontext.registerService(TEXT_DIRECTION_SERVICE_KEY, service);\n\t}\n\n\tprivate patchNodeSpecs(context: PluginContext): void {\n\t\tpatchNodeSpecAttr(context.getSchemaRegistry(), this.config.directableTypes, {\n\t\t\tattrName: 'dir',\n\t\t\tgetDefault: () => 'auto',\n\t\t\tapplyToDOM: applyDirection,\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('setDirectionLTR', () => {\n\t\t\tconst result: boolean = this.setDirection(context, 'ltr');\n\t\t\tif (result) context.announce(this.locale.announceLTR);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('setDirectionRTL', () => {\n\t\t\tconst result: boolean = this.setDirection(context, 'rtl');\n\t\t\tif (result) context.announce(this.locale.announceRTL);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('setDirectionAuto', () => {\n\t\t\tconst result: boolean = this.setDirection(context, 'auto');\n\t\t\tif (result) context.announce(this.locale.announceAuto);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('toggleDirection', () => {\n\t\t\tconst state = context.getState();\n\t\t\tconst block = getSelectedBlock(state);\n\t\t\tif (!block || !this.directableTypes.has(block.type)) return false;\n\n\t\t\tconst current: TextDirection = getBlockDir(block);\n\t\t\tconst next: TextDirection = current === 'auto' ? 'rtl' : current === 'rtl' ? 'ltr' : 'auto';\n\t\t\treturn this.setDirection(context, next);\n\t\t});\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift-D': () => context.executeCommand('toggleDirection'),\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst commandNames: Readonly<Record<TextDirection, string>> = {\n\t\t\tltr: 'setDirectionLTR',\n\t\t\trtl: 'setDirectionRTL',\n\t\t\tauto: 'setDirectionAuto',\n\t\t};\n\n\t\tconst dropdownItems = ALL_DIRECTIONS.map((dir) => ({\n\t\t\tlabel: this.getDirectionLabel(dir),\n\t\t\tcommand: commandNames[dir],\n\t\t\ticon: DIRECTION_ICONS[dir],\n\t\t}));\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'text-direction',\n\t\t\tgroup: 'block',\n\t\t\ticon: DIRECTION_ICONS.auto,\n\t\t\tlabel: this.locale.toolbarLabel,\n\t\t\ttooltip: `${this.locale.toolbarTooltip} (${formatShortcut('Mod-Shift-D')})`,\n\t\t\tcommand: 'setDirectionAuto',\n\t\t\tpopupType: 'dropdown',\n\t\t\tpopupConfig: { items: dropdownItems },\n\t\t\tisActive: (state) => this.isNonDefaultDirection(state),\n\t\t\tisEnabled: (state) => this.isDirectable(state),\n\t\t\tgetIcon: (state) => {\n\t\t\t\tconst block = getSelectedBlock(state);\n\t\t\t\tif (!block) return DIRECTION_ICONS.auto;\n\t\t\t\tconst dir: TextDirection = getBlockDir(block);\n\t\t\t\treturn DIRECTION_ICONS[dir] ?? DIRECTION_ICONS.auto;\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate getDirectionLabel(dir: TextDirection): string {\n\t\tif (dir === 'ltr') return this.locale.ltr;\n\t\tif (dir === 'rtl') return this.locale.rtl;\n\t\treturn this.locale.auto;\n\t}\n\n\tprivate setDirection(context: PluginContext, direction: TextDirection): boolean {\n\t\tconst state = context.getState();\n\t\tconst blockIds: BlockId[] = getSelectedBlockIds(state);\n\t\tif (blockIds.length === 0) return false;\n\n\t\tconst tb = state.transaction('command');\n\t\tlet changed = false;\n\n\t\tfor (const id of blockIds) {\n\t\t\tconst block = state.getBlock(id);\n\t\t\tif (!block || !this.directableTypes.has(block.type)) continue;\n\n\t\t\tconst path = state.getNodePath(id);\n\t\t\tif (!path) continue;\n\n\t\t\ttb.setNodeAttr(path, { ...block.attrs, dir: direction });\n\t\t\tchanged = true;\n\t\t}\n\n\t\tif (!changed) return false;\n\n\t\treturn dispatchIfPresent(context, tb.setSelection(state.selection).build());\n\t}\n\n\tprivate isNonDefaultDirection(state: EditorState): boolean {\n\t\tconst block = getSelectedBlock(state);\n\t\tif (!block || !this.directableTypes.has(block.type)) return false;\n\t\tconst dir = block.attrs?.dir;\n\t\treturn dir != null && dir !== 'auto';\n\t}\n\n\tprivate isDirectable(state: EditorState): boolean {\n\t\tconst block = getSelectedBlock(state);\n\t\treturn block != null && this.directableTypes.has(block.type);\n\t}\n}\n\nfunction applyDirection(el: HTMLElement, node: BlockNode): void {\n\tconst dir = node.attrs?.dir;\n\tif (dir === 'ltr' || dir === 'rtl' || dir === 'auto') {\n\t\tel.setAttribute('dir', dir);\n\t}\n}\n"],"mappings":"mYAUA,IAAa,EAAb,MAI8B,QAH7B,WAA2C,KAC3C,UAAwC,KAExC,WAAA,CAAY,GAAiB,KAAA,QAAA,CAAyB,CAEtD,MAAA,CAAO,GACN,KAAK,UAAY,EACjB,EAAU,iBAAiB,UAAW,KAAK,WAC3C,EAAU,iBAAiB,QAAS,KAAK,QAC1C,CAEA,MAAA,GACM,KAAK,YACV,KAAK,UAAU,oBAAoB,UAAW,KAAK,WACnD,KAAK,UAAU,oBAAoB,QAAS,KAAK,SACjD,KAAK,UAAY,KAClB,CAEA,UAA8B,IACf,UAAV,EAAE,MAAmB,EAAE,SAAY,EAAE,QAAW,EAAE,QAStD,KAAK,WAAa,KARF,cAAX,EAAE,KACL,KAAK,WAAa,MACG,eAAX,EAAE,OACZ,KAAK,WAAa,QAQrB,QAA4B,IAC3B,GAAc,UAAV,EAAE,MAAoB,KAAK,WAAY,OAC3C,MAAM,EAAqB,KAAK,WAChC,KAAK,WAAa,KAClB,MAAM,EAA0B,QAAR,EAAgB,kBAAoB,kBAC5D,KAAK,QAAQ,eAAe,KChCjB,EAAgD,CAC5D,IAAK,gBACL,IAAK,gBACL,KAAM,OACN,aAAc,iBACd,eAAgB,iBAChB,YAAa,sCACb,YAAa,sCACb,aAAc,mCAGT,iBAAsD,OAAA,OAAA,CAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,uBAI5D,eAAsB,EAAwB,GAC7C,OAAO,EAAiB,EAAe,EAAM,EAC9C,CCiBA,IAAM,EAAsC,CAC3C,gBAAiB,CAChB,YACA,UACA,QACA,WACA,aACA,aACA,cAII,EAA2C,CAAC,MAAO,MAAO,QAEnD,EAAb,MACC,GAAc,iBACd,KAAgB,iBAChB,SAAoB,GAEpB,OACA,OACA,gBACA,gBAAwD,KAExD,WAAA,CAAY,GACX,KAAK,OAAS,IAAK,KAAmB,EACvC,CAEA,UAAM,CAAK,GACV,KAAK,aAAe,EACnB,EACA,KAAK,OAAO,OACZ,EACA,GAGD,KAAK,gBAAkB,IAAI,IAAI,KAAK,OAAO,iBAC3C,KAAK,eAAe,GACpB,KAAK,iBAAiB,GACtB,KAAK,gBAAgB,GACrB,KAAK,oBAAoB,GACzB,KAAK,gBAAgB,GAEhB,MACJ,KAAK,gBAAkB,IAAI,EAAsB,GACjD,KAAK,gBAAgB,OAAO,EAAQ,gBAEtC,CAEA,OAAA,GACC,KAAK,iBAAiB,SACtB,KAAK,gBAAkB,IACxB,CAEA,eAAA,CAAwB,GACvB,MAAM,EAAgC,CACrC,gBAAiB,KAAK,gBACtB,eAED,EAAQ,gBAAgB,EAA4B,EACrD,CAEA,cAAA,CAAuB,GACtB,EAAkB,EAAQ,oBAAqB,KAAK,OAAO,gBAAiB,CAC3E,SAAU,MACV,WAAA,IAAkB,OAClB,WAAY,GAEd,CAEA,gBAAA,CAAyB,GACxB,EAAQ,gBAAgB,kBAAA,KACvB,MAAM,EAAkB,KAAK,aAAa,EAAS,OAEnD,OADI,GAAQ,EAAQ,SAAS,KAAK,OAAO,aAClC,IAGR,EAAQ,gBAAgB,kBAAA,KACvB,MAAM,EAAkB,KAAK,aAAa,EAAS,OAEnD,OADI,GAAQ,EAAQ,SAAS,KAAK,OAAO,aAClC,IAGR,EAAQ,gBAAgB,mBAAA,KACvB,MAAM,EAAkB,KAAK,aAAa,EAAS,QAEnD,OADI,GAAQ,EAAQ,SAAS,KAAK,OAAO,cAClC,IAGR,EAAQ,gBAAgB,kBAAA,KAEvB,MAAM,EAAQ,EADA,EAAQ,YAEtB,IAAK,IAAU,KAAK,gBAAgB,IAAI,EAAM,MAAO,OAAO,EAE5D,MAAM,EAAyB,EAAY,GACrC,EAAkC,SAAZ,EAAqB,MAAoB,QAAZ,EAAoB,MAAQ,OACrF,OAAO,KAAK,aAAa,EAAS,IAEpC,CAEA,eAAA,CAAwB,GACvB,EAAQ,eAAe,CACtB,cAAA,IAAqB,EAAQ,eAAe,oBAE9C,CAEA,mBAAA,CAA4B,GAC3B,MAAM,EAAwD,CAC7D,IAAK,kBACL,IAAK,kBACL,KAAM,oBAGD,EAAgB,EAAe,IAAK,IAAA,CACzC,MAAO,KAAK,kBAAkB,GAC9B,QAAS,EAAa,GACtB,KAAM,EAAgB,MAGvB,EAAQ,oBAAoB,CAC3B,GAAI,iBACJ,MAAO,QACP,KAAM,EAAgB,KACtB,MAAO,KAAK,OAAO,aACnB,QAAS,GAAG,KAAK,OAAO,mBAAmB,EAAe,kBAC1D,QAAS,mBACT,UAAW,WACX,YAAa,CAAE,MAAO,GACtB,SAAW,GAAU,KAAK,sBAAsB,GAChD,UAAY,GAAU,KAAK,aAAa,GACxC,QAAU,IACT,MAAM,EAAQ,EAAiB,GAC/B,OAAK,EAEE,EADoB,EAAY,KACR,EAAgB,KAF5B,EAAgB,OAKtC,CAEA,iBAAA,CAA0B,GACzB,MAAY,QAAR,EAAsB,KAAK,OAAO,IAC1B,QAAR,EAAsB,KAAK,OAAO,IAC/B,KAAK,OAAO,IACpB,CAEA,YAAA,CAAqB,EAAwB,GAC5C,MAAM,EAAQ,EAAQ,WAChB,EAAsB,EAAoB,GAChD,GAAwB,IAApB,EAAS,OAAc,OAAO,EAElC,MAAM,EAAK,EAAM,YAAY,WAC7B,IAAI,GAAU,EAEd,IAAK,MAAM,KAAM,EAAU,CAC1B,MAAM,EAAQ,EAAM,SAAS,GAC7B,IAAK,IAAU,KAAK,gBAAgB,IAAI,EAAM,MAAO,SAErD,MAAM,EAAO,EAAM,YAAY,GAC1B,IAEL,EAAG,YAAY,EAAM,IAAK,EAAM,MAAO,IAAK,IAC5C,GAAU,EACX,CAEA,QAAK,GAEE,EAAkB,EAAS,EAAG,aAAa,EAAM,WAAW,QACpE,CAEA,qBAAA,CAA8B,GAC7B,MAAM,EAAQ,EAAiB,GAC/B,IAAK,IAAU,KAAK,gBAAgB,IAAI,EAAM,MAAO,OAAO,EAC5D,MAAM,EAAM,EAAM,OAAO,IACzB,OAAc,MAAP,GAAuB,SAAR,CACvB,CAEA,YAAA,CAAqB,GACpB,MAAM,EAAQ,EAAiB,GAC/B,OAAgB,MAAT,GAAiB,KAAK,gBAAgB,IAAI,EAAM,KACxD,GAGD,SAAS,EAAe,EAAiB,GACxC,MAAM,EAAM,EAAK,OAAO,IACZ,QAAR,GAAyB,QAAR,GAAyB,SAAR,GACrC,EAAG,aAAa,MAAO,EAEzB"}
1
+ {"version":3,"file":"TextDirectionPlugin-BCeYyJHo.mjs","names":[],"sources":["../../src/plugins/text-direction/ShiftDirectionHandler.ts","../../src/plugins/text-direction/TextDirectionLocale.ts","../../src/plugins/text-direction/TextDirectionPlugin.ts"],"sourcesContent":["/**\n * Handles Ctrl+Left-Shift → LTR and Ctrl+Right-Shift → RTL shortcuts.\n *\n * Uses a deferred pattern: sets a pending direction on Ctrl+Shift keydown,\n * and applies it on Shift keyup only if no other key was pressed in between.\n * This prevents conflicts with Ctrl+Shift+<key> shortcuts like Ctrl+Shift+D.\n */\n\nimport type { PluginContext } from '../Plugin.js';\n\nexport class ShiftDirectionHandler {\n\tprivate pendingDir: 'ltr' | 'rtl' | null = null;\n\tprivate container: HTMLElement | null = null;\n\n\tconstructor(private readonly context: PluginContext) {}\n\n\tattach(container: HTMLElement): void {\n\t\tthis.container = container;\n\t\tcontainer.addEventListener('keydown', this.onKeydown);\n\t\tcontainer.addEventListener('keyup', this.onKeyup);\n\t}\n\n\tdetach(): void {\n\t\tif (!this.container) return;\n\t\tthis.container.removeEventListener('keydown', this.onKeydown);\n\t\tthis.container.removeEventListener('keyup', this.onKeyup);\n\t\tthis.container = null;\n\t}\n\n\tprivate readonly onKeydown = (e: KeyboardEvent): void => {\n\t\tif (e.key === 'Shift' && e.ctrlKey && !e.altKey && !e.metaKey) {\n\t\t\tif (e.code === 'ShiftLeft') {\n\t\t\t\tthis.pendingDir = 'ltr';\n\t\t\t} else if (e.code === 'ShiftRight') {\n\t\t\t\tthis.pendingDir = 'rtl';\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\t// Any other keydown cancels the pending direction change\n\t\tthis.pendingDir = null;\n\t};\n\n\tprivate readonly onKeyup = (e: KeyboardEvent): void => {\n\t\tif (e.key !== 'Shift' || !this.pendingDir) return;\n\t\tconst dir: 'ltr' | 'rtl' = this.pendingDir;\n\t\tthis.pendingDir = null;\n\t\tconst command: string = dir === 'ltr' ? 'setDirectionLTR' : 'setDirectionRTL';\n\t\tthis.context.executeCommand(command);\n\t};\n}\n","/** Locale interface and default English locale for the TextDirectionPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\nexport interface TextDirectionLocale {\n\treadonly ltr: string;\n\treadonly rtl: string;\n\treadonly auto: string;\n\treadonly toolbarLabel: string;\n\treadonly toolbarTooltip: string;\n\treadonly announceLTR: string;\n\treadonly announceRTL: string;\n\treadonly announceAuto: string;\n}\n\nexport const TEXT_DIRECTION_LOCALE_EN: TextDirectionLocale = {\n\tltr: 'Left to Right',\n\trtl: 'Right to Left',\n\tauto: 'Auto',\n\ttoolbarLabel: 'Text Direction',\n\ttoolbarTooltip: 'Text Direction',\n\tannounceLTR: 'Text direction set to left-to-right',\n\tannounceRTL: 'Text direction set to right-to-left',\n\tannounceAuto: 'Text direction set to automatic',\n};\n\nconst localeModules: LocaleModuleMap<TextDirectionLocale> = import.meta.glob<{\n\tdefault: TextDirectionLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadTextDirectionLocale(lang: string): Promise<TextDirectionLocale> {\n\treturn loadLocaleModule(localeModules, lang, TEXT_DIRECTION_LOCALE_EN);\n}\n","/**\n * Block-level text direction plugin.\n *\n * Patches NodeSpecs of directable block types to add a `dir` attribute\n * (`'ltr' | 'rtl' | 'auto'`), exposes commands and a toolbar dropdown\n * for changing block direction, registers a `Mod-Shift-D` keymap, and\n * (on Windows/Linux) attaches a `Ctrl+Shift` direction handler.\n *\n * Inline `<bdi>` isolation lives in {@link BidiIsolationPlugin}; the\n * auto-detect / inherit / preserve middlewares live in\n * {@link TextDirectionAutoPlugin}. Both consume the\n * {@link TextDirectionService} that this plugin registers.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport { isMac } from '../../platform/Platform.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { patchNodeSpecAttr } from '../shared/NodeSpecPatching.js';\nimport {\n\tdispatchIfPresent,\n\tgetSelectedBlock,\n\tgetSelectedBlockIds,\n\tresolveLocale,\n} from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { getBlockDir } from './DirectionDetection.js';\nimport { DIRECTION_ICONS } from './DirectionIcons.js';\nimport { ShiftDirectionHandler } from './ShiftDirectionHandler.js';\nimport {\n\tTEXT_DIRECTION_LOCALE_EN,\n\ttype TextDirectionLocale,\n\tloadTextDirectionLocale,\n} from './TextDirectionLocale.js';\nimport {\n\tTEXT_DIRECTION_SERVICE_KEY,\n\ttype TextDirection,\n\ttype TextDirectionService,\n} from './TextDirectionService.js';\n\nexport type { TextDirection };\n\nexport interface TextDirectionConfig {\n\t/** Block types that support direction. */\n\treadonly directableTypes: readonly string[];\n\treadonly locale?: TextDirectionLocale;\n}\n\nconst DEFAULT_CONFIG: TextDirectionConfig = {\n\tdirectableTypes: [\n\t\t'paragraph',\n\t\t'heading',\n\t\t'title',\n\t\t'subtitle',\n\t\t'table_cell',\n\t\t'blockquote',\n\t\t'list_item',\n\t],\n};\n\nconst ALL_DIRECTIONS: readonly TextDirection[] = ['ltr', 'rtl', 'auto'];\n\nexport class TextDirectionPlugin implements Plugin {\n\treadonly id = 'text-direction';\n\treadonly name = 'Text Direction';\n\treadonly priority = 91;\n\n\tprivate readonly config: TextDirectionConfig;\n\tprivate locale!: TextDirectionLocale;\n\tprivate directableTypes!: ReadonlySet<string>;\n\tprivate shiftDirHandler: ShiftDirectionHandler | null = null;\n\n\tconstructor(config?: Partial<TextDirectionConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tTEXT_DIRECTION_LOCALE_EN,\n\t\t\tloadTextDirectionLocale,\n\t\t);\n\n\t\tthis.directableTypes = new Set(this.config.directableTypes);\n\t\tthis.patchNodeSpecs(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerToolbarItem(context);\n\t\tthis.registerService(context);\n\n\t\tif (!isMac()) {\n\t\t\tthis.shiftDirHandler = new ShiftDirectionHandler(context);\n\t\t\tthis.shiftDirHandler.attach(context.getContainer());\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.shiftDirHandler?.detach();\n\t\tthis.shiftDirHandler = null;\n\t}\n\n\tprivate registerService(context: PluginContext): void {\n\t\tconst service: TextDirectionService = {\n\t\t\tdirectableTypes: this.directableTypes,\n\t\t\tgetBlockDir,\n\t\t};\n\t\tcontext.registerService(TEXT_DIRECTION_SERVICE_KEY, service);\n\t}\n\n\tprivate patchNodeSpecs(context: PluginContext): void {\n\t\tpatchNodeSpecAttr(context.getSchemaRegistry(), this.config.directableTypes, {\n\t\t\tattrName: 'dir',\n\t\t\tgetDefault: () => 'auto',\n\t\t\tapplyToDOM: applyDirection,\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('setDirectionLTR', () => {\n\t\t\tconst result: boolean = this.setDirection(context, 'ltr');\n\t\t\tif (result) context.announce(this.locale.announceLTR);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('setDirectionRTL', () => {\n\t\t\tconst result: boolean = this.setDirection(context, 'rtl');\n\t\t\tif (result) context.announce(this.locale.announceRTL);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('setDirectionAuto', () => {\n\t\t\tconst result: boolean = this.setDirection(context, 'auto');\n\t\t\tif (result) context.announce(this.locale.announceAuto);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('toggleDirection', () => {\n\t\t\tconst state = context.getState();\n\t\t\tconst block = getSelectedBlock(state);\n\t\t\tif (!block || !this.directableTypes.has(block.type)) return false;\n\n\t\t\tconst current: TextDirection = getBlockDir(block);\n\t\t\tconst next: TextDirection = current === 'auto' ? 'rtl' : current === 'rtl' ? 'ltr' : 'auto';\n\t\t\treturn this.setDirection(context, next);\n\t\t});\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift-D': () => context.executeCommand('toggleDirection'),\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst commandNames: Readonly<Record<TextDirection, string>> = {\n\t\t\tltr: 'setDirectionLTR',\n\t\t\trtl: 'setDirectionRTL',\n\t\t\tauto: 'setDirectionAuto',\n\t\t};\n\n\t\tconst dropdownItems = ALL_DIRECTIONS.map((dir) => ({\n\t\t\tlabel: this.getDirectionLabel(dir),\n\t\t\tcommand: commandNames[dir],\n\t\t\ticon: DIRECTION_ICONS[dir],\n\t\t}));\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'text-direction',\n\t\t\tgroup: 'block',\n\t\t\ticon: DIRECTION_ICONS.auto,\n\t\t\tlabel: this.locale.toolbarLabel,\n\t\t\ttooltip: `${this.locale.toolbarTooltip} (${formatShortcut('Mod-Shift-D')})`,\n\t\t\tcommand: 'setDirectionAuto',\n\t\t\tpopupType: 'dropdown',\n\t\t\tpopupConfig: { items: dropdownItems },\n\t\t\tisActive: (state) => this.isNonDefaultDirection(state),\n\t\t\tisEnabled: (state) => this.isDirectable(state),\n\t\t\tgetIcon: (state) => {\n\t\t\t\tconst block = getSelectedBlock(state);\n\t\t\t\tif (!block) return DIRECTION_ICONS.auto;\n\t\t\t\tconst dir: TextDirection = getBlockDir(block);\n\t\t\t\treturn DIRECTION_ICONS[dir] ?? DIRECTION_ICONS.auto;\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate getDirectionLabel(dir: TextDirection): string {\n\t\tif (dir === 'ltr') return this.locale.ltr;\n\t\tif (dir === 'rtl') return this.locale.rtl;\n\t\treturn this.locale.auto;\n\t}\n\n\tprivate setDirection(context: PluginContext, direction: TextDirection): boolean {\n\t\tconst state = context.getState();\n\t\tconst blockIds: BlockId[] = getSelectedBlockIds(state);\n\t\tif (blockIds.length === 0) return false;\n\n\t\tconst tb = state.transaction('command');\n\t\tlet changed = false;\n\n\t\tfor (const id of blockIds) {\n\t\t\tconst block = state.getBlock(id);\n\t\t\tif (!block || !this.directableTypes.has(block.type)) continue;\n\n\t\t\tconst path = state.getNodePath(id);\n\t\t\tif (!path) continue;\n\n\t\t\ttb.setNodeAttr(path, { ...block.attrs, dir: direction });\n\t\t\tchanged = true;\n\t\t}\n\n\t\tif (!changed) return false;\n\n\t\treturn dispatchIfPresent(context, tb.setSelection(state.selection).build());\n\t}\n\n\tprivate isNonDefaultDirection(state: EditorState): boolean {\n\t\tconst block = getSelectedBlock(state);\n\t\tif (!block || !this.directableTypes.has(block.type)) return false;\n\t\tconst dir = block.attrs?.dir;\n\t\treturn dir != null && dir !== 'auto';\n\t}\n\n\tprivate isDirectable(state: EditorState): boolean {\n\t\tconst block = getSelectedBlock(state);\n\t\treturn block != null && this.directableTypes.has(block.type);\n\t}\n}\n\nfunction applyDirection(el: HTMLElement, node: BlockNode): void {\n\tconst dir = node.attrs?.dir;\n\tif (dir === 'ltr' || dir === 'rtl' || dir === 'auto') {\n\t\tel.setAttribute('dir', dir);\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{n as e}from"./TypedKeys-CA4bfw9O.mjs";var t=new e("textDirection");export{t};
2
+ //# sourceMappingURL=TextDirectionService-OFOU6r_s.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextDirectionService-BcX07mw2.mjs","names":[],"sources":["../../src/plugins/text-direction/TextDirectionService.ts"],"sourcesContent":["/**\n * Service contract exposed by `TextDirectionPlugin` to other plugins\n * (e.g. `BidiIsolationPlugin`, `TextDirectionAutoPlugin`) that need to\n * read the current block-level direction or the set of types that\n * support direction.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { ServiceKey } from '../../model/TypedKeys.js';\n\nexport type TextDirection = 'ltr' | 'rtl' | 'auto';\n\nexport interface TextDirectionService {\n\treadonly directableTypes: ReadonlySet<string>;\n\tgetBlockDir(block: BlockNode): TextDirection;\n}\n\nexport const TEXT_DIRECTION_SERVICE_KEY: ServiceKey<TextDirectionService> =\n\tnew ServiceKey<TextDirectionService>('textDirection');\n"],"mappings":"6CAiBA,IAAa,EACZ,IAAI,EAAiC"}
1
+ {"version":3,"file":"TextDirectionService-OFOU6r_s.mjs","names":[],"sources":["../../src/plugins/text-direction/TextDirectionService.ts"],"sourcesContent":["/**\n * Service contract exposed by `TextDirectionPlugin` to other plugins\n * (e.g. `BidiIsolationPlugin`, `TextDirectionAutoPlugin`) that need to\n * read the current block-level direction or the set of types that\n * support direction.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { ServiceKey } from '../../model/TypedKeys.js';\n\nexport type TextDirection = 'ltr' | 'rtl' | 'auto';\n\nexport interface TextDirectionService {\n\treadonly directableTypes: ReadonlySet<string>;\n\tgetBlockDir(block: BlockNode): TextDirection;\n}\n\nexport const TEXT_DIRECTION_SERVICE_KEY: ServiceKey<TextDirectionService> =\n\tnew ServiceKey<TextDirectionService>('textDirection');\n"],"mappings":"6CAiBA,IAAa,EACZ,IAAI,EAAiC"}
@@ -0,0 +1,2 @@
1
+ import{i as t}from"./TypeBrands-Ch9856Gb.mjs";import{_ as e,m as i}from"./Commands-D5ND50PQ.mjs";import{c as s,n as o,o as r,s as n}from"./PluginHelpers-KDuTlmXm.mjs";import{t as a}from"./MarkInputRule-Bdi8KPus.mjs";import{t as l}from"./ShortcutFormatting-TwiufqeV.mjs";var g={boldLabel:"Bold",italicLabel:"Italic",underlineLabel:"Underline"},c=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-Dx2lO0Nm.mjs"),"./locales/de.ts":()=>import("./de-BcPntcnr.mjs"),"./locales/es.ts":()=>import("./es-nRLq7bgP.mjs"),"./locales/fr.ts":()=>import("./fr-DiDhVhyV.mjs"),"./locales/hi.ts":()=>import("./hi-BNJIGWQQ.mjs"),"./locales/pt.ts":()=>import("./pt-D__tcM2T.mjs"),"./locales/ru.ts":()=>import("./ru-CvDl-yEd.mjs"),"./locales/zh.ts":()=>import("./zh-C-wHnDo5.mjs")});async function m(t){return s(c,t,g)}var p={bold:!0,italic:!0,underline:!0},f=[{type:"bold",configKey:"bold",rank:0,tag:"strong",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z"/></svg>',keyBinding:"Mod-B",toHTMLString:t=>`<strong>${t}</strong>`,parseHTML:[{tag:"strong"},{tag:"b",getAttrs:t=>{const e=t.style.fontWeight;return"normal"!==e&&"400"!==e&&{}}},{tag:"span",getAttrs:t=>{const e=t.style.fontWeight;if(!e)return!1;if("bold"===e)return{};const i=Number.parseInt(e,10);return!Number.isNaN(i)&&i>=700&&{}}}],sanitize:{tags:["strong","b"]}},{type:"italic",configKey:"italic",rank:1,tag:"em",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z"/></svg>',keyBinding:"Mod-I",toHTMLString:t=>`<em>${t}</em>`,parseHTML:[{tag:"em"},{tag:"i"},{tag:"span",getAttrs:t=>"italic"===t.style.fontStyle&&{}}],sanitize:{tags:["em","i"]}},{type:"underline",configKey:"underline",rank:2,tag:"u",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z"/></svg>',keyBinding:"Mod-U",toHTMLString:t=>`<u>${t}</u>`,parseHTML:[{tag:"u"},{tag:"span",getAttrs:t=>!!t.style.textDecoration.includes("underline")&&{}}],sanitize:{tags:["u"]}}],h=class{id="text-formatting";name="Text Formatting";priority=20;config;locale;constructor(t){this.config={...p,...t}}async init(t){this.locale=await r(t,this.config.locale,g,m);const e=f.filter(t=>this.config[t.configKey]);for(const i of e)this.registerMark(t,i);this.registerKeymaps(t,e),this.registerInputRules(t),this.registerDisabledToolbarItems(t)}registerMark(s,r){const a=n(r.type),g=this.isToolbarVisible(r.configKey);if(s.registerMarkSpec({type:r.type,rank:r.rank,toDOM:()=>document.createElement(r.tag),toHTMLString:(t,e)=>r.toHTMLString(e),parseHTML:r.parseHTML,sanitize:r.sanitize}),s.registerCommand(a,()=>o(s,e(s.getState(),t(r.type)))),g){const e=this.getMarkLabel(r.type);s.registerToolbarItem({id:r.type,group:"format",icon:r.icon,label:e,tooltip:`${e} (${l(r.keyBinding)})`,command:a,isActive:e=>i(e,t(r.type))})}}registerKeymaps(t,e){const i={};for(const s of e){const e=n(s.type);i[s.keyBinding]=()=>t.executeCommand(e)}Object.keys(i).length>0&&t.registerKeymap(i)}registerInputRules(t){!1!==this.config.inputRule&&(this.config.bold&&t.registerInputRule(a("bold","**")),this.config.italic&&t.registerInputRule(a("italic","*")))}registerDisabledToolbarItems(t){if(this.config.toolbar)for(const e of f){const i=this.config[e.configKey],s=this.config.toolbar[e.configKey]??!0;!i&&s&&t.registerToolbarItem({id:e.type,group:"format",icon:e.icon,label:this.getMarkLabel(e.type),command:n(e.type),isEnabled:()=>!1})}}getMarkLabel(t){const e=`${t}Label`;return this.locale[e]}isToolbarVisible(t){return!this.config.toolbar||(this.config.toolbar[t]??!0)}};export{g as n,m as r,h as t};
2
+ //# sourceMappingURL=TextFormattingPlugin-BhRxSC8q.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextFormattingPlugin-DBVlePqj.mjs","names":[],"sources":["../../src/plugins/text-formatting/TextFormattingLocale.ts","../../src/plugins/text-formatting/TextFormattingPlugin.ts"],"sourcesContent":["/**\n * Locale interface and default English locale for the TextFormattingPlugin.\n */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\n// --- Locale Interface ---\n\nexport interface TextFormattingLocale {\n\treadonly boldLabel: string;\n\treadonly italicLabel: string;\n\treadonly underlineLabel: string;\n}\n\n// --- Default English Locale ---\n\nexport const TEXT_FORMATTING_LOCALE_EN: TextFormattingLocale = {\n\tboldLabel: 'Bold',\n\titalicLabel: 'Italic',\n\tunderlineLabel: 'Underline',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: LocaleModuleMap<TextFormattingLocale> = import.meta.glob<{\n\tdefault: TextFormattingLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadTextFormattingLocale(lang: string): Promise<TextFormattingLocale> {\n\treturn loadLocaleModule(localeModules, lang, TEXT_FORMATTING_LOCALE_EN);\n}\n","/**\n * TextFormattingPlugin: registers inline marks (bold, italic, underline)\n * with their MarkSpecs, toggle commands, keyboard shortcuts, and toolbar items.\n *\n * This plugin is data-driven — each mark type is defined declaratively and\n * all registrations (MarkSpec, command, keymap, toolbar item) are derived\n * from the same definition.\n *\n * Supports two separate config dimensions:\n * - Feature config (bold/italic/underline): controls whether the mark is\n * registered in the schema. When disabled, the keyboard shortcut does nothing.\n * - Toolbar config: controls whether the toolbar button is visible.\n * When a feature is disabled but toolbar is enabled, the button renders as disabled.\n */\n\nimport { isMarkActive, toggleMark } from '../../commands/Commands.js';\nimport type { ParseRule } from '../../model/ParseRule.js';\nimport type { SanitizeConfig } from '../../model/SanitizeConfig.js';\nimport { markType as mkType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { createMarkInputRule } from '../shared/MarkInputRule.js';\nimport { dispatchIfPresent, resolveLocale, toCommandName } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport {\n\tTEXT_FORMATTING_LOCALE_EN,\n\ttype TextFormattingLocale,\n\tloadTextFormattingLocale,\n} from './TextFormattingLocale.js';\n\n// --- Configuration ---\n\n/** Controls toolbar button visibility per mark. */\nexport interface TextFormattingToolbarConfig {\n\treadonly bold?: boolean;\n\treadonly italic?: boolean;\n\treadonly underline?: boolean;\n}\n\n/** Controls which inline marks are enabled and which toolbar buttons are shown. */\nexport interface TextFormattingConfig {\n\treadonly bold: boolean;\n\treadonly italic: boolean;\n\treadonly underline: boolean;\n\t/** Live Markdown shortcuts: `**x**` to bold, `*x*` to italic. Default true. */\n\treadonly inputRule?: boolean;\n\treadonly toolbar?: TextFormattingToolbarConfig;\n\treadonly locale?: TextFormattingLocale;\n}\n\nconst DEFAULT_CONFIG: TextFormattingConfig = {\n\tbold: true,\n\titalic: true,\n\tunderline: true,\n};\n\n// --- Mark Definitions ---\n\ninterface MarkDefinition {\n\treadonly type: string;\n\treadonly configKey: keyof Omit<TextFormattingConfig, 'toolbar' | 'locale' | 'inputRule'>;\n\treadonly rank: number;\n\treadonly tag: string;\n\treadonly icon: string;\n\treadonly keyBinding: string;\n\treadonly toHTMLString: (content: string) => string;\n\treadonly parseHTML: readonly ParseRule[];\n\treadonly sanitize: SanitizeConfig;\n}\n\nconst BOLD_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z\"/></svg>';\nconst ITALIC_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z\"/></svg>';\nconst UNDERLINE_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z\"/></svg>';\n\nconst MARK_DEFINITIONS: readonly MarkDefinition[] = [\n\t{\n\t\ttype: 'bold',\n\t\tconfigKey: 'bold',\n\t\trank: 0,\n\t\ttag: 'strong',\n\t\ticon: BOLD_ICON,\n\t\tkeyBinding: 'Mod-B',\n\t\ttoHTMLString: (content) => `<strong>${content}</strong>`,\n\t\tparseHTML: [\n\t\t\t{ tag: 'strong' },\n\t\t\t{\n\t\t\t\ttag: 'b',\n\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\tconst fw: string = el.style.fontWeight;\n\t\t\t\t\treturn fw === 'normal' || fw === '400' ? false : {};\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttag: 'span',\n\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\tconst fw: string = el.style.fontWeight;\n\t\t\t\t\tif (!fw) return false;\n\t\t\t\t\tif (fw === 'bold') return {};\n\t\t\t\t\tconst numeric: number = Number.parseInt(fw, 10);\n\t\t\t\t\treturn !Number.isNaN(numeric) && numeric >= 700 ? {} : false;\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tsanitize: { tags: ['strong', 'b'] },\n\t},\n\t{\n\t\ttype: 'italic',\n\t\tconfigKey: 'italic',\n\t\trank: 1,\n\t\ttag: 'em',\n\t\ticon: ITALIC_ICON,\n\t\tkeyBinding: 'Mod-I',\n\t\ttoHTMLString: (content) => `<em>${content}</em>`,\n\t\tparseHTML: [\n\t\t\t{ tag: 'em' },\n\t\t\t{ tag: 'i' },\n\t\t\t{\n\t\t\t\ttag: 'span',\n\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\treturn el.style.fontStyle === 'italic' ? {} : false;\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tsanitize: { tags: ['em', 'i'] },\n\t},\n\t{\n\t\ttype: 'underline',\n\t\tconfigKey: 'underline',\n\t\trank: 2,\n\t\ttag: 'u',\n\t\ticon: UNDERLINE_ICON,\n\t\tkeyBinding: 'Mod-U',\n\t\ttoHTMLString: (content) => `<u>${content}</u>`,\n\t\tparseHTML: [\n\t\t\t{ tag: 'u' },\n\t\t\t{\n\t\t\t\ttag: 'span',\n\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\treturn el.style.textDecoration.includes('underline') ? {} : false;\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tsanitize: { tags: ['u'] },\n\t},\n];\n\n// --- Plugin ---\n\nexport class TextFormattingPlugin implements Plugin {\n\treadonly id = 'text-formatting';\n\treadonly name = 'Text Formatting';\n\treadonly priority = 20;\n\n\tprivate readonly config: TextFormattingConfig;\n\tprivate locale!: TextFormattingLocale;\n\n\tconstructor(config?: Partial<TextFormattingConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tTEXT_FORMATTING_LOCALE_EN,\n\t\t\tloadTextFormattingLocale,\n\t\t);\n\n\t\tconst enabledMarks = MARK_DEFINITIONS.filter((def) => this.config[def.configKey]);\n\n\t\tfor (const def of enabledMarks) {\n\t\t\tthis.registerMark(context, def);\n\t\t}\n\n\t\tthis.registerKeymaps(context, enabledMarks);\n\t\tthis.registerInputRules(context);\n\n\t\t// Register disabled placeholder buttons for marks that are disabled\n\t\t// as features but explicitly requested in the toolbar config\n\t\tthis.registerDisabledToolbarItems(context);\n\t}\n\n\tprivate registerMark(context: PluginContext, def: MarkDefinition): void {\n\t\tconst commandName = toCommandName(def.type);\n\t\tconst toolbarVisible = this.isToolbarVisible(def.configKey);\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: def.type,\n\t\t\trank: def.rank,\n\t\t\ttoDOM() {\n\t\t\t\treturn document.createElement(def.tag);\n\t\t\t},\n\t\t\ttoHTMLString: (_mark, content) => def.toHTMLString(content),\n\t\t\tparseHTML: def.parseHTML,\n\t\t\tsanitize: def.sanitize,\n\t\t});\n\n\t\tcontext.registerCommand(commandName, () =>\n\t\t\tdispatchIfPresent(context, toggleMark(context.getState(), mkType(def.type))),\n\t\t);\n\n\t\tif (toolbarVisible) {\n\t\t\tconst label: string = this.getMarkLabel(def.type);\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: def.type,\n\t\t\t\tgroup: 'format',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel,\n\t\t\t\ttooltip: `${label} (${formatShortcut(def.keyBinding)})`,\n\t\t\t\tcommand: commandName,\n\t\t\t\tisActive: (state) => isMarkActive(state, mkType(def.type)),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext, marks: readonly MarkDefinition[]): void {\n\t\tconst keymap: Record<string, () => boolean> = {};\n\t\tfor (const def of marks) {\n\t\t\tconst commandName = toCommandName(def.type);\n\t\t\tkeymap[def.keyBinding] = () => context.executeCommand(commandName);\n\t\t}\n\t\tif (Object.keys(keymap).length > 0) {\n\t\t\tcontext.registerKeymap(keymap);\n\t\t}\n\t}\n\n\t/**\n\t * Registers live Markdown input rules: `**x**` to bold and `*x*` to italic,\n\t * each gated on its feature being enabled. Bold is registered first so it\n\t * wins over italic when both could match. Underscore variants are left to the\n\t * full parser (import/paste) to avoid intra-word `snake_case` false positives.\n\t */\n\tprivate registerInputRules(context: PluginContext): void {\n\t\tif (this.config.inputRule === false) return;\n\t\tif (this.config.bold) context.registerInputRule(createMarkInputRule('bold', '**'));\n\t\tif (this.config.italic) context.registerInputRule(createMarkInputRule('italic', '*'));\n\t}\n\n\t/**\n\t * Registers disabled toolbar buttons for marks whose feature is disabled\n\t * but whose toolbar button is explicitly requested.\n\t */\n\tprivate registerDisabledToolbarItems(context: PluginContext): void {\n\t\tif (!this.config.toolbar) return;\n\n\t\tfor (const def of MARK_DEFINITIONS) {\n\t\t\tconst featureEnabled = this.config[def.configKey];\n\t\t\tconst toolbarVisible = this.config.toolbar[def.configKey] ?? true;\n\n\t\t\tif (!featureEnabled && toolbarVisible) {\n\t\t\t\tcontext.registerToolbarItem({\n\t\t\t\t\tid: def.type,\n\t\t\t\t\tgroup: 'format',\n\t\t\t\t\ticon: def.icon,\n\t\t\t\t\tlabel: this.getMarkLabel(def.type),\n\t\t\t\t\tcommand: toCommandName(def.type),\n\t\t\t\t\tisEnabled: () => false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getMarkLabel(type: string): string {\n\t\tconst key = `${type}Label` as keyof TextFormattingLocale;\n\t\treturn this.locale[key] as string;\n\t}\n\n\t/** Checks if a toolbar button should be visible for a given mark. */\n\tprivate isToolbarVisible(\n\t\tconfigKey: keyof Omit<TextFormattingConfig, 'toolbar' | 'locale' | 'inputRule'>,\n\t): boolean {\n\t\tif (!this.config.toolbar) return true;\n\t\treturn this.config.toolbar[configKey] ?? true;\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TextFormattingPlugin-BhRxSC8q.mjs","names":[],"sources":["../../src/plugins/text-formatting/TextFormattingLocale.ts","../../src/plugins/text-formatting/TextFormattingPlugin.ts"],"sourcesContent":["/**\n * Locale interface and default English locale for the TextFormattingPlugin.\n */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\n// --- Locale Interface ---\n\nexport interface TextFormattingLocale {\n\treadonly boldLabel: string;\n\treadonly italicLabel: string;\n\treadonly underlineLabel: string;\n}\n\n// --- Default English Locale ---\n\nexport const TEXT_FORMATTING_LOCALE_EN: TextFormattingLocale = {\n\tboldLabel: 'Bold',\n\titalicLabel: 'Italic',\n\tunderlineLabel: 'Underline',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: LocaleModuleMap<TextFormattingLocale> = import.meta.glob<{\n\tdefault: TextFormattingLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadTextFormattingLocale(lang: string): Promise<TextFormattingLocale> {\n\treturn loadLocaleModule(localeModules, lang, TEXT_FORMATTING_LOCALE_EN);\n}\n","/**\n * TextFormattingPlugin: registers inline marks (bold, italic, underline)\n * with their MarkSpecs, toggle commands, keyboard shortcuts, and toolbar items.\n *\n * This plugin is data-driven — each mark type is defined declaratively and\n * all registrations (MarkSpec, command, keymap, toolbar item) are derived\n * from the same definition.\n *\n * Supports two separate config dimensions:\n * - Feature config (bold/italic/underline): controls whether the mark is\n * registered in the schema. When disabled, the keyboard shortcut does nothing.\n * - Toolbar config: controls whether the toolbar button is visible.\n * When a feature is disabled but toolbar is enabled, the button renders as disabled.\n */\n\nimport { isMarkActive, toggleMark } from '../../commands/Commands.js';\nimport type { ParseRule } from '../../model/ParseRule.js';\nimport type { SanitizeConfig } from '../../model/SanitizeConfig.js';\nimport { markType as mkType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { createMarkInputRule } from '../shared/MarkInputRule.js';\nimport { dispatchIfPresent, resolveLocale, toCommandName } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport {\n\tTEXT_FORMATTING_LOCALE_EN,\n\ttype TextFormattingLocale,\n\tloadTextFormattingLocale,\n} from './TextFormattingLocale.js';\n\n// --- Configuration ---\n\n/** Controls toolbar button visibility per mark. */\nexport interface TextFormattingToolbarConfig {\n\treadonly bold?: boolean;\n\treadonly italic?: boolean;\n\treadonly underline?: boolean;\n}\n\n/** Controls which inline marks are enabled and which toolbar buttons are shown. */\nexport interface TextFormattingConfig {\n\treadonly bold: boolean;\n\treadonly italic: boolean;\n\treadonly underline: boolean;\n\t/** Live Markdown shortcuts: `**x**` to bold, `*x*` to italic. Default true. */\n\treadonly inputRule?: boolean;\n\treadonly toolbar?: TextFormattingToolbarConfig;\n\treadonly locale?: TextFormattingLocale;\n}\n\nconst DEFAULT_CONFIG: TextFormattingConfig = {\n\tbold: true,\n\titalic: true,\n\tunderline: true,\n};\n\n// --- Mark Definitions ---\n\ninterface MarkDefinition {\n\treadonly type: string;\n\treadonly configKey: keyof Omit<TextFormattingConfig, 'toolbar' | 'locale' | 'inputRule'>;\n\treadonly rank: number;\n\treadonly tag: string;\n\treadonly icon: string;\n\treadonly keyBinding: string;\n\treadonly toHTMLString: (content: string) => string;\n\treadonly parseHTML: readonly ParseRule[];\n\treadonly sanitize: SanitizeConfig;\n}\n\nconst BOLD_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z\"/></svg>';\nconst ITALIC_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z\"/></svg>';\nconst UNDERLINE_ICON =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z\"/></svg>';\n\nconst MARK_DEFINITIONS: readonly MarkDefinition[] = [\n\t{\n\t\ttype: 'bold',\n\t\tconfigKey: 'bold',\n\t\trank: 0,\n\t\ttag: 'strong',\n\t\ticon: BOLD_ICON,\n\t\tkeyBinding: 'Mod-B',\n\t\ttoHTMLString: (content) => `<strong>${content}</strong>`,\n\t\tparseHTML: [\n\t\t\t{ tag: 'strong' },\n\t\t\t{\n\t\t\t\ttag: 'b',\n\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\tconst fw: string = el.style.fontWeight;\n\t\t\t\t\treturn fw === 'normal' || fw === '400' ? false : {};\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttag: 'span',\n\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\tconst fw: string = el.style.fontWeight;\n\t\t\t\t\tif (!fw) return false;\n\t\t\t\t\tif (fw === 'bold') return {};\n\t\t\t\t\tconst numeric: number = Number.parseInt(fw, 10);\n\t\t\t\t\treturn !Number.isNaN(numeric) && numeric >= 700 ? {} : false;\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tsanitize: { tags: ['strong', 'b'] },\n\t},\n\t{\n\t\ttype: 'italic',\n\t\tconfigKey: 'italic',\n\t\trank: 1,\n\t\ttag: 'em',\n\t\ticon: ITALIC_ICON,\n\t\tkeyBinding: 'Mod-I',\n\t\ttoHTMLString: (content) => `<em>${content}</em>`,\n\t\tparseHTML: [\n\t\t\t{ tag: 'em' },\n\t\t\t{ tag: 'i' },\n\t\t\t{\n\t\t\t\ttag: 'span',\n\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\treturn el.style.fontStyle === 'italic' ? {} : false;\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tsanitize: { tags: ['em', 'i'] },\n\t},\n\t{\n\t\ttype: 'underline',\n\t\tconfigKey: 'underline',\n\t\trank: 2,\n\t\ttag: 'u',\n\t\ticon: UNDERLINE_ICON,\n\t\tkeyBinding: 'Mod-U',\n\t\ttoHTMLString: (content) => `<u>${content}</u>`,\n\t\tparseHTML: [\n\t\t\t{ tag: 'u' },\n\t\t\t{\n\t\t\t\ttag: 'span',\n\t\t\t\tgetAttrs: (el: HTMLElement) => {\n\t\t\t\t\treturn el.style.textDecoration.includes('underline') ? {} : false;\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tsanitize: { tags: ['u'] },\n\t},\n];\n\n// --- Plugin ---\n\nexport class TextFormattingPlugin implements Plugin {\n\treadonly id = 'text-formatting';\n\treadonly name = 'Text Formatting';\n\treadonly priority = 20;\n\n\tprivate readonly config: TextFormattingConfig;\n\tprivate locale!: TextFormattingLocale;\n\n\tconstructor(config?: Partial<TextFormattingConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tTEXT_FORMATTING_LOCALE_EN,\n\t\t\tloadTextFormattingLocale,\n\t\t);\n\n\t\tconst enabledMarks = MARK_DEFINITIONS.filter((def) => this.config[def.configKey]);\n\n\t\tfor (const def of enabledMarks) {\n\t\t\tthis.registerMark(context, def);\n\t\t}\n\n\t\tthis.registerKeymaps(context, enabledMarks);\n\t\tthis.registerInputRules(context);\n\n\t\t// Register disabled placeholder buttons for marks that are disabled\n\t\t// as features but explicitly requested in the toolbar config\n\t\tthis.registerDisabledToolbarItems(context);\n\t}\n\n\tprivate registerMark(context: PluginContext, def: MarkDefinition): void {\n\t\tconst commandName = toCommandName(def.type);\n\t\tconst toolbarVisible = this.isToolbarVisible(def.configKey);\n\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: def.type,\n\t\t\trank: def.rank,\n\t\t\ttoDOM() {\n\t\t\t\treturn document.createElement(def.tag);\n\t\t\t},\n\t\t\ttoHTMLString: (_mark, content) => def.toHTMLString(content),\n\t\t\tparseHTML: def.parseHTML,\n\t\t\tsanitize: def.sanitize,\n\t\t});\n\n\t\tcontext.registerCommand(commandName, () =>\n\t\t\tdispatchIfPresent(context, toggleMark(context.getState(), mkType(def.type))),\n\t\t);\n\n\t\tif (toolbarVisible) {\n\t\t\tconst label: string = this.getMarkLabel(def.type);\n\t\t\tcontext.registerToolbarItem({\n\t\t\t\tid: def.type,\n\t\t\t\tgroup: 'format',\n\t\t\t\ticon: def.icon,\n\t\t\t\tlabel,\n\t\t\t\ttooltip: `${label} (${formatShortcut(def.keyBinding)})`,\n\t\t\t\tcommand: commandName,\n\t\t\t\tisActive: (state) => isMarkActive(state, mkType(def.type)),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate registerKeymaps(context: PluginContext, marks: readonly MarkDefinition[]): void {\n\t\tconst keymap: Record<string, () => boolean> = {};\n\t\tfor (const def of marks) {\n\t\t\tconst commandName = toCommandName(def.type);\n\t\t\tkeymap[def.keyBinding] = () => context.executeCommand(commandName);\n\t\t}\n\t\tif (Object.keys(keymap).length > 0) {\n\t\t\tcontext.registerKeymap(keymap);\n\t\t}\n\t}\n\n\t/**\n\t * Registers live Markdown input rules: `**x**` to bold and `*x*` to italic,\n\t * each gated on its feature being enabled. Bold is registered first so it\n\t * wins over italic when both could match. Underscore variants are left to the\n\t * full parser (import/paste) to avoid intra-word `snake_case` false positives.\n\t */\n\tprivate registerInputRules(context: PluginContext): void {\n\t\tif (this.config.inputRule === false) return;\n\t\tif (this.config.bold) context.registerInputRule(createMarkInputRule('bold', '**'));\n\t\tif (this.config.italic) context.registerInputRule(createMarkInputRule('italic', '*'));\n\t}\n\n\t/**\n\t * Registers disabled toolbar buttons for marks whose feature is disabled\n\t * but whose toolbar button is explicitly requested.\n\t */\n\tprivate registerDisabledToolbarItems(context: PluginContext): void {\n\t\tif (!this.config.toolbar) return;\n\n\t\tfor (const def of MARK_DEFINITIONS) {\n\t\t\tconst featureEnabled = this.config[def.configKey];\n\t\t\tconst toolbarVisible = this.config.toolbar[def.configKey] ?? true;\n\n\t\t\tif (!featureEnabled && toolbarVisible) {\n\t\t\t\tcontext.registerToolbarItem({\n\t\t\t\t\tid: def.type,\n\t\t\t\t\tgroup: 'format',\n\t\t\t\t\ticon: def.icon,\n\t\t\t\t\tlabel: this.getMarkLabel(def.type),\n\t\t\t\t\tcommand: toCommandName(def.type),\n\t\t\t\t\tisEnabled: () => false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getMarkLabel(type: string): string {\n\t\tconst key = `${type}Label` as keyof TextFormattingLocale;\n\t\treturn this.locale[key] as string;\n\t}\n\n\t/** Checks if a toolbar button should be visible for a given mark. */\n\tprivate isToolbarVisible(\n\t\tconfigKey: keyof Omit<TextFormattingConfig, 'toolbar' | 'locale' | 'inputRule'>,\n\t): boolean {\n\t\tif (!this.config.toolbar) return true;\n\t\treturn this.config.toolbar[configKey] ?? true;\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import{i as e,n as o,r as t,t as r}from"./SyntaxTokenTypes-BUCOMtL8.mjs";import{n,t as a}from"./TypedKeys-CA4bfw9O.mjs";var c="data-notectl-static";function i(e){return e.hasAttribute(c)}function d(){/* @__PURE__ */
2
+ return new Error("Cannot initialize a static print replica (data-notectl-static). Remove the marker and its shadow content to reuse the element as an editor.")}var l=96/25.4,s={DINA4:"din-a4",DINA5:"din-a5",USLetter:"us-letter",USLegal:"us-legal"};function f(e){return Math.round(e*l)}var u=new Map([[s.DINA4,{widthMm:210,heightMm:297,widthPx:f(210),heightPx:f(297)}],[s.DINA5,{widthMm:148,heightMm:210,widthPx:f(148),heightPx:f(210)}],[s.USLetter,{widthMm:215.9,heightMm:279.4,widthPx:f(215.9),heightPx:f(279.4)}],[s.USLegal,{widthMm:215.9,heightMm:355.6,widthPx:f(215.9),heightPx:f(355.6)}]]),g=new Map([[s.DINA4,"A4"],[s.DINA5,"A5"],[s.USLetter,"letter"],[s.USLegal,"legal"]]);function b(e){const o=u.get(e);if(!o)throw new Error(`Unknown paper size: ${e}`);return o}var p=48,m=56,h=24;function k(e){return Object.values(s).includes(e)}function v(e){const o=g.get(e);if(!o)throw new Error(`Unknown paper size: ${e}`);return o}var y={Light:"light",Dark:"dark",System:"system"},B={name:"light",primitives:{background:"#ffffff",foreground:"#1a1a1a",mutedForeground:"#666666",border:"#d0d0d0",borderFocus:"#4a90d9",primary:"#4a90d9",primaryForeground:"#1a5fa0",primaryMuted:"#d0e0f0",surfaceRaised:"#f8f8f8",surfaceOverlay:"#ffffff",hoverBackground:"#e8e8e8",activeBackground:"#d0e0f0",danger:"#dc2626",dangerMuted:"#fee2e2",success:"#1a8c1a",shadow:"rgba(0, 0, 0, 0.15)",focusRing:"rgba(74, 144, 217, 0.2)"},inlineCode:{background:"#edf0f5",foreground:"#334155"},codeBlock:{background:"#f8fafc",foreground:"#334155",headerBackground:"#f1f5f9",headerForeground:"#64748b",headerBorder:"#e2e8f0",syntax:{keyword:"#d73a49",string:"#032f62",comment:{color:"#6a737d",fontStyle:"italic"},number:"#005cc5",function:"#6f42c1",operator:"#d73a49",punctuation:"#24292e",boolean:"#005cc5",null:"#005cc5",property:"#005cc5",type:"#e36209",annotation:"#6f42c1",tag:"#22863a",attribute:"#6f42c1",constant:"#005cc5",regex:"#032f62"}},tooltip:{background:"#1a1a1a",foreground:"#ffffff"}},w={name:"dark",primitives:{background:"#1e1e2e",foreground:"#cdd6f4",mutedForeground:"#7f849c",border:"#45475a",borderFocus:"#89b4fa",primary:"#89b4fa",primaryForeground:"#89b4fa",primaryMuted:"rgba(137, 180, 250, 0.15)",surfaceRaised:"#313244",surfaceOverlay:"#313244",hoverBackground:"#45475a",activeBackground:"rgba(137, 180, 250, 0.15)",danger:"#f38ba8",dangerMuted:"rgba(243, 139, 168, 0.15)",success:"#a6e3a1",shadow:"rgba(0, 0, 0, 0.4)",focusRing:"rgba(137, 180, 250, 0.25)"},inlineCode:{background:"#313244",foreground:"#cdd6f4"},codeBlock:{background:"#313244",foreground:"#cdd6f4",headerBackground:"#45475a",headerForeground:"#bac2de",headerBorder:"#585b70",syntax:{keyword:"#cba6f7",string:"#a6e3a1",comment:{color:"#9399b2",fontStyle:"italic"},number:"#fab387",function:"#89b4fa",operator:"#89dceb",punctuation:"#bac2de",boolean:"#fab387",null:"#f38ba8",property:"#89b4fa",type:"#fab387",annotation:"#cba6f7",tag:"#a6e3a1",attribute:"#89b4fa",constant:"#f9e2af",regex:"#a6e3a1"}},tooltip:{background:"#585b70",foreground:"#cdd6f4"}};function x(e,o){return{name:o.name,primitives:{...e.primitives,...o.primitives},toolbar:o.toolbar?{...e.toolbar,...o.toolbar}:e.toolbar,inlineCode:o.inlineCode?{...e.inlineCode,...o.inlineCode}:e.inlineCode,codeBlock:o.codeBlock?{...e.codeBlock,...o.codeBlock,syntax:o.codeBlock?.syntax?e.codeBlock?.syntax?{...e.codeBlock.syntax,...o.codeBlock.syntax}:void 0:e.codeBlock?.syntax}:e.codeBlock,tooltip:o.tooltip?{...e.tooltip,...o.tooltip}:e.tooltip}}function M(e){if("object"==typeof e)return e;switch(e){case y.Light:return B;case y.Dark:return w;default:return B}}var S=new n("print"),$=new a("print:before"),C=new a("print:after"),F=[["primitives.background","--notectl-bg"],["primitives.foreground","--notectl-fg"],["primitives.mutedForeground","--notectl-fg-muted"],["primitives.border","--notectl-border"],["primitives.borderFocus","--notectl-border-focus"],["primitives.primary","--notectl-primary"],["primitives.primaryForeground","--notectl-primary-fg"],["primitives.primaryMuted","--notectl-primary-muted"],["primitives.surfaceRaised","--notectl-surface-raised"],["primitives.surfaceOverlay","--notectl-surface-overlay"],["primitives.hoverBackground","--notectl-hover-bg"],["primitives.activeBackground","--notectl-active-bg"],["primitives.danger","--notectl-danger"],["primitives.dangerMuted","--notectl-danger-muted"],["primitives.success","--notectl-success"],["primitives.shadow","--notectl-shadow"],["primitives.focusRing","--notectl-focus-ring"],["toolbar.background","--notectl-toolbar-bg"],["toolbar.borderColor","--notectl-toolbar-border"],["inlineCode.background","--notectl-code-bg"],["inlineCode.foreground","--notectl-code-color"],["codeBlock.background","--notectl-code-block-bg"],["codeBlock.foreground","--notectl-code-block-color"],["codeBlock.headerBackground","--notectl-code-block-header-bg"],["codeBlock.headerForeground","--notectl-code-block-header-color"],["codeBlock.headerBorder","--notectl-code-block-header-border"],["tooltip.background","--notectl-tooltip-bg"],["tooltip.foreground","--notectl-tooltip-fg"],...r.map(e=>[`codeBlock.syntax.${e}`,`--notectl-code-token-${e}`])],A=r.map(e=>[`--notectl-code-token-${e}`,"var(--notectl-code-block-color)"]),j=new Map([["--notectl-toolbar-bg","var(--notectl-surface-raised)"],["--notectl-toolbar-border","var(--notectl-border)"],["--notectl-code-bg","var(--notectl-surface-raised)"],["--notectl-code-color","var(--notectl-fg)"],["--notectl-code-block-bg","var(--notectl-surface-raised)"],["--notectl-code-block-color","var(--notectl-fg)"],["--notectl-code-block-header-bg","var(--notectl-surface-raised)"],["--notectl-code-block-header-color","var(--notectl-fg-muted)"],["--notectl-code-block-header-border","var(--notectl-border)"],["--notectl-tooltip-bg","var(--notectl-fg)"],["--notectl-tooltip-fg","var(--notectl-bg)"],...A]);function D(e,t){const r=t.split(".");let n=e;for(const o of r){if(null==n)return;if("object"!=typeof n)return;n=n[o]}return"string"==typeof n?n:"object"==typeof n&&null!==n&&"color"in n?o(n):void 0}function L(o){const n=[":host {"];for(const[e,t]of F){const r=D(o,e);if(void 0!==r)n.push(`\t${t}: ${r};`);else{const e=j.get(t);e&&n.push(`\t${t}: ${e};`)}}return o.codeBlock?.syntax&&function(o,n){for(const a of r){const r=o[a];if("object"!=typeof r)continue;const c=t(r);c&&n.push(`\t--notectl-code-token-${a}-font-style: ${c};`);const i=e(r);i&&n.push(`\t--notectl-code-token-${a}-font-weight: ${i};`)}}(o.codeBlock.syntax,n),n.push("}"),n.join("\n")}function P(e){const o=new CSSStyleSheet;return o.replaceSync(L(e)),o}export{k as _,S as a,i as b,y as c,m as d,p as f,b as g,v as h,$ as i,x as l,s as m,L as n,w as o,h as p,C as r,B as s,P as t,M as u,c as v,d as y};
3
+ //# sourceMappingURL=ThemeEngine-BUVo_zaT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemeEngine-BUVo_zaT.mjs","names":[],"sources":["../../src/plugins/print/StaticHostMarker.ts","../../src/model/PaperSize.ts","../../src/editor/theme/ThemeTokens.ts","../../src/plugins/print/PrintTypes.ts","../../src/editor/theme/ThemeEngine.ts"],"sourcesContent":["/**\n * Marker attribute for static host replicas.\n *\n * Print output replicates the editor host element (tag and attributes) so\n * host-page `::part()` rules keep matching in the print document. When that\n * markup is injected into a page where `<notectl-editor>` is registered, the\n * replica must stay static markup: upgrading it into a live editor would\n * replace the replicated shadow content with a fresh editor instance.\n *\n * The print plugin writes the marker; `NotectlEditor` honors it by refusing\n * to boot on marked hosts.\n */\nexport const STATIC_HOST_ATTRIBUTE = 'data-notectl-static';\n\n/** True when the element is a static replica that must not boot an editor. */\nexport function isStaticHostReplica(el: Element): boolean {\n\treturn el.hasAttribute(STATIC_HOST_ATTRIBUTE);\n}\n\n/** Error raised when editor lifecycle APIs are used on a static replica. */\nexport function createStaticReplicaError(): Error {\n\treturn new Error(\n\t\t'Cannot initialize a static print replica (data-notectl-static). ' +\n\t\t\t'Remove the marker and its shadow content to reuse the element as an editor.',\n\t);\n}\n","/**\n * Paper size definitions and dimension helpers.\n * Used by PaperLayoutController for WYSIWYG page layout\n * and by PrintStyleCollector for @page CSS rules.\n */\n\n/** Conversion factor: 1mm = 96/25.4 px at CSS reference pixel (96 DPI). */\nconst MM_TO_PX: number = 96 / 25.4;\n\n/** Physical dimensions of a paper size. */\nexport interface PaperDimensions {\n\treadonly widthMm: number;\n\treadonly heightMm: number;\n\treadonly widthPx: number;\n\treadonly heightPx: number;\n}\n\n/** Available paper size presets. */\nexport const PaperSize = {\n\tDINA4: 'din-a4',\n\tDINA5: 'din-a5',\n\tUSLetter: 'us-letter',\n\tUSLegal: 'us-legal',\n} as const;\nexport type PaperSize = (typeof PaperSize)[keyof typeof PaperSize];\n\n/** Rounds to nearest integer for pixel dimensions. */\nfunction mmToPx(mm: number): number {\n\treturn Math.round(mm * MM_TO_PX);\n}\n\n/** Lookup table for paper dimensions. */\nconst PAPER_DIMENSIONS: ReadonlyMap<PaperSize, PaperDimensions> = new Map<\n\tPaperSize,\n\tPaperDimensions\n>([\n\t[PaperSize.DINA4, { widthMm: 210, heightMm: 297, widthPx: mmToPx(210), heightPx: mmToPx(297) }],\n\t[PaperSize.DINA5, { widthMm: 148, heightMm: 210, widthPx: mmToPx(148), heightPx: mmToPx(210) }],\n\t[\n\t\tPaperSize.USLetter,\n\t\t{ widthMm: 215.9, heightMm: 279.4, widthPx: mmToPx(215.9), heightPx: mmToPx(279.4) },\n\t],\n\t[\n\t\tPaperSize.USLegal,\n\t\t{ widthMm: 215.9, heightMm: 355.6, widthPx: mmToPx(215.9), heightPx: mmToPx(355.6) },\n\t],\n]);\n\n/** CSS @page size keywords for each paper size. */\nconst CSS_SIZE_KEYWORDS: ReadonlyMap<PaperSize, string> = new Map<PaperSize, string>([\n\t[PaperSize.DINA4, 'A4'],\n\t[PaperSize.DINA5, 'A5'],\n\t[PaperSize.USLetter, 'letter'],\n\t[PaperSize.USLegal, 'legal'],\n]);\n\n/** Returns the physical and pixel dimensions for a paper size. */\nexport function getPaperDimensions(size: PaperSize): PaperDimensions {\n\tconst dims: PaperDimensions | undefined = PAPER_DIMENSIONS.get(size);\n\tif (!dims) {\n\t\tthrow new Error(`Unknown paper size: ${size}`);\n\t}\n\treturn dims;\n}\n\n/**\n * Document margin constants for paper mode (in px).\n * These define the content padding inside the paper surface in the editor,\n * and become @page margins in print output to ensure WYSIWYG fidelity.\n */\nexport const PAPER_MARGIN_TOP_PX: number = 48;\nexport const PAPER_MARGIN_HORIZONTAL_PX: number = 56;\nexport const PAPER_VIEWPORT_PADDING_PX: number = 24;\n\n/** Type guard: returns true if the value is a valid PaperSize string. */\nexport function isValidPaperSize(value: string): value is PaperSize {\n\treturn (Object.values(PaperSize) as string[]).includes(value);\n}\n\n/** Returns the CSS @page size keyword (e.g. 'A4', 'letter') for a paper size. */\nexport function getPaperCSSSize(size: PaperSize): string {\n\tconst keyword: string | undefined = CSS_SIZE_KEYWORDS.get(size);\n\tif (!keyword) {\n\t\tthrow new Error(`Unknown paper size: ${size}`);\n\t}\n\treturn keyword;\n}\n","/**\n * Theme token types, built-in themes, and theme creation helpers.\n */\n\nimport type { SyntaxTokenType, TokenStyleValue } from './SyntaxTokenTypes.js';\nimport { resolveTokenColor } from './SyntaxTokenTypes.js';\n\n/** Primitive color palette a theme defines. */\nexport interface ThemePrimitives {\n\treadonly background: string;\n\treadonly foreground: string;\n\treadonly mutedForeground: string;\n\treadonly border: string;\n\treadonly borderFocus: string;\n\treadonly primary: string;\n\treadonly primaryForeground: string;\n\treadonly primaryMuted: string;\n\treadonly surfaceRaised: string;\n\treadonly surfaceOverlay: string;\n\treadonly hoverBackground: string;\n\treadonly activeBackground: string;\n\treadonly danger: string;\n\treadonly dangerMuted: string;\n\treadonly success: string;\n\treadonly shadow: string;\n\treadonly focusRing: string;\n}\n\n/** Component-level toolbar overrides. */\nexport interface ThemeToolbar {\n\treadonly background: string;\n\treadonly borderColor: string;\n}\n\n/** Syntax highlighting token styles — one entry per canonical token type. */\nexport type ThemeSyntax = { readonly [K in SyntaxTokenType]: TokenStyleValue };\n\n/** Component-level code block overrides. */\nexport interface ThemeCodeBlock {\n\treadonly background: string;\n\treadonly foreground: string;\n\treadonly headerBackground: string;\n\treadonly headerForeground: string;\n\treadonly headerBorder: string;\n\treadonly syntax?: ThemeSyntax;\n}\n\n/** Component-level inline code overrides. */\nexport interface ThemeInlineCode {\n\treadonly background: string;\n\treadonly foreground: string;\n}\n\n/** Component-level tooltip overrides. */\nexport interface ThemeTooltip {\n\treadonly background: string;\n\treadonly foreground: string;\n}\n\n/** Full theme definition. */\nexport interface Theme {\n\treadonly name: string;\n\treadonly primitives: ThemePrimitives;\n\treadonly toolbar?: Partial<ThemeToolbar>;\n\treadonly inlineCode?: Partial<ThemeInlineCode>;\n\treadonly codeBlock?: Partial<ThemeCodeBlock>;\n\treadonly tooltip?: Partial<ThemeTooltip>;\n}\n\n/** Partial custom theme — deeply partial for creating overrides. */\nexport interface PartialTheme {\n\treadonly name: string;\n\treadonly primitives?: Partial<ThemePrimitives>;\n\treadonly toolbar?: Partial<ThemeToolbar>;\n\treadonly inlineCode?: Partial<ThemeInlineCode>;\n\treadonly codeBlock?: Partial<Omit<ThemeCodeBlock, 'syntax'>> & {\n\t\treadonly syntax?: Partial<ThemeSyntax>;\n\t};\n\treadonly tooltip?: Partial<ThemeTooltip>;\n}\n\n/** Built-in theme presets. */\nexport const ThemePreset = {\n\tLight: 'light',\n\tDark: 'dark',\n\tSystem: 'system',\n} as const;\nexport type ThemePreset = (typeof ThemePreset)[keyof typeof ThemePreset];\n\n/** Built-in light theme. */\nexport const LIGHT_THEME: Theme = {\n\tname: 'light',\n\tprimitives: {\n\t\tbackground: '#ffffff',\n\t\tforeground: '#1a1a1a',\n\t\tmutedForeground: '#666666',\n\t\tborder: '#d0d0d0',\n\t\tborderFocus: '#4a90d9',\n\t\tprimary: '#4a90d9',\n\t\tprimaryForeground: '#1a5fa0',\n\t\tprimaryMuted: '#d0e0f0',\n\t\tsurfaceRaised: '#f8f8f8',\n\t\tsurfaceOverlay: '#ffffff',\n\t\thoverBackground: '#e8e8e8',\n\t\tactiveBackground: '#d0e0f0',\n\t\tdanger: '#dc2626',\n\t\tdangerMuted: '#fee2e2',\n\t\tsuccess: '#1a8c1a',\n\t\tshadow: 'rgba(0, 0, 0, 0.15)',\n\t\tfocusRing: 'rgba(74, 144, 217, 0.2)',\n\t},\n\tinlineCode: {\n\t\tbackground: '#edf0f5',\n\t\tforeground: '#334155',\n\t},\n\tcodeBlock: {\n\t\tbackground: '#f8fafc',\n\t\tforeground: '#334155',\n\t\theaderBackground: '#f1f5f9',\n\t\theaderForeground: '#64748b',\n\t\theaderBorder: '#e2e8f0',\n\t\tsyntax: {\n\t\t\tkeyword: '#d73a49',\n\t\t\tstring: '#032f62',\n\t\t\tcomment: { color: '#6a737d', fontStyle: 'italic' },\n\t\t\tnumber: '#005cc5',\n\t\t\tfunction: '#6f42c1',\n\t\t\toperator: '#d73a49',\n\t\t\tpunctuation: '#24292e',\n\t\t\tboolean: '#005cc5',\n\t\t\tnull: '#005cc5',\n\t\t\tproperty: '#005cc5',\n\t\t\ttype: '#e36209',\n\t\t\tannotation: '#6f42c1',\n\t\t\ttag: '#22863a',\n\t\t\tattribute: '#6f42c1',\n\t\t\tconstant: '#005cc5',\n\t\t\tregex: '#032f62',\n\t\t},\n\t},\n\ttooltip: {\n\t\tbackground: '#1a1a1a',\n\t\tforeground: '#ffffff',\n\t},\n};\n\n/** Built-in dark theme. */\nexport const DARK_THEME: Theme = {\n\tname: 'dark',\n\tprimitives: {\n\t\tbackground: '#1e1e2e',\n\t\tforeground: '#cdd6f4',\n\t\tmutedForeground: '#7f849c',\n\t\tborder: '#45475a',\n\t\tborderFocus: '#89b4fa',\n\t\tprimary: '#89b4fa',\n\t\tprimaryForeground: '#89b4fa',\n\t\tprimaryMuted: 'rgba(137, 180, 250, 0.15)',\n\t\tsurfaceRaised: '#313244',\n\t\tsurfaceOverlay: '#313244',\n\t\thoverBackground: '#45475a',\n\t\tactiveBackground: 'rgba(137, 180, 250, 0.15)',\n\t\tdanger: '#f38ba8',\n\t\tdangerMuted: 'rgba(243, 139, 168, 0.15)',\n\t\tsuccess: '#a6e3a1',\n\t\tshadow: 'rgba(0, 0, 0, 0.4)',\n\t\tfocusRing: 'rgba(137, 180, 250, 0.25)',\n\t},\n\tinlineCode: {\n\t\tbackground: '#313244',\n\t\tforeground: '#cdd6f4',\n\t},\n\tcodeBlock: {\n\t\tbackground: '#313244',\n\t\tforeground: '#cdd6f4',\n\t\theaderBackground: '#45475a',\n\t\theaderForeground: '#bac2de',\n\t\theaderBorder: '#585b70',\n\t\tsyntax: {\n\t\t\tkeyword: '#cba6f7',\n\t\t\tstring: '#a6e3a1',\n\t\t\tcomment: { color: '#9399b2', fontStyle: 'italic' },\n\t\t\tnumber: '#fab387',\n\t\t\tfunction: '#89b4fa',\n\t\t\toperator: '#89dceb',\n\t\t\tpunctuation: '#bac2de',\n\t\t\tboolean: '#fab387',\n\t\t\tnull: '#f38ba8',\n\t\t\tproperty: '#89b4fa',\n\t\t\ttype: '#fab387',\n\t\t\tannotation: '#cba6f7',\n\t\t\ttag: '#a6e3a1',\n\t\t\tattribute: '#89b4fa',\n\t\t\tconstant: '#f9e2af',\n\t\t\tregex: '#a6e3a1',\n\t\t},\n\t},\n\ttooltip: {\n\t\tbackground: '#585b70',\n\t\tforeground: '#cdd6f4',\n\t},\n};\n\n/** Creates a custom theme by extending a base theme with partial overrides. */\nexport function createTheme(base: Theme, overrides: PartialTheme): Theme {\n\tconst mergeSyntax = (): ThemeSyntax | undefined => {\n\t\tif (!overrides.codeBlock?.syntax) return base.codeBlock?.syntax;\n\t\tif (!base.codeBlock?.syntax) return undefined;\n\t\treturn { ...base.codeBlock.syntax, ...overrides.codeBlock.syntax } as ThemeSyntax;\n\t};\n\n\treturn {\n\t\tname: overrides.name,\n\t\tprimitives: { ...base.primitives, ...overrides.primitives },\n\t\ttoolbar: overrides.toolbar ? { ...base.toolbar, ...overrides.toolbar } : base.toolbar,\n\t\tinlineCode: overrides.inlineCode\n\t\t\t? { ...base.inlineCode, ...overrides.inlineCode }\n\t\t\t: base.inlineCode,\n\t\tcodeBlock: overrides.codeBlock\n\t\t\t? {\n\t\t\t\t\t...base.codeBlock,\n\t\t\t\t\t...overrides.codeBlock,\n\t\t\t\t\tsyntax: mergeSyntax(),\n\t\t\t\t}\n\t\t\t: base.codeBlock,\n\t\ttooltip: overrides.tooltip ? { ...base.tooltip, ...overrides.tooltip } : base.tooltip,\n\t};\n}\n\n// Re-export for convenience — avoids extra imports in consumer code.\nexport { resolveTokenColor };\n\n/** Resolves a ThemePreset string or Theme object to a full Theme. */\nexport function resolveTheme(theme: ThemePreset | Theme): Theme {\n\tif (typeof theme === 'object') return theme;\n\tswitch (theme) {\n\t\tcase ThemePreset.Light:\n\t\t\treturn LIGHT_THEME;\n\t\tcase ThemePreset.Dark:\n\t\t\treturn DARK_THEME;\n\t\tcase ThemePreset.System:\n\t\t\t// System is resolved externally via matchMedia; default to light.\n\t\t\treturn LIGHT_THEME;\n\t\tdefault:\n\t\t\treturn LIGHT_THEME;\n\t}\n}\n","/**\n * Type definitions, service keys, and event keys for the PrintPlugin.\n */\n\nimport type { PaperSize } from '../../model/PaperSize.js';\nimport type { NodeTypeName } from '../../model/TypeBrands.js';\nimport { EventKey, ServiceKey } from '../Plugin.js';\n\n// --- Print Options ---\n\nexport interface PrintOptions {\n\t/** Page title shown in the browser print header. */\n\treadonly title?: string;\n\n\t/** Additional CSS appended to the print stylesheet. */\n\treadonly customCSS?: string;\n\n\t/**\n\t * Header HTML inserted once at the top of the print document.\n\t * For repeating per-page headers, use toHTML() with server-side PDF generation.\n\t */\n\treadonly header?: string | (() => string);\n\n\t/**\n\t * Footer HTML inserted once at the bottom of the print document.\n\t * For repeating per-page footers, use toHTML() with server-side PDF generation.\n\t */\n\treadonly footer?: string | (() => string);\n\n\t/** Page margins as CSS value (e.g. '2cm'). */\n\treadonly margin?: string;\n\n\t/** Force page break before these block types. */\n\treadonly pageBreakBefore?: readonly NodeTypeName[];\n\n\t/** Exclude these block types from print output. */\n\treadonly excludeBlockTypes?: readonly NodeTypeName[];\n\n\t/**\n\t * Whether to preserve background colors and images in print output.\n\t * Defaults to `true` (WYSIWYG). Set to `false` to let the browser strip\n\t * backgrounds (e.g. to save ink).\n\t */\n\treadonly printBackground?: boolean;\n\n\t/**\n\t * Force light theme tokens in print output for readability on paper.\n\t * Defaults to `true`. Set to `false` to print with the current editor theme.\n\t */\n\treadonly forceLightTheme?: boolean;\n\n\t/** Page orientation. */\n\treadonly orientation?: 'portrait' | 'landscape';\n\n\t/** Paper size for @page CSS rule. When set, overrides the default A4 page size. */\n\treadonly paperSize?: PaperSize;\n}\n\n// --- Plugin Configuration ---\n\nexport interface PrintPluginConfig {\n\t/** Default options applied to every print() call. */\n\treadonly defaults?: PrintOptions;\n\n\t/** Keyboard shortcut (default: 'Mod-P'). */\n\treadonly keyBinding?: string;\n\n\t/** Show toolbar button (default: true). */\n\treadonly showToolbarItem?: boolean;\n\n\t/** Locale override for user-facing strings. */\n\treadonly locale?: import('./PrintLocale.js').PrintLocale;\n}\n\n// --- Service Interface ---\n\nexport interface PrintService {\n\t/** Prints the editor content with optional configuration. */\n\tprint(options?: PrintOptions): void;\n\n\t/** Generates print-ready HTML as a complete document string. */\n\ttoHTML(options?: PrintOptions): string;\n}\n\n// --- Service & Event Keys ---\n\nexport const PRINT_SERVICE_KEY: ServiceKey<PrintService> = new ServiceKey<PrintService>('print');\n\nexport const BEFORE_PRINT: EventKey<BeforePrintEvent> = new EventKey<BeforePrintEvent>(\n\t'print:before',\n);\n\nexport const AFTER_PRINT: EventKey<AfterPrintEvent> = new EventKey<AfterPrintEvent>('print:after');\n\n// --- Event Payloads ---\n\nexport interface BeforePrintEvent {\n\t/** Options can be mutated — EventBus passes by reference. */\n\toptions: PrintOptions;\n\t/** Set to true to cancel the print. */\n\tcancelled: boolean;\n}\n\nexport interface AfterPrintEvent {\n\t/** The generated HTML (read-only). */\n\treadonly html: string;\n}\n","/**\n * Theme engine — converts a Theme object into CSS custom properties.\n */\n\nimport {\n\tSYNTAX_TOKEN_TYPES,\n\tresolveTokenColor,\n\tresolveTokenFontStyle,\n\tresolveTokenFontWeight,\n} from './SyntaxTokenTypes.js';\nimport type { TokenStyleValue } from './SyntaxTokenTypes.js';\nimport type { Theme, ThemeSyntax } from './ThemeTokens.js';\n\n// --- Static entries (non-syntax) ---\n\nconst STATIC_ENTRIES: ReadonlyArray<readonly [string, string]> = [\n\t// Primitives\n\t['primitives.background', '--notectl-bg'],\n\t['primitives.foreground', '--notectl-fg'],\n\t['primitives.mutedForeground', '--notectl-fg-muted'],\n\t['primitives.border', '--notectl-border'],\n\t['primitives.borderFocus', '--notectl-border-focus'],\n\t['primitives.primary', '--notectl-primary'],\n\t['primitives.primaryForeground', '--notectl-primary-fg'],\n\t['primitives.primaryMuted', '--notectl-primary-muted'],\n\t['primitives.surfaceRaised', '--notectl-surface-raised'],\n\t['primitives.surfaceOverlay', '--notectl-surface-overlay'],\n\t['primitives.hoverBackground', '--notectl-hover-bg'],\n\t['primitives.activeBackground', '--notectl-active-bg'],\n\t['primitives.danger', '--notectl-danger'],\n\t['primitives.dangerMuted', '--notectl-danger-muted'],\n\t['primitives.success', '--notectl-success'],\n\t['primitives.shadow', '--notectl-shadow'],\n\t['primitives.focusRing', '--notectl-focus-ring'],\n\t// Component: toolbar\n\t['toolbar.background', '--notectl-toolbar-bg'],\n\t['toolbar.borderColor', '--notectl-toolbar-border'],\n\t// Component: inlineCode\n\t['inlineCode.background', '--notectl-code-bg'],\n\t['inlineCode.foreground', '--notectl-code-color'],\n\t// Component: codeBlock (non-syntax)\n\t['codeBlock.background', '--notectl-code-block-bg'],\n\t['codeBlock.foreground', '--notectl-code-block-color'],\n\t['codeBlock.headerBackground', '--notectl-code-block-header-bg'],\n\t['codeBlock.headerForeground', '--notectl-code-block-header-color'],\n\t['codeBlock.headerBorder', '--notectl-code-block-header-border'],\n\t// Component: tooltip\n\t['tooltip.background', '--notectl-tooltip-bg'],\n\t['tooltip.foreground', '--notectl-tooltip-fg'],\n];\n\n// --- Generated syntax variable map (derived from SYNTAX_TOKEN_TYPES) ---\n\nconst SYNTAX_VARIABLE_MAP: ReadonlyArray<readonly [string, string]> = SYNTAX_TOKEN_TYPES.map(\n\t(type) => [`codeBlock.syntax.${type}`, `--notectl-code-token-${type}`] as const,\n);\n\n/** Full variable map: static entries + syntax entries. */\nconst VARIABLE_MAP: ReadonlyArray<readonly [string, string]> = [\n\t...STATIC_ENTRIES,\n\t...SYNTAX_VARIABLE_MAP,\n];\n\n// --- Static fallbacks (non-syntax) ---\n\nconst STATIC_FALLBACKS: ReadonlyArray<readonly [string, string]> = [\n\t['--notectl-toolbar-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-toolbar-border', 'var(--notectl-border)'],\n\t['--notectl-code-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-code-color', 'var(--notectl-fg)'],\n\t['--notectl-code-block-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-code-block-color', 'var(--notectl-fg)'],\n\t['--notectl-code-block-header-bg', 'var(--notectl-surface-raised)'],\n\t['--notectl-code-block-header-color', 'var(--notectl-fg-muted)'],\n\t['--notectl-code-block-header-border', 'var(--notectl-border)'],\n\t['--notectl-tooltip-bg', 'var(--notectl-fg)'],\n\t['--notectl-tooltip-fg', 'var(--notectl-bg)'],\n];\n\n// --- Generated syntax fallbacks (derived from SYNTAX_TOKEN_TYPES) ---\n\nconst SYNTAX_FALLBACKS: ReadonlyArray<readonly [string, string]> = SYNTAX_TOKEN_TYPES.map(\n\t(type) => [`--notectl-code-token-${type}`, 'var(--notectl-code-block-color)'] as const,\n);\n\n/** Fallbacks for component tokens when not explicitly set. */\nconst COMPONENT_FALLBACKS: ReadonlyMap<string, string> = new Map([\n\t...STATIC_FALLBACKS,\n\t...SYNTAX_FALLBACKS,\n]);\n\n/** Resolves a dotted path like 'primitives.background' from a Theme. */\nfunction resolvePath(theme: Theme, path: string): string | undefined {\n\tconst parts: string[] = path.split('.');\n\tlet current: unknown = theme;\n\tfor (const part of parts) {\n\t\tif (current === undefined || current === null) return undefined;\n\t\tif (typeof current !== 'object') return undefined;\n\t\tcurrent = (current as Record<string, unknown>)[part];\n\t}\n\tif (typeof current === 'string') return current;\n\tif (typeof current === 'object' && current !== null && 'color' in current) {\n\t\treturn resolveTokenColor(current as TokenStyleValue);\n\t}\n\treturn undefined;\n}\n\n/** Emits font-style/font-weight CSS vars for syntax tokens that use TokenStyle objects. */\nfunction emitTokenStyleVars(syntax: ThemeSyntax, lines: string[]): void {\n\tfor (const type of SYNTAX_TOKEN_TYPES) {\n\t\tconst value: TokenStyleValue = syntax[type];\n\t\tif (typeof value !== 'object') continue;\n\n\t\tconst fontStyle: string | undefined = resolveTokenFontStyle(value);\n\t\tif (fontStyle) {\n\t\t\tlines.push(`\\t--notectl-code-token-${type}-font-style: ${fontStyle};`);\n\t\t}\n\t\tconst fontWeight: string | undefined = resolveTokenFontWeight(value);\n\t\tif (fontWeight) {\n\t\t\tlines.push(`\\t--notectl-code-token-${type}-font-weight: ${fontWeight};`);\n\t\t}\n\t}\n}\n\n/** Generates CSS text with all theme custom properties on :host. */\nexport function generateThemeCSS(theme: Theme): string {\n\tconst lines: string[] = [':host {'];\n\n\tfor (const [path, cssVar] of VARIABLE_MAP) {\n\t\tconst value: string | undefined = resolvePath(theme, path);\n\t\tif (value !== undefined) {\n\t\t\tlines.push(`\\t${cssVar}: ${value};`);\n\t\t} else {\n\t\t\tconst fallback: string | undefined = COMPONENT_FALLBACKS.get(cssVar);\n\t\t\tif (fallback) {\n\t\t\t\tlines.push(`\\t${cssVar}: ${fallback};`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Emit font-style / font-weight vars for TokenStyle entries\n\tif (theme.codeBlock?.syntax) {\n\t\temitTokenStyleVars(theme.codeBlock.syntax, lines);\n\t}\n\n\tlines.push('}');\n\treturn lines.join('\\n');\n}\n\n/** Creates a CSSStyleSheet populated with theme CSS variables. */\nexport function createThemeStyleSheet(theme: Theme): CSSStyleSheet {\n\tconst sheet: CSSStyleSheet = new CSSStyleSheet();\n\tsheet.replaceSync(generateThemeCSS(theme));\n\treturn sheet;\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{n as t}from"./TypedKeys-CA4bfw9O.mjs";import{c as e,o}from"./PluginHelpers-KDuTlmXm.mjs";import{c as n,s as r}from"./StyleRuntime-DW6omotc.mjs";import{i}from"./Platform-ByobkiCc.mjs";import{n as l,r as s,t as a}from"./KeyboardNav-D0my3wuy.mjs";import{i as c,r as d,t as p}from"./PopupPositioning-BFh6Ed1D.mjs";import{n as u,t as h}from"./PopupManager-Cj86uDEB.mjs";var b=class{_toolbarItems=/* @__PURE__ */new Map;_toolbarItemPluginMap=/* @__PURE__ */new Map;registerToolbarItem(t,e){if(this._toolbarItems.has(t.id))throw new Error(`ToolbarItem with id "${t.id}" is already registered.`);if(this._toolbarItems.set(t.id,t),e){const o=this._toolbarItemPluginMap.get(e)??[];o.push(t.id),this._toolbarItemPluginMap.set(e,o)}}getToolbarItemsByPlugin(t){const e=this._toolbarItemPluginMap.get(t)??[],o=[];for(const n of e){const t=this._toolbarItems.get(n);t&&o.push(t)}return o}getToolbarItem(t){return this._toolbarItems.get(t)}getToolbarItems(){return[...this._toolbarItems.values()]}removeToolbarItem(t){this._toolbarItems.delete(t);for(const[e,o]of this._toolbarItemPluginMap){const n=o.indexOf(t);if(-1!==n){o.splice(n,1),0===o.length&&this._toolbarItemPluginMap.delete(e);break}}}clear(){this._toolbarItems.clear(),this._toolbarItemPluginMap.clear()}};function m(t){for(let e=0;e<t.length;e++)if(!t[e]?.disabled)return e;return-1}var f={formattingOptionsAria:"Formatting options",moreToolsAria:"More tools",gridPickerLabel:(t,e)=>`${t} x ${e}`},v=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-C9lO1jsY.mjs"),"./locales/de.ts":()=>import("./de-BXQBXxFJ.mjs"),"./locales/es.ts":()=>import("./es-CXuMz87y.mjs"),"./locales/fr.ts":()=>import("./fr-fshsDD66.mjs"),"./locales/hi.ts":()=>import("./hi-BOMkDPqC.mjs"),"./locales/pt.ts":()=>import("./pt-Cc4zysaT.mjs"),"./locales/ru.ts":()=>import("./ru-CwyPz2Va.mjs"),"./locales/zh.ts":()=>import("./zh-DgSmvLyw.mjs")});async function g(t){return e(v,t,f)}var w={BurgerMenu:"burger-menu",Flow:"flow",None:"none"},x="notectl-toolbar-btn--overflow-hidden",y="notectl-toolbar-separator--overflow-hidden",A="notectl-toolbar-group--overflow-hidden",E="notectl-toolbar-group",_="notectl-toolbar-separator",k=class{toolbar;context;onOverflowChange;onItemActivated;getActiveElement;ariaLabel;popupManager;entries=[];overflowButton=null;overflowDropdown=null;overflowHandle=null;overflowEntries=[];resizeObserver=null;closeHandler=null;closeHandlerTimer=null;closeHandlerAttached=!1;constructor(t){this.toolbar=t.toolbar,this.ariaLabel=t.ariaLabel,this.context=t.context,this.onOverflowChange=t.onOverflowChange,this.onItemActivated=t.onItemActivated,this.getActiveElement=t.getActiveElement,this.popupManager=t.popupManager??null,this.resizeObserver=new ResizeObserver(()=>this.recalculate()),this.resizeObserver.observe(this.toolbar)}update(t){this.entries=t.map(t=>({element:t.element,item:t.item})),this.recalculate()}recalculate(){if(0===this.entries.length)return;this.closeDropdown(),this.resetVisibility(),this.ensureOverflowButton(),this.setOverflowButtonVisible(!1);const t=this.measureAvailableWidth(),e=Array.from(this.toolbar.children),o=this.measureChildWidths(e),n=t-34-2;let r=0,i=!1;const l=[];for(const s of e){if(s===this.overflowButton)continue;if(s.classList.contains(_)){const t=(o.get(s)??0)+2;i||r+t>n?(i=!0,s.classList.add(y)):r+=t;continue}if(s.classList.contains(E)){const t=(o.get(s)??0)+2,e=this.entriesInside(s);i||r+t>n?(i=!0,this.hideGroup(s,e,l)):r+=t;continue}const t=this.entries.find(t=>t.element===s);if(!t)continue;const e=(o.get(s)??0)+2;i||r+e>n?(i=!0,t.element.classList.add(x),l.push(t)):r+=e}this.overflowEntries=l,this.hideTrailingSeparators(),this.setOverflowButtonVisible(l.length>0),this.notifyChange()}hideGroup(t,e,o){t.classList.add(A);for(const n of e)n.element.classList.add(x),o.push(n)}entriesInside(t){const e=[];for(const o of this.entries)t.contains(o.element)&&e.push(o);return e}updateItemStates(t){if(!this.overflowDropdown)return;const e=Array.from(this.overflowDropdown.querySelectorAll(".notectl-dropdown__item"));for(const o of e){const e=o.getAttribute("data-toolbar-item"),n=this.overflowEntries.find(t=>t.item.id===e);if(!n)continue;const r=n.item.isActive?.(t)??!1,i=n.item.isEnabled?.(t)??!0;if(o.classList.toggle("notectl-dropdown__item--active",r),o.disabled=!i,"combobox"===n.item.popupType){const e=o.querySelector(".notectl-dropdown__item-label");e&&(e.textContent=n.item.getLabel(t))}if(n.item.getIcon){const e=n.item.getIcon(t),r=o.querySelector(".notectl-dropdown__item-icon");r&&r.innerHTML!==e&&(r.innerHTML=e)}}}destroy(){this.resizeObserver?.disconnect(),this.resizeObserver=null,this.closeDropdown(),this.overflowButton?.remove(),this.overflowButton=null,this.entries=[],this.overflowEntries=[]}measureChildWidths(t){const e=/* @__PURE__ */new Map;for(const o of t)o!==this.overflowButton&&e.set(o,o.offsetWidth);return e}measureAvailableWidth(){const t=getComputedStyle(this.toolbar),e=Number.parseFloat(t.paddingLeft)||0,o=Number.parseFloat(t.paddingRight)||0;return this.toolbar.clientWidth-e-o}resetVisibility(){for(const o of this.entries)o.element.classList.remove(x);const t=Array.from(this.toolbar.querySelectorAll(`.${_}`));for(const o of t)o.classList.remove(y);const e=Array.from(this.toolbar.querySelectorAll(`.${E}`));for(const o of e)o.classList.remove(A)}setOverflowButtonVisible(t){this.overflowButton&&(this.overflowButton.classList.toggle("notectl-toolbar-overflow-btn--hidden",!t),t||this.overflowButton.removeAttribute("tabindex"))}ensureOverflowButton(){if(this.overflowButton)return;const t=document.createElement("button");t.type="button",t.className="notectl-toolbar-overflow-btn",t.setAttribute("aria-label",this.ariaLabel),t.setAttribute("aria-haspopup","true"),t.setAttribute("aria-expanded","false"),t.setAttribute("part","toolbar-button toolbar-overflow-button"),t.innerHTML='<svg viewBox="0 0 16 16" width="16" height="16"><circle cx="3" cy="8" r="1.5" fill="currentColor"/><circle cx="8" cy="8" r="1.5" fill="currentColor"/><circle cx="13" cy="8" r="1.5" fill="currentColor"/></svg>',t.addEventListener("mousedown",t=>{t.preventDefault(),this.toggleDropdown()}),this.toolbar.appendChild(t),this.overflowButton=t}toggleDropdown(){this.overflowDropdown?this.closeDropdown():this.openDropdown()}openDropdown(){if(!this.overflowButton||0===this.overflowEntries.length)return;const t=document.createElement("div");t.className="notectl-toolbar-popup notectl-dropdown",t.setAttribute("role","menu"),this.renderDropdownItems(t,this.context.getState()),this.popupManager?(this.overflowHandle=this.popupManager.open({anchor:this.overflowButton,className:"notectl-toolbar-popup notectl-dropdown",ariaRole:"menu",position:"below-end",referenceNode:this.overflowButton,restoreFocusTo:this.overflowButton,onClose:()=>{this.overflowHandle=null,this.overflowDropdown=null,this.overflowButton&&this.overflowButton.setAttribute("aria-expanded","false")},content:t=>{this.renderDropdownItems(t,this.context.getState()),this.overflowDropdown=t,t.addEventListener("keydown",t=>this.handleDropdownKeydown(t))}}),this.overflowButton.setAttribute("aria-expanded","true")):(this.positionDropdown(t),p(t,this.overflowButton),this.overflowDropdown=t,this.overflowButton.setAttribute("aria-expanded","true"),requestAnimationFrame(()=>{t.querySelector('[role="menuitem"]')?.focus()}),t.addEventListener("keydown",t=>this.handleDropdownKeydown(t)),this.registerCloseHandler())}renderDropdownItems(t,e){let o=null;for(const n of this.overflowEntries){if(null!==o&&n.item.group!==o){const e=document.createElement("div");e.className="notectl-dropdown__separator",e.setAttribute("role","separator"),t.appendChild(e)}o=n.item.group;const r=document.createElement("button");r.type="button",r.className="notectl-dropdown__item",r.setAttribute("role","menuitem"),r.setAttribute("tabindex","-1"),r.setAttribute("data-toolbar-item",n.item.id);const i=document.createElement("span");i.className="notectl-dropdown__item-icon","combobox"!==n.item.popupType&&(i.innerHTML=n.item.icon),r.appendChild(i);const l=document.createElement("span");l.className="notectl-dropdown__item-label",l.textContent="combobox"===n.item.popupType?n.item.getLabel(e):n.item.tooltip??n.item.label,r.appendChild(l),r.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation(),this.activateOverflowItem(n)}),t.appendChild(r)}}positionDropdown(t){if(!this.overflowButton)return;const e=this.overflowButton.getBoundingClientRect(),o=i(this.toolbar);c(t,e,{position:o?"below-start":"below-end",isRtl:o})}registerCloseHandler(){this.closeHandler=t=>{const e=t.composedPath();this.overflowDropdown&&!e.includes(this.overflowDropdown)&&this.overflowButton&&!e.includes(this.overflowButton)&&this.closeDropdown()},this.closeHandlerTimer=setTimeout(()=>{this.closeHandlerTimer=null,this.closeHandler&&this.overflowDropdown&&(document.addEventListener("mousedown",this.closeHandler),this.closeHandlerAttached=!0)},0)}closeDropdown(){if(this.overflowHandle){const t=this.overflowHandle;return this.overflowHandle=null,this.overflowDropdown=null,t.close(),void(this.overflowButton&&this.overflowButton.setAttribute("aria-expanded","false"))}this.overflowDropdown&&(this.overflowDropdown.remove(),this.overflowDropdown=null),this.overflowButton&&this.overflowButton.setAttribute("aria-expanded","false"),this.closeHandler&&(null!==this.closeHandlerTimer&&(clearTimeout(this.closeHandlerTimer),this.closeHandlerTimer=null),this.closeHandlerAttached&&(document.removeEventListener("mousedown",this.closeHandler),this.closeHandlerAttached=!1),this.closeHandler=null)}activateOverflowItem(t){this.closeDropdown(),t.item.popupType&&this.overflowButton?this.onItemActivated(this.overflowButton,t.item):this.context.executeCommand(t.item.command)}handleDropdownKeydown(t){if(!this.overflowDropdown)return;if("Escape"===t.key||"Tab"===t.key)return t.preventDefault(),t.stopPropagation(),this.closeDropdown(),void this.overflowButton?.focus();const e=Array.from(this.overflowDropdown.querySelectorAll('[role="menuitem"]')),o=e.indexOf(this.getActiveElement());switch(t.key){case"ArrowDown":t.preventDefault(),e[l(e,o,1)]?.focus();break;case"ArrowUp":t.preventDefault(),e[l(e,o,-1)]?.focus();break;case"Enter":case" ":{t.preventDefault();const n=e[o];if(!n)break;const r=n.getAttribute("data-toolbar-item"),i=this.overflowEntries.find(t=>t.item.id===r);i&&this.activateOverflowItem(i);break}}}hideTrailingSeparators(){const t=Array.from(this.toolbar.children);for(let e=t.length-1;e>=0;e--){const o=t[e];if(!o||o===this.overflowButton)continue;if(o.classList.contains(_)){o.classList.contains(y)||o.classList.add(y);continue}const n=o.classList.contains(E)&&o.classList.contains(A),r=o.classList.contains("notectl-toolbar-btn")&&o.classList.contains(x);if(!n&&!r)break}}notifyChange(){const t=this.entries.filter(t=>!t.element.classList.contains(x)).map(t=>t.element);this.onOverflowChange(t,this.overflowEntries.length>0?this.overflowButton:null)}};function C(t,e,o){const n=t.querySelectorAll(".notectl-grid-picker__cell");for(const r of n){const t=Number(r.getAttribute("data-row")),n=Number(r.getAttribute("data-col"));r.classList.toggle("notectl-grid-picker__cell--highlighted",t<=e&&n<=o)}}function B(){const t=document.createElement("span");return t.className="notectl-toolbar-separator",t.setAttribute("role","separator"),t.setAttribute("part","toolbar-divider"),t}var L=class{activePopup=null;activePopupButton=null;activeHandle=null;getActiveElement;locale;popupManager=null;constructor(t,e=f){this.getActiveElement=t,this.locale=e}setPopupManager(t){this.popupManager=t}isOpen(){return null!==this.activePopup}toggle(t,e,o){this.activePopup?this.close():this.openViaManager(t,e,o)}close(){if(this.activeHandle){const t=this.activeHandle;return this.activeHandle=null,this.clearButtonState(),void t.close()}this.clearButtonState(),this.activePopup&&(this.activePopup.remove(),this.activePopup=null)}closeAndRestoreFocus(){const t=this.activePopupButton;this.close(),t?.focus()}destroy(){this.close()}openViaManager(t,e,o){this.popupManager&&(this.activePopupButton=t,t.classList.add("notectl-toolbar-btn--popup-open"),t.setAttribute("aria-expanded","true"),this.activeHandle=this.popupManager.open({anchor:t,className:"notectl-toolbar-popup",referenceNode:t,restoreFocusTo:t,position:"below-start",onClose:()=>{this.activeHandle=null,this.clearButtonState(),this.activePopup=null},content:(t,n)=>{this.activePopup=t,this.renderPopupContent(t,e,o,n),t.addEventListener("keydown",t=>this.handlePopupKeydown(t))}}))}renderPopupContent(t,e,o,n){const i=()=>{n({restoreFocusTo:null}),o.getContainer().focus()};switch(e.popupType){case"gridPicker":!function(t,e,o,n=f){t.className+=" notectl-grid-picker";const i=document.createElement("div");i.className="notectl-grid-picker__grid",i.setAttribute("role","grid"),r(i,{display:"grid",gridTemplateColumns:`repeat(${e.maxCols}, 1fr)`,gap:"2px",padding:"8px"});const l=document.createElement("div");l.className="notectl-grid-picker__label",l.textContent=n.gridPickerLabel(1,1),r(l,{textAlign:"center",padding:"4px",fontSize:"12px"}),l.setAttribute("aria-live","polite");for(let s=1;s<=e.maxRows;s++)for(let t=1;t<=e.maxCols;t++){const a=document.createElement("div");a.className="notectl-grid-picker__cell",a.setAttribute("role","gridcell"),a.setAttribute("tabindex","-1"),a.setAttribute("aria-label",n.gridPickerLabel(s,t)),r(a,{width:"20px",height:"20px",border:"1px solid #ccc",cursor:"pointer"}),a.setAttribute("data-row",String(s)),a.setAttribute("data-col",String(t)),a.addEventListener("mouseenter",()=>{C(i,s,t),l.textContent=n.gridPickerLabel(s,t)}),a.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation()}),a.addEventListener("click",()=>{e.onSelect(s,t),o()}),i.appendChild(a)}t.appendChild(i),t.appendChild(l)}(t,e.popupConfig,i,this.locale);break;case"dropdown":!function(t,e,n,r){t.classList.add("notectl-dropdown"),t.setAttribute("role","menu");for(const i of e.items){const e=document.createElement("button");if(e.type="button",e.className="notectl-dropdown__item",e.setAttribute("role","menuitem"),e.setAttribute("tabindex","-1"),i.icon){const t=document.createElement("span");t.className="notectl-dropdown__item-icon",t.innerHTML=i.icon,e.appendChild(t)}const n=document.createElement("span");n.className="notectl-dropdown__item-label",n.textContent=i.label,e.appendChild(n),e.addEventListener("mousedown",t=>{t.preventDefault(),t.stopPropagation()}),e.addEventListener("click",()=>{var t;t=i.command,o.executeCommand(t),r()}),t.appendChild(e)}}(t,e.popupConfig,0,i);break;case"custom":case"combobox":e.renderPopup(t,o,n)}}clearButtonState(){this.activePopupButton&&(this.activePopupButton.classList.remove("notectl-toolbar-btn--popup-open"),this.activePopupButton.setAttribute("aria-expanded","false"),this.activePopupButton=null)}handlePopupKeydown(t){if(!this.activePopup)return;if("Escape"===t.key)return t.preventDefault(),t.stopPropagation(),void this.closeAndRestoreFocus();if("Tab"===t.key)return t.preventDefault(),void this.closeAndRestoreFocus();const e=this.activePopup.querySelectorAll('[role="menuitem"]');e.length>0?this.handleDropdownKeydown(t,e):null===this.activePopup.querySelector(".notectl-grid-picker__cell")?this.handleCustomPopupKeydown(t):this.handleGridKeydown(t)}handleDropdownKeydown(t,e){const o=Array.from(e),n=o.indexOf(this.getActiveElement());switch(t.key){case"ArrowDown":t.preventDefault(),o[l(o,n,1)]?.focus();break;case"ArrowUp":t.preventDefault(),o[l(o,n,-1)]?.focus();break;case"Enter":case" ":{t.preventDefault();const e=o[n];e&&e.click();break}}}handleGridKeydown(t){const e=this.getActiveElement(),o=Number(e?.getAttribute("data-row")??1),n=Number(e?.getAttribute("data-col")??1),r=this.activePopup?.querySelector(".notectl-grid-picker__grid")??null;if(!r)return;const l=r.querySelector(".notectl-grid-picker__cell:last-child"),a=Number(l?.getAttribute("data-col")??1),c=Number(l?.getAttribute("data-row")??1);if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(t.key)){t.preventDefault();const[e,l]=s(o,n,c,a,t.key,!!this.activePopup&&i(this.activePopup));r.querySelector(`.notectl-grid-picker__cell[data-row="${e}"][data-col="${l}"]`)?.focus(),C(r,e,l);const d=this.activePopup?.querySelector(".notectl-grid-picker__label")??null;d&&(d.textContent=this.locale.gridPickerLabel(e,l))}"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),e?.click())}handleCustomPopupKeydown(t){if(!this.activePopup)return;const e=Array.from(this.activePopup.querySelectorAll("button"));if(0===e.length)return;const o=this.getActiveElement(),n=e.indexOf(o);switch(t.key){case"ArrowDown":t.preventDefault(),e[l(e,n,1)]?.focus();break;case"ArrowUp":t.preventDefault(),e[l(e,n,-1)]?.focus();break;case"Enter":case" ":t.preventDefault(),o&&((r=o).dispatchEvent(new MouseEvent("mousedown",{bubbles:!0,cancelable:!0})),r.dispatchEvent(new MouseEvent("mouseup",{bubbles:!0,cancelable:!0})),r.click())}var r}},I=class t{element;timer=null;target=null;isPopupActive;static TOOLTIP_ID="notectl-toolbar-tooltip";constructor(e){this.isPopupActive=e,this.element=document.createElement("div"),this.element.className="notectl-toolbar-tooltip",this.element.id=t.TOOLTIP_ID,this.element.setAttribute("role","tooltip"),n(this.element,"display","none")}show(e){if(this.hide(),this.isPopupActive()||e.disabled)return;const o=e.getAttribute("data-tooltip");o&&(this.target=e,this.timer=setTimeout(()=>{if(this.isPopupActive())return;this.element.textContent=o,n(this.element,"display","");const i=e.getRootNode();i instanceof ShadowRoot&&!this.element.parentNode?i.appendChild(this.element):i instanceof ShadowRoot||this.element.parentNode||document.body.appendChild(this.element),e.setAttribute("aria-describedby",t.TOOLTIP_ID);const l=e.getBoundingClientRect();n(this.element,"position","fixed");const s=d(this.element);r(this.element,{top:l.bottom+6-s.y+"px",left:l.left+l.width/2-s.x+"px",transform:"translateX(-50%)"})},500))}hide(){this.timer&&(clearTimeout(this.timer),this.timer=null),this.target&&(this.target.removeAttribute("aria-describedby"),this.target=null),n(this.element,"display","none")}destroy(){this.hide(),this.element.remove()}};function P(t){if(Array.isArray(t))return{plugins:t,label:void 0};const e=t;return{plugins:e.plugins,label:e.label}}var D=new t("toolbar"),T=class{id="toolbar";name="Toolbar";priority=10;context=null;toolbarElement=null;buttons=[];hiddenItems=/* @__PURE__ */new Set;layoutConfig;overflowBehavior;focusedIndex=0;tooltip=null;popupController=null;popupManager=null;overflowController=null;visibleElements=[];locale;constructor(t){this.layoutConfig=t??null,this.overflowBehavior=t?.overflow??w.BurgerMenu}async init(t){this.locale=await o(t,void 0,f,g),t.registerStyleSheet('\n/* Toolbar */\n.notectl-plugin-container--top {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: nowrap;\n\tborder-bottom: 1px solid var(--notectl-border);\n\tbackground: var(--notectl-toolbar-bg, var(--notectl-surface-raised));\n\tmin-height: 40px;\n\tflex-shrink: 0;\n}\n\n.notectl-toolbar {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: nowrap;\n\toverflow: hidden;\n\tflex: 1;\n\tmin-width: 0;\n\tgap: 2px;\n\tpadding: 4px 8px;\n}\n\n.notectl-toolbar[hidden] {\n\tdisplay: none;\n}\n\n/* Group wrapper — real flex container so consumers can style it via ::part(toolbar-group)\n with padding/background/border directly. Group gap mirrors the toolbar gap so the\n visual rhythm between buttons stays uniform whether or not a group boundary lies between them. */\n.notectl-toolbar-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 2px;\n}\n\n.notectl-toolbar-group--overflow-hidden {\n\tdisplay: none;\n}\n\n.notectl-toolbar-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid transparent;\n\tborder-radius: 4px;\n\tbackground: var(--notectl-toolbar-button-bg, transparent);\n\tcursor: pointer;\n\tcolor: var(--notectl-toolbar-button-fg, var(--notectl-fg));\n\tfont-size: 14px;\n\tline-height: 1;\n\tpadding: 0;\n\tflex-shrink: 0;\n\ttransition: background 0.1s, border-color 0.1s;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn:hover {\n\t\tbackground: var(--notectl-toolbar-button-hover-bg, var(--notectl-hover-bg));\n\t\tborder-color: var(--notectl-border);\n\t}\n}\n\n.notectl-toolbar-btn--active {\n\tbackground: var(--notectl-toolbar-button-active-bg, var(--notectl-active-bg));\n\tborder-color: var(--notectl-primary-muted);\n\tcolor: var(--notectl-toolbar-button-active-fg, var(--notectl-primary-fg));\n}\n\n.notectl-toolbar-btn:focus-visible {\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n\toutline: none;\n}\n\n.notectl-toolbar-btn:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn:disabled:hover {\n\t\tbackground: transparent;\n\t\tborder-color: transparent;\n\t}\n}\n\n.notectl-toolbar-btn__icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpointer-events: none;\n}\n\n.notectl-toolbar-btn__icon svg {\n\tdisplay: block;\n\twidth: 18px;\n\theight: 18px;\n\tfill: currentColor;\n}\n\n/* Tooltip (rendered as fixed-position element in shadow root) */\n.notectl-toolbar-tooltip {\n\tpadding: 4px 8px;\n\tborder-radius: 4px;\n\tbackground: var(--notectl-tooltip-bg);\n\tcolor: var(--notectl-tooltip-fg);\n\tfont-size: 11px;\n\tfont-weight: 500;\n\twhite-space: nowrap;\n\tpointer-events: none;\n\tz-index: 10001;\n\tline-height: 1.4;\n\tletter-spacing: 0.01em;\n\tfont-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;\n}\n\n.notectl-toolbar-separator {\n\tdisplay: inline-block;\n\twidth: 1px;\n\theight: 20px;\n\tbackground: var(--notectl-border);\n\tmargin: 0 4px;\n\tvertical-align: middle;\n}\n\n/* Toolbar Popups */\n.notectl-toolbar-popup {\n\tbackground: var(--notectl-surface-overlay);\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 6px;\n\tbox-shadow: 0 4px 12px var(--notectl-shadow);\n\toverflow: hidden;\n}\n\n/* Grid Picker */\n.notectl-grid-picker__cell:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n\n.notectl-grid-picker__cell--highlighted {\n\tbackground: var(--notectl-primary-muted);\n\tborder-color: var(--notectl-primary);\n}\n\n/* Dropdown */\n.notectl-dropdown {\n\tmin-width: 160px;\n\tpadding: 4px 0;\n}\n\n.notectl-dropdown__item {\n\tdisplay: flex;\n\talign-items: center;\n\twidth: 100%;\n\tpadding: 8px 12px;\n\ttext-align: start;\n\tborder: none;\n\tbackground: none;\n\tcursor: pointer;\n\tfont-size: 14px;\n\tcolor: var(--notectl-fg);\n\tline-height: 1.4;\n\tfont-family: inherit;\n\twhite-space: nowrap;\n}\n\n@media (hover: hover) {\n\t.notectl-dropdown__item:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t}\n}\n\n.notectl-dropdown__item:focus-visible {\n\tbackground: var(--notectl-hover-bg);\n\toutline: none;\n}\n\n.notectl-dropdown__item-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\tfont-weight: 600;\n\tcolor: var(--notectl-fg-muted);\n\tflex-shrink: 0;\n}\n\n.notectl-dropdown__item-label {\n\tflex: 1;\n}\n\n/* Overflow behavior: flow mode — toolbar wraps to additional rows */\n.notectl-toolbar[data-overflow="flow"] {\n\tflex-wrap: wrap;\n\toverflow: visible;\n}\n\n/* Overflow behavior: none — toolbar clips without any responsive behavior */\n.notectl-toolbar[data-overflow="none"] {\n\tflex-wrap: nowrap;\n\toverflow: hidden;\n}\n\n/* Overflow: hidden items (burger-menu mode) */\n.notectl-toolbar-btn--overflow-hidden,\n.notectl-toolbar-separator--overflow-hidden {\n\tdisplay: none;\n}\n\n/* Overflow "more" button */\n.notectl-toolbar-overflow-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder: 1px solid transparent;\n\tborder-radius: 4px;\n\tbackground: transparent;\n\tcursor: pointer;\n\tcolor: var(--notectl-fg);\n\tfont-size: 16px;\n\tline-height: 1;\n\tpadding: 0;\n\tflex-shrink: 0;\n\tmargin-inline-start: auto;\n\ttransition: background 0.1s, border-color 0.1s;\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-overflow-btn:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t\tborder-color: var(--notectl-border);\n\t}\n}\n\n.notectl-toolbar-overflow-btn--hidden {\n\tdisplay: none;\n}\n\n.notectl-toolbar-overflow-btn:focus-visible {\n\tbox-shadow: 0 0 0 2px var(--notectl-focus-ring);\n\toutline: none;\n}\n\n/* Dropdown item states shared by all dropdown menus (including overflow) */\n.notectl-dropdown__item:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n@media (hover: hover) {\n\t.notectl-dropdown__item:disabled:hover {\n\t\tbackground: none;\n\t}\n}\n\n.notectl-dropdown__item--active {\n\tcolor: var(--notectl-primary-fg);\n}\n\n.notectl-dropdown__item-icon svg {\n\tdisplay: block;\n\twidth: 16px;\n\theight: 16px;\n\tfill: currentColor;\n}\n\n.notectl-dropdown__separator {\n\theight: 1px;\n\tbackground: var(--notectl-border);\n\tmargin: 4px 0;\n}\n\n/* Combobox-style toolbar buttons (shared base for font, fontSize, heading, etc.) */\n.notectl-toolbar-btn[role="combobox"] {\n\twidth: auto;\n\tpadding: 0 8px;\n\tgap: 4px;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-toolbar-bg, var(--notectl-surface-raised));\n}\n\n@media (hover: hover) {\n\t.notectl-toolbar-btn[role="combobox"]:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t\tborder-color: var(--notectl-fg-muted);\n\t}\n}\n\n.notectl-toolbar-btn[role="combobox"].notectl-toolbar-btn--active {\n\tbackground: var(--notectl-toolbar-bg, var(--notectl-surface-raised));\n\tborder-color: var(--notectl-primary-muted);\n}\n\n.notectl-toolbar-combobox__label {\n\tflex: 1;\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcolor: var(--notectl-fg);\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\ttext-align: start;\n\tline-height: 30px;\n}\n\n.notectl-toolbar-combobox__arrow {\n\tflex-shrink: 0;\n\tfont-size: 11px;\n\tcolor: var(--notectl-fg-muted);\n\tline-height: 30px;\n}\n\n/* Link Popup */\n.notectl-link-popup {\n\tpadding: 8px;\n\tmin-width: 200px;\n}\n\n.notectl-link-popup__input {\n\twidth: 100%;\n\tpadding: 4px;\n\tbox-sizing: border-box;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tfont-size: 13px;\n\tcolor: var(--notectl-fg);\n\tbackground: var(--notectl-surface-overlay);\n}\n\n.notectl-link-popup__input:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n\n.notectl-link-popup__button {\n\twidth: 100%;\n\tpadding: 6px 12px;\n\tcursor: pointer;\n\tborder: 1px solid var(--notectl-border);\n\tborder-radius: 4px;\n\tbackground: var(--notectl-surface-overlay);\n\tcolor: var(--notectl-fg);\n\tfont-size: 13px;\n}\n\n.notectl-link-popup__button--apply {\n\tmargin-top: 4px;\n}\n\n@media (hover: hover) {\n\t.notectl-link-popup__button:hover {\n\t\tbackground: var(--notectl-hover-bg);\n\t}\n}\n\n.notectl-link-popup__button:focus-visible {\n\toutline: 2px solid var(--notectl-focus-ring);\n\toutline-offset: -1px;\n}\n'),this.context=t,this.popupManager=new h(t.getContainer()),t.registerService(u,this.popupManager),this.popupController=new L(()=>this.getActiveElement(),this.locale),this.popupController.setPopupManager(this.popupManager),this.tooltip=new I(()=>this.popupController?.isOpen()??!1),t.registerService(D,{refresh:()=>this.updateButtonStates(t.getState()),closePopup:()=>this.popupController?.close()}),this.createToolbarElement()}getOverflowBehavior(){return this.overflowBehavior}setOverflowBehavior(t){t!==this.overflowBehavior&&(this.overflowBehavior=t,this.applyOverflowBehavior(),this.renderItems())}onReady(){this.renderItems()}destroy(){this.overflowController?.destroy(),this.overflowController=null,this.popupController?.destroy(),this.popupController=null,this.popupManager?.destroy(),this.popupManager=null,this.tooltip?.destroy(),this.tooltip=null,this.toolbarElement&&(this.toolbarElement.remove(),this.toolbarElement=null),this.buttons=[],this.visibleElements=[],this.context=null}onStateChange(t,e,o){this.updateButtonStates(e)}onReadOnlyChange(t){this.toolbarElement&&(this.toolbarElement.hidden=t)}onConfigure(t){for(const[e,o]of Object.entries(t))!1===o?this.hiddenItems.add(e):this.hiddenItems.delete(e);this.renderItems()}createToolbarElement(){if(!this.context)return;this.toolbarElement&&this.toolbarElement.remove(),this.buttons=[];const t=this.context.getPluginContainer("top");this.toolbarElement=document.createElement("div"),this.toolbarElement.setAttribute("role","toolbar"),this.toolbarElement.setAttribute("aria-label",this.locale.formattingOptionsAria),this.toolbarElement.setAttribute("data-notectl-no-print",""),this.toolbarElement.setAttribute("part","toolbar"),this.toolbarElement.className="notectl-toolbar",this.toolbarElement.addEventListener("keydown",t=>this.handleToolbarKeydown(t)),this.applyOverflowBehavior(),t.appendChild(this.toolbarElement)}applyOverflowBehavior(){this.toolbarElement&&this.context&&(this.overflowController?.destroy(),this.overflowController=null,this.toolbarElement.setAttribute("data-overflow",this.overflowBehavior),this.overflowBehavior===w.BurgerMenu?this.overflowController=new k({toolbar:this.toolbarElement,ariaLabel:this.locale.moreToolsAria,context:this.context,popupManager:this.popupManager??void 0,onOverflowChange:(t,e)=>{this.visibleElements=e?[...t,e]:[...t],this.initRovingTabindex()},onItemActivated:(t,e)=>{this.activateButton(t,e)},getActiveElement:()=>this.getActiveElement()}):this.visibleElements=[])}renderItems(){if(this.context&&this.toolbarElement){for(const t of this.buttons)t.element.remove();this.buttons=[];for(const t of this.toolbarElement.querySelectorAll(".notectl-toolbar-separator"))t.remove();for(const t of this.toolbarElement.querySelectorAll(".notectl-toolbar-group"))t.remove();this.layoutConfig?this.renderItemsByLayout():this.renderItemsByGroup(),this.buttons.length>0&&!this.toolbarElement.parentElement&&this.context.getPluginContainer("top").appendChild(this.toolbarElement),this.overflowController?.update(this.buttons),this.initRovingTabindex(),this.updateButtonStates(this.context.getState())}}createGroupWrapper(t){const e=document.createElement("div");return e.className="notectl-toolbar-group",e.setAttribute("part","toolbar-group"),void 0!==t&&(e.setAttribute("role","group"),e.setAttribute("aria-label",t)),e}getTabElements(){return this.visibleElements.length>0?this.visibleElements:this.buttons.map(t=>t.element)}initRovingTabindex(){const t=this.getTabElements(),e=m(t);this.focusedIndex=e>=0?e:0,a(t,this.focusedIndex)}setRovingFocus(t){const e=this.getTabElements();t<0||t>=e.length||(this.focusedIndex=t,a(e,t),e[t]?.focus())}getActiveElement(){const t=this.toolbarElement?.getRootNode();return t instanceof ShadowRoot?t.activeElement:document.activeElement}syncFocusedIndex(){const t=this.getActiveElement(),e=this.getTabElements().findIndex(e=>e===t);e>=0&&(this.focusedIndex=e)}handleToolbarKeydown(t){const e=this.getTabElements();var o;if(0!==e.length)switch(this.syncFocusedIndex(),t.key){case"ArrowRight":case"ArrowLeft":{t.preventDefault();const n=(o=!!this.toolbarElement&&i(this.toolbarElement),"ArrowRight"===t.key?o?-1:1:o?1:-1),r=function(t,e,o){const n=t.length;if(0===n)return-1;let r=e;for(let i=0;i<n;i++)if(r=(r+o+n)%n,!t[r]?.disabled)return r;return e}(e,this.focusedIndex,n);this.setRovingFocus(r);break}case"Home":{t.preventDefault();const o=m(e);o>=0&&this.setRovingFocus(o);break}case"End":{t.preventDefault();const o=function(t){for(let e=t.length-1;e>=0;e--)if(!t[e]?.disabled)return e;return-1}(e);o>=0&&this.setRovingFocus(o);break}case"Enter":case" ":{t.preventDefault();const o=e[this.focusedIndex],n=this.buttons.find(t=>t.element===o);n&&this.activateButton(n.element,n.item);break}}}activateButton(t,e){this.tooltip?.hide(),e.popupType&&this.context?this.popupController?.toggle(t,e,this.context):this.context?.executeCommand(e.command)}renderItemsByLayout(){if(!this.context||!this.toolbarElement||!this.layoutConfig)return;const t=this.context.getToolbarRegistry();let e=!0;for(const o of this.layoutConfig.groups){const{plugins:n,label:r}=P(o),i=[];for(const e of n){const o=t.getToolbarItemsByPlugin(e).filter(t=>!this.hiddenItems.has(t.id));i.push(...o)}if(0===i.length)continue;e||this.toolbarElement.appendChild(B()),e=!1;const l=this.createGroupWrapper(r);for(const t of i){const e=this.createButton(t);l.appendChild(e.element),this.buttons.push(e)}this.toolbarElement.appendChild(l)}0===this.buttons.length&&this.toolbarElement.remove()}renderItemsByGroup(){if(!this.context||!this.toolbarElement)return;const t=this.context.getToolbarRegistry().getToolbarItems().filter(t=>!this.hiddenItems.has(t.id));if(0===t.length)return void this.toolbarElement.remove();const e=/* @__PURE__ */new Map;for(const n of t){const t=e.get(n.group)??[];t.push(n),e.set(n.group,t)}let o=!0;for(const[,n]of e){o||this.toolbarElement.appendChild(B()),o=!1;const t=this.createGroupWrapper(void 0);for(const e of n){const o=this.createButton(e);t.appendChild(o.element),this.buttons.push(o)}this.toolbarElement.appendChild(t)}}createButton(t){const e=document.createElement("button");e.type="button",e.className=`notectl-toolbar-btn notectl-toolbar-btn--${t.id}`,e.setAttribute("aria-pressed","false"),e.setAttribute("aria-label",t.label),e.setAttribute("data-toolbar-item",t.id),e.setAttribute("data-tooltip",t.tooltip??t.label),e.setAttribute("part","toolbar-button");let o=null;if("combobox"===t.popupType){e.setAttribute("role","combobox"),e.setAttribute("aria-haspopup","listbox"),e.setAttribute("aria-expanded","false");const n=document.createElement("span");n.className="notectl-toolbar-combobox__label";const r=this.context?.getState();r&&(n.textContent=t.getLabel(r)),e.appendChild(n),o=n;const i=document.createElement("span");i.className="notectl-toolbar-combobox__arrow",i.setAttribute("aria-hidden","true"),i.textContent="▾",e.appendChild(i)}else{t.popupType&&(e.setAttribute("aria-haspopup","true"),e.setAttribute("aria-expanded","false"));const o=document.createElement("span");o.className="notectl-toolbar-btn__icon",o.innerHTML=t.icon,e.appendChild(o)}return e.addEventListener("mousedown",o=>{o.preventDefault(),this.activateButton(e,t)}),e.addEventListener("mouseenter",()=>this.tooltip?.show(e)),e.addEventListener("mouseleave",()=>this.tooltip?.hide()),e.addEventListener("focus",()=>this.tooltip?.show(e)),e.addEventListener("blur",()=>this.tooltip?.hide()),{element:e,item:t,comboLabelEl:o}}updateButtonStates(t){for(const e of this.buttons){const o=e.item.isActive?.(t)??!1,n=e.item.isEnabled?.(t)??!0;if(e.element.setAttribute("aria-pressed",String(o)),e.element.classList.toggle("notectl-toolbar-btn--active",o),e.element.setAttribute("part",o?"toolbar-button toolbar-button-active":"toolbar-button"),e.element.disabled=!n,n?e.element.removeAttribute("aria-disabled"):e.element.setAttribute("aria-disabled","true"),e.comboLabelEl&&"combobox"===e.item.popupType&&(e.comboLabelEl.textContent=e.item.getLabel(t)),e.item.getIcon){const o=e.item.getIcon(t),n=e.element.querySelector(".notectl-toolbar-btn__icon");n&&n.innerHTML!==o&&(n.innerHTML=o)}}this.overflowController?.updateItemStates(t)}};export{g as a,f as i,D as n,b as o,w as r,T as t};
2
+ //# sourceMappingURL=ToolbarPlugin-dmTj1jIz.mjs.map