@templatical/editor 0.23.0 → 0.24.0

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 (184) hide show
  1. package/dist/{AiChatSidebar-Bru6-ziQ.js → AiChatSidebar-Nq-jrGaf.js} +2 -2
  2. package/dist/{AiFeatureMenu-CcqjRMFW.js → AiFeatureMenu-tg_zMKMK.js} +3 -3
  3. package/dist/{BlockIssueBadge-Dmj9rVra.js → BlockIssueBadge-Bd94kIiw.js} +2 -2
  4. package/dist/BlockPreviewCanvas-B34aMhHe.js +117 -0
  5. package/dist/{CloudEditor-iK4vkpNm.js → CloudEditor-DjN_9Yso.js} +124 -119
  6. package/dist/{CollaboratorBar-C_1SF7Xf.js → CollaboratorBar-Bhazzcg-.js} +2 -2
  7. package/dist/{ColorPicker-s9GHXjZs.js → ColorPicker-DXGrcJxJ.js} +5 -5
  8. package/dist/{CommentsSidebar-DvNEdugN.js → CommentsSidebar-ku1kt10u.js} +3 -3
  9. package/dist/{CountdownBlock-J_Q9JRQM.js → CountdownBlock-CN9Lc23W.js} +1 -1
  10. package/dist/{CountdownToolbar-DPRcv3Fu.js → CountdownToolbar-VEsIyKV6.js} +3 -3
  11. package/dist/{DesignReferenceSidebar-BxPo0zyx.js → DesignReferenceSidebar-C4pTMzQE.js} +3 -3
  12. package/dist/{IssuesPanel-CEnEGFtd.js → IssuesPanel-CEfzOpS_.js} +2 -2
  13. package/dist/MergeTagModeToggle-C3V2xGAg.js +180 -0
  14. package/dist/{MergeTagSuggestion-D9eCryMC.js → MergeTagSuggestion-Dn8ww9nV.js} +2 -2
  15. package/dist/{NumberWithSuffix-CCPN_oCh.js → NumberWithSuffix-BGocZkj9.js} +1 -1
  16. package/dist/{ParagraphEditor-MKJYyWN9.js → ParagraphEditor-D-fz0kUb.js} +19 -19
  17. package/dist/{RichTextEditorContent-FbnWsh46.js → RichTextEditorContent-DydrqFts.js} +5 -5
  18. package/dist/{SaveBlockDialog-CFAJHP3v.js → SaveBlockDialog-BDDFbAWF.js} +6 -6
  19. package/dist/{SavedBlocksBrowserModal-C_-Xcm0Q.js → SavedBlocksBrowserModal-Djik_fJh.js} +6 -6
  20. package/dist/{SavedBlocksPanels-CRf7zzFn.js → SavedBlocksPanels-CxemyPxL.js} +1 -1
  21. package/dist/{SavedBlocksPickBar-C1FTJP-I.js → SavedBlocksPickBar-Dlhipmob.js} +2 -2
  22. package/dist/{SnapshotHistory-DWlQ3Eh0.js → SnapshotHistory-DPbM4ons.js} +4 -4
  23. package/dist/{TemplateScoringPanel-ifGGGWs5.js → TemplateScoringPanel-BFYgweDX.js} +2 -2
  24. package/dist/{TestEmailModal-D90-3Yex.js → TestEmailModal-IZfwgya-.js} +71 -59
  25. package/dist/{TestEmailPanel-B0u_Yd3X.js → TestEmailPanel-QEEx_PkN.js} +1 -1
  26. package/dist/{TitleEditor-DzsPxKv4.js → TitleEditor-BB4YlIBF.js} +10 -10
  27. package/dist/{TplModal-CykwWFhF.js → TplModal-DPH4vV8M.js} +3 -3
  28. package/dist/{blockTypeIcons-CpKkI47V.js → blockTypeIcons-Wzd7W_2x.js} +1 -1
  29. package/dist/bundle-stats.json +6 -6
  30. package/dist/{ca-D47BxSGu.js → ca-CO4nq6TX.js} +8 -1
  31. package/dist/cdn/chunks/{AiChatSidebar-BMnsF8G6.js → AiChatSidebar-CN-0DIuA.js} +11 -11
  32. package/dist/cdn/chunks/{AiChatSidebar-BMnsF8G6.js.map → AiChatSidebar-CN-0DIuA.js.map} +1 -1
  33. package/dist/cdn/chunks/{AiFeatureMenu-hWgWQg11.js → AiFeatureMenu-B5pV6Iux.js} +8 -8
  34. package/dist/cdn/chunks/{AiFeatureMenu-hWgWQg11.js.map → AiFeatureMenu-B5pV6Iux.js.map} +1 -1
  35. package/dist/cdn/chunks/{BlockIssueBadge-Da4yR-mh.js → BlockIssueBadge-aanOjeyi.js} +4 -4
  36. package/dist/cdn/chunks/{BlockIssueBadge-Da4yR-mh.js.map → BlockIssueBadge-aanOjeyi.js.map} +1 -1
  37. package/dist/cdn/chunks/BlockPreviewCanvas-Dc4F4HzY.js +119 -0
  38. package/dist/cdn/chunks/BlockPreviewCanvas-Dc4F4HzY.js.map +1 -0
  39. package/dist/cdn/chunks/{CloudEditor-S8zLHtKb.js → CloudEditor-CeKaWWO5.js} +129 -124
  40. package/dist/cdn/chunks/CloudEditor-CeKaWWO5.js.map +1 -0
  41. package/dist/cdn/chunks/{CollaboratorBar-mkJVAkSh.js → CollaboratorBar-CEdKr0A2.js} +4 -4
  42. package/dist/cdn/chunks/{CollaboratorBar-mkJVAkSh.js.map → CollaboratorBar-CEdKr0A2.js.map} +1 -1
  43. package/dist/cdn/chunks/{ColorPicker-DZSzZ5ZP.js → ColorPicker-BckwEfcN.js} +7 -7
  44. package/dist/cdn/chunks/{ColorPicker-DZSzZ5ZP.js.map → ColorPicker-BckwEfcN.js.map} +1 -1
  45. package/dist/cdn/chunks/{CommentsSidebar-DHdRiGPX.js → CommentsSidebar-6PfpJKh-.js} +18 -18
  46. package/dist/cdn/chunks/{CommentsSidebar-DHdRiGPX.js.map → CommentsSidebar-6PfpJKh-.js.map} +1 -1
  47. package/dist/cdn/chunks/{CountdownBlock-Bffpoppw.js → CountdownBlock-CoBmvQKv.js} +2 -2
  48. package/dist/cdn/chunks/{CountdownBlock-Bffpoppw.js.map → CountdownBlock-CoBmvQKv.js.map} +1 -1
  49. package/dist/cdn/chunks/{CountdownToolbar-DAnmIZjq.js → CountdownToolbar-CdV8RTQu.js} +4 -4
  50. package/dist/cdn/chunks/{CountdownToolbar-DAnmIZjq.js.map → CountdownToolbar-CdV8RTQu.js.map} +1 -1
  51. package/dist/cdn/chunks/{DesignReferenceSidebar-CM-k15pd.js → DesignReferenceSidebar-BjlaP69l.js} +90 -90
  52. package/dist/cdn/chunks/{DesignReferenceSidebar-CM-k15pd.js.map → DesignReferenceSidebar-BjlaP69l.js.map} +1 -1
  53. package/dist/cdn/chunks/{IssuesPanel-D80JedOj.js → IssuesPanel-CkkEnhxZ.js} +9 -9
  54. package/dist/cdn/chunks/{IssuesPanel-D80JedOj.js.map → IssuesPanel-CkkEnhxZ.js.map} +1 -1
  55. package/dist/cdn/chunks/MergeTagModeToggle-DmtR300G.js +127 -0
  56. package/dist/cdn/chunks/MergeTagModeToggle-DmtR300G.js.map +1 -0
  57. package/dist/cdn/chunks/{MergeTagSuggestion-BM349_QH.js → MergeTagSuggestion-Cvlkw_PM.js} +2 -2
  58. package/dist/cdn/chunks/{MergeTagSuggestion-BM349_QH.js.map → MergeTagSuggestion-Cvlkw_PM.js.map} +1 -1
  59. package/dist/cdn/chunks/{NumberWithSuffix-CjlVNIEe.js → NumberWithSuffix-BOcMN26z.js} +2 -2
  60. package/dist/cdn/chunks/{NumberWithSuffix-CjlVNIEe.js.map → NumberWithSuffix-BOcMN26z.js.map} +1 -1
  61. package/dist/cdn/chunks/{ParagraphEditor-J-1RLyi7.js → ParagraphEditor-CX1yks4N.js} +35 -35
  62. package/dist/cdn/chunks/{ParagraphEditor-J-1RLyi7.js.map → ParagraphEditor-CX1yks4N.js.map} +1 -1
  63. package/dist/cdn/chunks/{RichTextEditorContent-BbdgJqWM.js → RichTextEditorContent-z9s7qxs3.js} +7 -7
  64. package/dist/cdn/chunks/{RichTextEditorContent-BbdgJqWM.js.map → RichTextEditorContent-z9s7qxs3.js.map} +1 -1
  65. package/dist/cdn/chunks/{SaveBlockDialog-Bi_Z3kuA.js → SaveBlockDialog-D2CtW4lC.js} +8 -8
  66. package/dist/cdn/chunks/{SaveBlockDialog-Bi_Z3kuA.js.map → SaveBlockDialog-D2CtW4lC.js.map} +1 -1
  67. package/dist/cdn/chunks/{SavedBlocksBrowserModal-CesYxFsH.js → SavedBlocksBrowserModal-DdUKJzzF.js} +8 -8
  68. package/dist/cdn/chunks/{SavedBlocksBrowserModal-CesYxFsH.js.map → SavedBlocksBrowserModal-DdUKJzzF.js.map} +1 -1
  69. package/dist/cdn/chunks/{SavedBlocksPanels-BsSpJwrW.js → SavedBlocksPanels-1kVbqdpc.js} +2 -2
  70. package/dist/cdn/chunks/{SavedBlocksPanels-BsSpJwrW.js.map → SavedBlocksPanels-1kVbqdpc.js.map} +1 -1
  71. package/dist/cdn/chunks/{SavedBlocksPickBar-CduR1Cpb.js → SavedBlocksPickBar--noDJIyN.js} +6 -6
  72. package/dist/cdn/chunks/{SavedBlocksPickBar-CduR1Cpb.js.map → SavedBlocksPickBar--noDJIyN.js.map} +1 -1
  73. package/dist/cdn/chunks/{SnapshotHistory-DO-gzr3i.js → SnapshotHistory-DFuNJRc9.js} +8 -8
  74. package/dist/cdn/chunks/{SnapshotHistory-DO-gzr3i.js.map → SnapshotHistory-DFuNJRc9.js.map} +1 -1
  75. package/dist/cdn/chunks/{TemplateScoringPanel-CTk8WwxU.js → TemplateScoringPanel-DG1dAjQk.js} +52 -52
  76. package/dist/cdn/chunks/{TemplateScoringPanel-CTk8WwxU.js.map → TemplateScoringPanel-DG1dAjQk.js.map} +1 -1
  77. package/dist/cdn/chunks/TestEmailModal-CiPfOn2v.js +174 -0
  78. package/dist/cdn/chunks/TestEmailModal-CiPfOn2v.js.map +1 -0
  79. package/dist/cdn/chunks/{TestEmailPanel-048m0kxX.js → TestEmailPanel-saOfnpjz.js} +2 -2
  80. package/dist/cdn/chunks/{TestEmailPanel-048m0kxX.js.map → TestEmailPanel-saOfnpjz.js.map} +1 -1
  81. package/dist/cdn/chunks/{TitleEditor-J1vgU_J6.js → TitleEditor-08KM_VzZ.js} +18 -18
  82. package/dist/cdn/chunks/{TitleEditor-J1vgU_J6.js.map → TitleEditor-08KM_VzZ.js.map} +1 -1
  83. package/dist/cdn/chunks/{TplModal-BN53d9Se.js → TplModal-Cu4tBBnF.js} +4 -4
  84. package/dist/cdn/chunks/{TplModal-BN53d9Se.js.map → TplModal-Cu4tBBnF.js.map} +1 -1
  85. package/dist/cdn/chunks/blockTypeIcons-DvohkXqi.js +21 -0
  86. package/dist/cdn/chunks/{blockTypeIcons-etMMQoVv.js.map → blockTypeIcons-DvohkXqi.js.map} +1 -1
  87. package/dist/cdn/chunks/{ca-D47BxSGu.js → ca-CO4nq6TX.js} +9 -2
  88. package/dist/cdn/chunks/{ca-D47BxSGu.js.map → ca-CO4nq6TX.js.map} +1 -1
  89. package/dist/cdn/chunks/{cloud-F-aVi9hj.js → cloud-C2I0P9qj.js} +2 -2
  90. package/dist/cdn/chunks/{cloud-F-aVi9hj.js.map → cloud-C2I0P9qj.js.map} +1 -1
  91. package/dist/{de-CnnxBwh7.js → cdn/chunks/de-CUeaFJph.js} +10 -1
  92. package/dist/cdn/chunks/{de-CnnxBwh7.js.map → de-CUeaFJph.js.map} +1 -1
  93. package/dist/{en-5gW-bYy2.js → cdn/chunks/en-zCYIPAL5.js} +10 -1
  94. package/dist/cdn/chunks/{en-5gW-bYy2.js.map → en-zCYIPAL5.js.map} +1 -1
  95. package/dist/cdn/chunks/{es-sQ9SdI0l.js → es-BSiH7YkP.js} +9 -2
  96. package/dist/cdn/chunks/{es-sQ9SdI0l.js.map → es-BSiH7YkP.js.map} +1 -1
  97. package/dist/cdn/chunks/{extensions-C49c51P1.js → extensions-DBWF_lxx.js} +16 -16
  98. package/dist/cdn/chunks/{extensions-C49c51P1.js.map → extensions-DBWF_lxx.js.map} +1 -1
  99. package/dist/{fr-DBZ5w21C.js → cdn/chunks/fr-DTVJ3det.js} +10 -1
  100. package/dist/cdn/chunks/fr-DTVJ3det.js.map +1 -0
  101. package/dist/cdn/chunks/{icons-CYWw8Xfp.js → icons-Cqxvwgz7.js} +35 -14
  102. package/dist/cdn/chunks/icons-Cqxvwgz7.js.map +1 -0
  103. package/dist/cdn/chunks/keys-B5uoP9P7.js +12 -0
  104. package/dist/cdn/chunks/keys-B5uoP9P7.js.map +1 -0
  105. package/dist/cdn/chunks/{nl-DOL7Fnfo.js → nl-BqSquFS3.js} +9 -2
  106. package/dist/cdn/chunks/nl-BqSquFS3.js.map +1 -0
  107. package/dist/{pt-BR-DRCdHX1d.js → cdn/chunks/pt-BR-CMljK37h.js} +10 -1
  108. package/dist/cdn/chunks/{pt-BR-DRCdHX1d.js.map → pt-BR-CMljK37h.js.map} +1 -1
  109. package/dist/cdn/chunks/{src-BKI1x1k7.js → src-BCJna-6p.js} +183 -165
  110. package/dist/cdn/chunks/{src-BKI1x1k7.js.map → src-BCJna-6p.js.map} +1 -1
  111. package/dist/cdn/chunks/{src-SluTVSz_.js → src-C45kfA2t.js} +17 -17
  112. package/dist/cdn/chunks/{src-SluTVSz_.js.map → src-C45kfA2t.js.map} +1 -1
  113. package/dist/cdn/chunks/{src-CzoMNRq4.js → src-XQmI_Xs1.js} +33 -33
  114. package/dist/cdn/chunks/{src-CzoMNRq4.js.map → src-XQmI_Xs1.js.map} +1 -1
  115. package/dist/cdn/chunks/{src-CM0gCvAS.js → src-YVsPFLNJ.js} +251 -251
  116. package/dist/cdn/chunks/{src-CM0gCvAS.js.map → src-YVsPFLNJ.js.map} +1 -1
  117. package/dist/cdn/chunks/{styles-BbfU2w9R.js → styles-BohMfIBd.js} +700 -693
  118. package/dist/cdn/chunks/styles-BohMfIBd.js.map +1 -0
  119. package/dist/cdn/chunks/{tiptap-DUTbZTeR.js → tiptap-DRKu__AX.js} +5 -5
  120. package/dist/cdn/chunks/{tiptap-DUTbZTeR.js.map → tiptap-DRKu__AX.js.map} +1 -1
  121. package/dist/cdn/chunks/{useCloudI18n-BjNENqkM.js → useCloudI18n-Bem8DUjH.js} +2 -2
  122. package/dist/cdn/chunks/{useCloudI18n-BjNENqkM.js.map → useCloudI18n-Bem8DUjH.js.map} +1 -1
  123. package/dist/cdn/chunks/{useEditorCore-CzMhD6Gd.js → useEditorCore-B_vwuKdI.js} +434 -414
  124. package/dist/cdn/chunks/useEditorCore-B_vwuKdI.js.map +1 -0
  125. package/dist/cdn/chunks/{useI18n-8Wd7G-cq.js → useI18n-graz19nI.js} +2 -2
  126. package/dist/cdn/chunks/{useI18n-8Wd7G-cq.js.map → useI18n-graz19nI.js.map} +1 -1
  127. package/dist/cdn/chunks/{useMergeTag-C7G31KV-.js → useMergeTag-rTzAFMlr.js} +4 -4
  128. package/dist/cdn/chunks/{useMergeTag-C7G31KV-.js.map → useMergeTag-rTzAFMlr.js.map} +1 -1
  129. package/dist/cdn/chunks/{usePopoverPosition-Bx0QewTv.js → usePopoverPosition-BaFxLP3w.js} +2 -2
  130. package/dist/cdn/chunks/{usePopoverPosition-Bx0QewTv.js.map → usePopoverPosition-BaFxLP3w.js.map} +1 -1
  131. package/dist/cdn/editor.css +1 -1
  132. package/dist/cdn/editor.js +144 -139
  133. package/dist/cdn/editor.js.map +1 -1
  134. package/dist/{cloud-CeZPgo1V.js → cloud-DsUct4Zq.js} +1 -1
  135. package/dist/{cdn/chunks/de-CnnxBwh7.js → de-CUeaFJph.js} +8 -3
  136. package/dist/{dist-CL_CfQ3Q.js → dist-9uhI32Q4.js} +2 -2
  137. package/dist/{dist-3DHaYEiT.js → dist-BAkGuPYm.js} +2 -2
  138. package/dist/dist-BIYm-U9x.js +5 -0
  139. package/dist/{dist-3HenmYIg.js → dist-ByJVlKWy.js} +1 -1
  140. package/dist/{dist-DKWoZJAV.js → dist-C5tigvDF.js} +2 -2
  141. package/dist/{dist-bivrM-nS.js → dist-CQiAZlTt.js} +2 -2
  142. package/dist/{dist-Ih7ejWzn.js → dist-C_kAE1sC.js} +2 -2
  143. package/dist/{dist-CclnU_v0.js → dist-CkCVlKj_.js} +2 -2
  144. package/dist/{dist-B_etKYyh.js → dist-DFO896yT.js} +5 -5
  145. package/dist/{dist-BJbqgyPn.js → dist-DPHqs0Yh.js} +105 -87
  146. package/dist/{dist-DOtLGnLr.js → dist-DWu9QWFl.js} +2 -2
  147. package/dist/{dist-BCnJcAQc.js → dist-IGetXrbO.js} +2 -2
  148. package/dist/dist-JXOq1hib.js +5 -0
  149. package/dist/{cdn/chunks/en-5gW-bYy2.js → en-zCYIPAL5.js} +8 -3
  150. package/dist/{es-sQ9SdI0l.js → es-BSiH7YkP.js} +8 -1
  151. package/dist/{extensions-3870a_3R.js → extensions-C0DXnYdA.js} +13 -13
  152. package/dist/{cdn/chunks/fr-DBZ5w21C.js → fr-DTVJ3det.js} +8 -3
  153. package/dist/keys-BVlG5Ozc.js +10 -0
  154. package/dist/{nl-DOL7Fnfo.js → nl-BqSquFS3.js} +8 -1
  155. package/dist/{cdn/chunks/pt-BR-DRCdHX1d.js → pt-BR-CMljK37h.js} +8 -3
  156. package/dist/style.css +1 -1
  157. package/dist/{styles-BWTIgN5L.js → styles-BTTD0Je4.js} +856 -849
  158. package/dist/templatical-editor.js +92 -87
  159. package/dist/{useCloudI18n-BmiygEM4.js → useCloudI18n-DGr3b2SX.js} +1 -1
  160. package/dist/{useEditorCore-CuMMIfiS.js → useEditorCore-DOrGex_t.js} +917 -897
  161. package/dist/{useI18n-D2L9Mkik.js → useI18n-BhAejA-x.js} +1 -1
  162. package/dist/{useMergeTag-BTdDq5DC.js → useMergeTag-Ce95YIOO.js} +3 -3
  163. package/dist/{usePopoverPosition-BO2LNy5n.js → usePopoverPosition-vjKJaqJf.js} +1 -1
  164. package/package.json +20 -20
  165. package/dist/BlockPreviewCanvas-MD9BGuXV.js +0 -115
  166. package/dist/ViewportToggle-BjmbNoao.js +0 -97
  167. package/dist/cdn/chunks/BlockPreviewCanvas-eASrdFSN.js +0 -117
  168. package/dist/cdn/chunks/BlockPreviewCanvas-eASrdFSN.js.map +0 -1
  169. package/dist/cdn/chunks/CloudEditor-S8zLHtKb.js.map +0 -1
  170. package/dist/cdn/chunks/TestEmailModal-CCWEVrE2.js +0 -162
  171. package/dist/cdn/chunks/TestEmailModal-CCWEVrE2.js.map +0 -1
  172. package/dist/cdn/chunks/ViewportToggle-CFmF-N4i.js +0 -66
  173. package/dist/cdn/chunks/ViewportToggle-CFmF-N4i.js.map +0 -1
  174. package/dist/cdn/chunks/blockTypeIcons-etMMQoVv.js +0 -21
  175. package/dist/cdn/chunks/fr-DBZ5w21C.js.map +0 -1
  176. package/dist/cdn/chunks/icons-CYWw8Xfp.js.map +0 -1
  177. package/dist/cdn/chunks/keys-D7kUmfpE.js +0 -12
  178. package/dist/cdn/chunks/keys-D7kUmfpE.js.map +0 -1
  179. package/dist/cdn/chunks/nl-DOL7Fnfo.js.map +0 -1
  180. package/dist/cdn/chunks/styles-BbfU2w9R.js.map +0 -1
  181. package/dist/cdn/chunks/useEditorCore-CzMhD6Gd.js.map +0 -1
  182. package/dist/dist-CcQLJeWV.js +0 -5
  183. package/dist/dist-DerdmERj.js +0 -5
  184. package/dist/keys-CHPcp-Nz.js +0 -10
@@ -1,13 +1,13 @@
1
1
  import { K as e, L as t, M as n, P as r, T as i, Z as a, c as o, ct as s, d as c, f as l, g as u, h as d, it as f, l as p, m, ot as h, p as g, st as _, u as v, v as y, x as b, y as x } from "./draggable-D840DIZB.js";
2
- import { D as S, E as C, S as w, x as T } from "./useEditorCore-CzMhD6Gd.js";
2
+ import { D as S, E as C, S as w, x as T } from "./useEditorCore-B_vwuKdI.js";
3
3
  import { t as E } from "./dist-CxTt8FRE.js";
4
- import { B as D, D as O, L as k, _ as ee, h as te, w as ne, z as re } from "./keys-D7kUmfpE.js";
5
- import { t as A } from "./useI18n-8Wd7G-cq.js";
6
- import { n as j } from "./usePopoverPosition-Bx0QewTv.js";
7
- import { It as ie, L as ae, N as oe, T as M, _ as se, at as ce, b as le, h as ue, it as de, l as fe, lt as pe, m as me, p as he, rt as ge, st as _e, y as ve, zt as ye } from "./icons-CYWw8Xfp.js";
4
+ import { B as D, D as O, H as k, R as ee, _ as te, h as ne, w as re } from "./keys-B5uoP9P7.js";
5
+ import { t as A } from "./useI18n-graz19nI.js";
6
+ import { n as j } from "./usePopoverPosition-BaFxLP3w.js";
7
+ import { Bt as ie, E as M, Lt as ae, P as oe, R as se, at as ce, b as le, ct as ue, g as de, h as fe, it as pe, l as me, m as he, ot as ge, ut as _e, v as ve, x as ye } from "./icons-Cqxvwgz7.js";
8
8
  import { t as N } from "./_plugin-vue_export-helper-B3ysoDQm.js";
9
- import { c as P, o as be, r as xe, s as Se, t as F } from "./ColorPicker-DZSzZ5ZP.js";
10
- import { n as I, t as L } from "./RichTextEditorContent-BbdgJqWM.js";
9
+ import { c as P, o as be, r as xe, s as Se, t as F } from "./ColorPicker-BckwEfcN.js";
10
+ import { n as I, t as L } from "./RichTextEditorContent-z9s7qxs3.js";
11
11
  //#region src/components/blocks/EmojiPickerDropdown.vue?vue&type=script&setup=true&lang.ts
12
12
  var R = [
13
13
  "aria-label",
@@ -156,7 +156,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
156
156
  "add-logic-tag"
157
157
  ],
158
158
  setup(e, { emit: t }) {
159
- let r = e, a = t, o = i(k, null), p = i(re, null), h = D(ee, "ParagraphToolbar"), b = j(), S = i(O, null), C = i(ne, null), w = i(te, null), T = l(() => (S?.isOpen.value ?? !1) || (C?.isOpen.value ?? !1)), { t: E } = A(), M = h.fonts;
159
+ let r = e, a = t, o = i(ee, null), p = i(D, null), h = k(te, "ParagraphToolbar"), b = j(), S = i(O, null), C = i(re, null), w = i(ne, null), T = l(() => (S?.isOpen.value ?? !1) || (C?.isOpen.value ?? !1)), { t: E } = A(), M = h.fonts;
160
160
  function N(e) {
161
161
  r.editor?.chain().focus().insertContent(e).run();
162
162
  }
@@ -277,7 +277,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
277
277
  ]),
278
278
  x(J),
279
279
  x(W, {
280
- icon: f(ye),
280
+ icon: f(ie),
281
281
  label: f(E).paragraphEditor.bold,
282
282
  active: e.editor.isActive("bold"),
283
283
  "stroke-width": 2.5,
@@ -288,7 +288,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
288
288
  "active"
289
289
  ]),
290
290
  x(W, {
291
- icon: f(pe),
291
+ icon: f(_e),
292
292
  label: f(E).paragraphEditor.italic,
293
293
  active: e.editor.isActive("italic"),
294
294
  onClick: r[1] ||= (t) => e.editor.chain().focus().toggleItalic().run()
@@ -298,7 +298,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
298
298
  "active"
299
299
  ]),
300
300
  x(W, {
301
- icon: f(fe),
301
+ icon: f(me),
302
302
  label: f(E).paragraphEditor.underline,
303
303
  active: e.editor.isActive("underline"),
304
304
  onClick: r[2] ||= (t) => e.editor.chain().focus().toggleUnderline().run()
@@ -308,7 +308,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
308
308
  "active"
309
309
  ]),
310
310
  x(W, {
311
- icon: f(ve),
311
+ icon: f(le),
312
312
  label: f(E).paragraphEditor.strikethrough,
313
313
  active: e.editor.isActive("strike"),
314
314
  onClick: r[3] ||= (t) => e.editor.chain().focus().toggleStrike().run()
@@ -319,7 +319,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
319
319
  ]),
320
320
  x(J),
321
321
  x(W, {
322
- icon: f(le),
322
+ icon: f(ye),
323
323
  label: f(E).paragraphEditor.subscript,
324
324
  active: e.editor.isActive("subscript"),
325
325
  onClick: r[4] ||= (t) => e.editor.chain().focus().toggleSubscript().run()
@@ -329,7 +329,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
329
329
  "active"
330
330
  ]),
331
331
  x(W, {
332
- icon: f(se),
332
+ icon: f(ve),
333
333
  label: f(E).paragraphEditor.superscript,
334
334
  active: e.editor.isActive("superscript"),
335
335
  onClick: r[5] ||= (t) => e.editor.chain().focus().toggleSuperscript().run()
@@ -340,7 +340,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
340
340
  ]),
341
341
  x(J),
342
342
  x(W, {
343
- icon: f(_e),
343
+ icon: f(ue),
344
344
  label: f(E).paragraphEditor.addLink,
345
345
  active: e.editor.isActive("link"),
346
346
  onClick: r[6] ||= (e) => a("open-link-dialog")
@@ -351,7 +351,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
351
351
  ])
352
352
  ]), g("div", Ee, [
353
353
  x(W, {
354
- icon: f(de),
354
+ icon: f(ce),
355
355
  label: f(E).paragraphEditor.bulletList,
356
356
  active: e.editor.isActive("bulletList"),
357
357
  onClick: r[7] ||= (t) => e.editor.chain().focus().toggleBulletList().run()
@@ -361,7 +361,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
361
361
  "active"
362
362
  ]),
363
363
  x(W, {
364
- icon: f(ce),
364
+ icon: f(ge),
365
365
  label: f(E).paragraphEditor.numberedList,
366
366
  active: e.editor.isActive("orderedList"),
367
367
  onClick: r[8] ||= (t) => e.editor.chain().focus().toggleOrderedList().run()
@@ -382,7 +382,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
382
382
  "active"
383
383
  ]),
384
384
  x(W, {
385
- icon: f(ue),
385
+ icon: f(de),
386
386
  label: f(E).paragraphEditor.alignCenter,
387
387
  active: e.editor.isActive({ textAlign: "center" }),
388
388
  onClick: r[10] ||= (t) => e.editor.chain().focus().setTextAlign("center").run()
@@ -392,7 +392,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
392
392
  "active"
393
393
  ]),
394
394
  x(W, {
395
- icon: f(me),
395
+ icon: f(fe),
396
396
  label: f(E).paragraphEditor.alignRight,
397
397
  active: e.editor.isActive({ textAlign: "right" }),
398
398
  onClick: r[11] ||= (t) => e.editor.chain().focus().setTextAlign("right").run()
@@ -428,7 +428,7 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
428
428
  ]),
429
429
  x(J),
430
430
  x(W, {
431
- icon: f(ae),
431
+ icon: f(se),
432
432
  label: f(E).paragraphEditor.clearFormatting,
433
433
  onClick: r[12] ||= (t) => e.editor.chain().focus().clearNodes().unsetAllMarks().run()
434
434
  }, null, 8, ["icon", "label"]),
@@ -451,11 +451,11 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
451
451
  title: f(E).logicTag.insert,
452
452
  "data-testid": "insert-logic-button",
453
453
  onClick: r[14] ||= (e) => a("add-logic-tag")
454
- }, [x(f(ie), {
454
+ }, [x(f(ae), {
455
455
  size: 16,
456
456
  "stroke-width": 2
457
457
  }), y(" " + s(f(E).logicTag.insertShort), 1)], 8, Oe)], 64)) : d("", !0)
458
- ])], 64)) : (n(), u("div", ke, [x(f(ge), {
458
+ ])], 64)) : (n(), u("div", ke, [x(f(pe), {
459
459
  class: "tpl-spinner",
460
460
  size: 14,
461
461
  "stroke-width": 2
@@ -476,18 +476,18 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
476
476
  editorName: "ParagraphEditor",
477
477
  async loadExtensions({ mergeTags: e, syntax: t, triggerChar: n, autocompleteEnabled: r, suggestionEmptyText: i }) {
478
478
  let [{ Editor: a, EditorContent: s }, { default: c }, { default: l }, { default: u }, { default: d }, { default: f }, { default: p }, { TextStyle: m }, { default: h }, { default: g }, { default: _ }, { MergeTagNode: v, MergeTagSuggestion: y, LogicMergeTagNode: b, FontSize: x, LineHeight: S, LetterSpacing: C }] = await Promise.all([
479
- import("./tiptap-DUTbZTeR.js").then((e) => e.r),
480
- import("./tiptap-DUTbZTeR.js").then((e) => e.i),
481
- import("./tiptap-DUTbZTeR.js").then((e) => e.l),
482
- import("./tiptap-DUTbZTeR.js").then((e) => e.a),
483
- import("./tiptap-DUTbZTeR.js").then((e) => e.c),
484
- import("./tiptap-DUTbZTeR.js").then((e) => e.s),
485
- import("./tiptap-DUTbZTeR.js").then((e) => e.o),
486
- import("./tiptap-DUTbZTeR.js").then((e) => e.p),
487
- import("./tiptap-DUTbZTeR.js").then((e) => e.f),
488
- import("./tiptap-DUTbZTeR.js").then((e) => e.d),
489
- import("./tiptap-DUTbZTeR.js").then((e) => e.u),
490
- import("./extensions-C49c51P1.js")
479
+ import("./tiptap-DRKu__AX.js").then((e) => e.r),
480
+ import("./tiptap-DRKu__AX.js").then((e) => e.i),
481
+ import("./tiptap-DRKu__AX.js").then((e) => e.l),
482
+ import("./tiptap-DRKu__AX.js").then((e) => e.a),
483
+ import("./tiptap-DRKu__AX.js").then((e) => e.c),
484
+ import("./tiptap-DRKu__AX.js").then((e) => e.s),
485
+ import("./tiptap-DRKu__AX.js").then((e) => e.o),
486
+ import("./tiptap-DRKu__AX.js").then((e) => e.p),
487
+ import("./tiptap-DRKu__AX.js").then((e) => e.f),
488
+ import("./tiptap-DRKu__AX.js").then((e) => e.d),
489
+ import("./tiptap-DRKu__AX.js").then((e) => e.u),
490
+ import("./extensions-DBWF_lxx.js")
491
491
  ]);
492
492
  return {
493
493
  TiptapEditor: a,
@@ -597,4 +597,4 @@ var $ = ["data-tpl-theme", "aria-label"], Te = { class: "tpl:flex tpl:items-cent
597
597
  //#endregion
598
598
  export { Me as default };
599
599
 
600
- //# sourceMappingURL=ParagraphEditor-J-1RLyi7.js.map
600
+ //# sourceMappingURL=ParagraphEditor-CX1yks4N.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ParagraphEditor-J-1RLyi7.js","names":[],"sources":["../../../src/components/blocks/EmojiPickerDropdown.vue","../../../src/components/blocks/EmojiPickerDropdown.vue","../../../src/components/toolbar/ToolbarIconButton.vue","../../../src/components/toolbar/ToolbarIconButton.vue","../../../src/components/toolbar/ToolbarSeparator.vue","../../../src/components/toolbar/ToolbarSelect.vue","../../../src/components/toolbar/ToolbarSelect.vue","../../../src/utils/richTextColor.ts","../../../src/components/blocks/ParagraphToolbar.vue","../../../src/components/blocks/ParagraphToolbar.vue","../../../src/components/blocks/ParagraphEditor.vue","../../../src/components/blocks/ParagraphEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useEmoji, useI18n } from \"../../composables\";\nimport { useFocusTrap } from \"../../composables/useFocusTrap\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport { Smile } from \"@lucide/vue\";\nimport { computed, ref } from \"vue\";\n\nconst emit = defineEmits<{\n (e: \"insert\", emoji: string): void;\n}>();\n\nconst {\n categories: emojiCategories,\n isOpen: showEmojiPicker,\n toggle: toggleEmojiPicker,\n close: closeEmojiPicker,\n} = useEmoji();\n\nconst { t, format } = useI18n();\n\nconst pickerRef = ref<HTMLElement | null>(null);\nconst rootRef = ref<HTMLElement | null>(null);\n\nconst isOpenRef = computed(() => showEmojiPicker.value);\nuseFocusTrap(pickerRef, isOpenRef);\n\nonClickOutside(rootRef, () => {\n if (showEmojiPicker.value) {\n closeEmojiPicker();\n }\n});\n\nfunction handleInsert(emoji: string): void {\n emit(\"insert\", emoji);\n closeEmojiPicker();\n}\n</script>\n\n<template>\n <div ref=\"rootRef\" class=\"tpl:relative\">\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': showEmojiPicker,\n }\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n :title=\"t.paragraphEditor.insertEmoji\"\n :aria-expanded=\"showEmojiPicker\"\n aria-haspopup=\"dialog\"\n aria-controls=\"tpl-emoji-picker\"\n @click=\"toggleEmojiPicker\"\n >\n <Smile :size=\"16\" :stroke-width=\"2\" />\n </button>\n <div\n v-if=\"showEmojiPicker\"\n id=\"tpl-emoji-picker\"\n ref=\"pickerRef\"\n role=\"dialog\"\n aria-modal=\"false\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n tabindex=\"-1\"\n class=\"tpl-emoji-picker tpl:absolute tpl:top-full tpl:left-0 tpl:z-10 tpl:mt-2 tpl:w-72 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2 tpl:shadow-lg\"\n @keydown.esc.stop.prevent=\"closeEmojiPicker\"\n >\n <div\n v-for=\"category in emojiCategories\"\n :key=\"category.key\"\n class=\"tpl:mb-2 tpl:last:mb-0\"\n >\n <div\n class=\"tpl:mb-1.5 tpl:text-[10px] tpl:font-medium tpl:tracking-wide tpl:text-[var(--tpl-text-muted)] tpl:uppercase\"\n >\n {{ t.emoji[category.key] }}\n </div>\n <div class=\"tpl:grid tpl:grid-cols-10 tpl:gap-0.5\">\n <button\n v-for=\"emoji in category.emojis\"\n :key=\"emoji\"\n type=\"button\"\n :aria-label=\"format(t.paragraphEditor.emojiItemLabel, { emoji })\"\n class=\"tpl:flex tpl:size-6 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded tpl:border-none tpl:bg-transparent tpl:text-base tpl:transition-all tpl:duration-100 tpl:hover:scale-125 tpl:hover:bg-[var(--tpl-bg-active)]\"\n @click=\"handleInsert(emoji)\"\n >\n {{ emoji }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useEmoji, useI18n } from \"../../composables\";\nimport { useFocusTrap } from \"../../composables/useFocusTrap\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport { Smile } from \"@lucide/vue\";\nimport { computed, ref } from \"vue\";\n\nconst emit = defineEmits<{\n (e: \"insert\", emoji: string): void;\n}>();\n\nconst {\n categories: emojiCategories,\n isOpen: showEmojiPicker,\n toggle: toggleEmojiPicker,\n close: closeEmojiPicker,\n} = useEmoji();\n\nconst { t, format } = useI18n();\n\nconst pickerRef = ref<HTMLElement | null>(null);\nconst rootRef = ref<HTMLElement | null>(null);\n\nconst isOpenRef = computed(() => showEmojiPicker.value);\nuseFocusTrap(pickerRef, isOpenRef);\n\nonClickOutside(rootRef, () => {\n if (showEmojiPicker.value) {\n closeEmojiPicker();\n }\n});\n\nfunction handleInsert(emoji: string): void {\n emit(\"insert\", emoji);\n closeEmojiPicker();\n}\n</script>\n\n<template>\n <div ref=\"rootRef\" class=\"tpl:relative\">\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': showEmojiPicker,\n }\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n :title=\"t.paragraphEditor.insertEmoji\"\n :aria-expanded=\"showEmojiPicker\"\n aria-haspopup=\"dialog\"\n aria-controls=\"tpl-emoji-picker\"\n @click=\"toggleEmojiPicker\"\n >\n <Smile :size=\"16\" :stroke-width=\"2\" />\n </button>\n <div\n v-if=\"showEmojiPicker\"\n id=\"tpl-emoji-picker\"\n ref=\"pickerRef\"\n role=\"dialog\"\n aria-modal=\"false\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n tabindex=\"-1\"\n class=\"tpl-emoji-picker tpl:absolute tpl:top-full tpl:left-0 tpl:z-10 tpl:mt-2 tpl:w-72 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2 tpl:shadow-lg\"\n @keydown.esc.stop.prevent=\"closeEmojiPicker\"\n >\n <div\n v-for=\"category in emojiCategories\"\n :key=\"category.key\"\n class=\"tpl:mb-2 tpl:last:mb-0\"\n >\n <div\n class=\"tpl:mb-1.5 tpl:text-[10px] tpl:font-medium tpl:tracking-wide tpl:text-[var(--tpl-text-muted)] tpl:uppercase\"\n >\n {{ t.emoji[category.key] }}\n </div>\n <div class=\"tpl:grid tpl:grid-cols-10 tpl:gap-0.5\">\n <button\n v-for=\"emoji in category.emojis\"\n :key=\"emoji\"\n type=\"button\"\n :aria-label=\"format(t.paragraphEditor.emojiItemLabel, { emoji })\"\n class=\"tpl:flex tpl:size-6 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded tpl:border-none tpl:bg-transparent tpl:text-base tpl:transition-all tpl:duration-100 tpl:hover:scale-125 tpl:hover:bg-[var(--tpl-bg-active)]\"\n @click=\"handleInsert(emoji)\"\n >\n {{ emoji }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { Component } from \"vue\";\n\ndefineProps<{\n icon: Component;\n label: string;\n active?: boolean;\n strokeWidth?: number;\n size?: number;\n}>();\n</script>\n\n<template>\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{ 'tpl-text-toolbar-btn--active': active }\"\n :aria-label=\"label\"\n :title=\"label\"\n :aria-pressed=\"active ? 'true' : 'false'\"\n >\n <component :is=\"icon\" :size=\"size ?? 16\" :stroke-width=\"strokeWidth ?? 2\" />\n </button>\n</template>\n","<script setup lang=\"ts\">\nimport type { Component } from \"vue\";\n\ndefineProps<{\n icon: Component;\n label: string;\n active?: boolean;\n strokeWidth?: number;\n size?: number;\n}>();\n</script>\n\n<template>\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{ 'tpl-text-toolbar-btn--active': active }\"\n :aria-label=\"label\"\n :title=\"label\"\n :aria-pressed=\"active ? 'true' : 'false'\"\n >\n <component :is=\"icon\" :size=\"size ?? 16\" :stroke-width=\"strokeWidth ?? 2\" />\n </button>\n</template>\n","<template>\n <span\n class=\"tpl:mx-1 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n aria-hidden=\"true\"\n ></span>\n</template>\n","<script setup lang=\"ts\">\ninterface OptionItem {\n value: string;\n label: string;\n}\n\ndefineProps<{\n modelValue: string;\n options: readonly (string | OptionItem)[];\n label: string;\n placeholder?: string;\n widthClass?: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: string): void;\n}>();\n\nfunction onChange(e: Event): void {\n emit(\"update:modelValue\", (e.target as HTMLSelectElement).value);\n}\n\nfunction optionValue(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.value;\n}\n\nfunction optionLabel(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.label;\n}\n</script>\n\n<template>\n <select\n :class=\"[\n 'tpl:h-8 tpl:cursor-pointer tpl:rounded tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text)] tpl:outline-none',\n widthClass ?? 'tpl:w-20',\n ]\"\n :value=\"modelValue\"\n :aria-label=\"label\"\n :title=\"label\"\n @change=\"onChange\"\n >\n <option value=\"\">{{ placeholder ?? \"\" }}</option>\n <option\n v-for=\"opt in options\"\n :key=\"optionValue(opt)\"\n :value=\"optionValue(opt)\"\n >\n {{ optionLabel(opt) }}\n </option>\n </select>\n</template>\n","<script setup lang=\"ts\">\ninterface OptionItem {\n value: string;\n label: string;\n}\n\ndefineProps<{\n modelValue: string;\n options: readonly (string | OptionItem)[];\n label: string;\n placeholder?: string;\n widthClass?: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: string): void;\n}>();\n\nfunction onChange(e: Event): void {\n emit(\"update:modelValue\", (e.target as HTMLSelectElement).value);\n}\n\nfunction optionValue(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.value;\n}\n\nfunction optionLabel(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.label;\n}\n</script>\n\n<template>\n <select\n :class=\"[\n 'tpl:h-8 tpl:cursor-pointer tpl:rounded tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text)] tpl:outline-none',\n widthClass ?? 'tpl:w-20',\n ]\"\n :value=\"modelValue\"\n :aria-label=\"label\"\n :title=\"label\"\n @change=\"onChange\"\n >\n <option value=\"\">{{ placeholder ?? \"\" }}</option>\n <option\n v-for=\"opt in options\"\n :key=\"optionValue(opt)\"\n :value=\"optionValue(opt)\"\n >\n {{ optionLabel(opt) }}\n </option>\n </select>\n</template>\n","import { DEFAULT_TEXT_COLOR } from \"../constants/styleConstants\";\n\n/**\n * The color a rich-text selection actually renders as, for display in the\n * text-color control (issue #373).\n *\n * Priority: an explicit inline text-color mark on the selection wins; otherwise\n * the text inherits the document-level `textColor`; if that too is unset (older\n * content predating document text color), fall back to the built-in default.\n *\n * A native `<input type=\"color\">` can't represent \"no color\", so before this it\n * always painted a hard-coded `#000000` when no inline mark existed — which both\n * looked like an explicit choice and didn't even match the real inherited color\n * (`#1a1a1a`). Resolving the effective color keeps the swatch truthful: it shows\n * the color the text is actually rendered in, whatever level it comes from.\n */\nexport function resolveEffectiveTextColor(\n explicitColor: string,\n documentTextColor: string | undefined,\n): string {\n return explicitColor || documentTextColor || DEFAULT_TEXT_COLOR;\n}\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport EmojiPickerDropdown from \"./EmojiPickerDropdown.vue\";\nimport ToolbarIconButton from \"../toolbar/ToolbarIconButton.vue\";\nimport ToolbarSeparator from \"../toolbar/ToolbarSeparator.vue\";\nimport ToolbarSelect from \"../toolbar/ToolbarSelect.vue\";\nimport { useI18n } from \"../../composables\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { Editor } from \"@tiptap/core\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Italic,\n Braces,\n Link,\n List,\n ListOrdered,\n LoaderCircle,\n RemoveFormatting,\n ScanLine,\n Strikethrough,\n Subscript,\n Superscript,\n Underline,\n} from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n EDITOR_KEY,\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n FONTS_MANAGER_KEY,\n MERGE_TAG_PICKER_KEY,\n LOGIC_TAG_PICKER_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n DEFAULT_HIGHLIGHT_COLOR,\n FONT_SIZE_OPTIONS,\n LINE_HEIGHT_OPTIONS,\n LETTER_SPACING_OPTIONS,\n} from \"../../constants/styleConstants\";\nimport { resolveEffectiveTextColor } from \"../../utils/richTextColor\";\n\nconst props = defineProps<{\n editor: Editor | null;\n toolbarPosition: { top: number; left: number };\n isLoading: boolean;\n canRequestMergeTag: boolean;\n canInsertLogicTag: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"open-link-dialog\"): void;\n (e: \"add-merge-tag\"): void;\n (e: \"add-logic-tag\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\nconst fontsManager = requireInject(FONTS_MANAGER_KEY, \"ParagraphToolbar\");\nconst popoverRoot = usePopoverRoot();\n// Picker may be null in non-editor contexts (e.g. isolated component tests).\n// When it's provided AND open, hide the floating toolbar — leaving it\n// visible behind the modal is visually noisy and the toolbar's Tailwind\n// z-index utility doesn't compile reliably, so it can sometimes paint\n// over the modal backdrop.\nconst picker = inject(MERGE_TAG_PICKER_KEY, null);\nconst logicPicker = inject(LOGIC_TAG_PICKER_KEY, null);\n// Editor may be absent in isolated tests; used only to resolve the inherited\n// document text color for the text-color swatch.\nconst editorReturn = inject(EDITOR_KEY, null);\n// Hide the floating toolbar while either built-in picker modal is open, so it\n// doesn't overlap the dialog.\nconst pickerIsOpen = computed(\n () => (picker?.isOpen.value ?? false) || (logicPicker?.isOpen.value ?? false),\n);\n\nconst { t } = useI18n();\n\nconst fontFamilies = fontsManager.fonts;\n\nfunction insertEmoji(emoji: string): void {\n props.editor?.chain().focus().insertContent(emoji).run();\n}\n\nfunction textStyleAttr(attr: string): string {\n return (props.editor?.getAttributes(\"textStyle\")[attr] as string) || \"\";\n}\n\nfunction setFontFamily(family: string): void {\n const chain = props.editor?.chain().focus();\n if (family) chain?.setFontFamily(family).run();\n else chain?.unsetFontFamily().run();\n}\n\nfunction setFontSize(size: string): void {\n const chain = props.editor?.chain().focus();\n if (size) chain?.setFontSize(size).run();\n else chain?.unsetFontSize().run();\n}\n\n// When the selection is a link, the color control operates on the link itself\n// (its `color` attribute → inline on the `<a>`) so the link's text and underline\n// stay in sync; otherwise it applies a plain inline text-color mark.\nfunction isLinkSelection(): boolean {\n return props.editor?.isActive(\"link\") ?? false;\n}\n\nfunction linkColorAttr(): string {\n return (props.editor?.getAttributes(\"link\").color as string) || \"\";\n}\n\n// Set (or clear, when empty) the color of the current selection. On a link the\n// whole link is recolored (extendMarkRange) so it doesn't split into segments.\nfunction setColor(color: string): void {\n const chain = props.editor?.chain().focus();\n if (!chain) return;\n if (isLinkSelection()) {\n chain.extendMarkRange(\"link\").updateAttributes(\"link\", {\n color: color || null,\n });\n // A per-link color takes absolute priority over any inner text-color: strip\n // the inline text color on the link range so the `<a>` color alone drives\n // the glyphs and the underline (mirrors useRichTextLinkDialog.insertLink).\n // Only when setting a color — clearing leaves the text color untouched.\n if (color) chain.unsetColor();\n chain.run();\n } else if (color) {\n // A text color applied over a selection that includes a link unifies the\n // link with it: update the link's own color so the `<a>` (which paints the\n // underline and is what the dialog/toolbar read) matches the recolored\n // glyphs. A no-op on a selection with no link. Mirror of the link branch\n // above — either way a link never ends up with a text color fighting its\n // own color.\n chain.setColor(color).updateAttributes(\"link\", { color }).run();\n } else {\n chain.unsetColor().run();\n }\n}\n\n// The color the current selection actually renders in — a link's own color (else\n// the effective document link color: link color, then text color), or for plain\n// text the inline mark else the document text color. Keeps the swatch truthful\n// rather than showing a hard-coded default (issue #373 / per-link color).\nfunction effectiveTextColor(): string {\n const settings = editorReturn?.content.value.settings;\n if (isLinkSelection()) {\n return resolveEffectiveTextColor(\n linkColorAttr(),\n settings?.linkColor || settings?.textColor,\n );\n }\n return resolveEffectiveTextColor(textStyleAttr(\"color\"), settings?.textColor);\n}\n\n// The selection's own explicit color: a link's color when on a link, else the\n// inline text-color mark. May be \"\" when the selection only inherits its color\n// — that drives the swatch's set/unset state, while `effectiveTextColor()`\n// seeds the wheel so it still opens on the real rendered color.\nfunction explicitTextColor(): string {\n return isLinkSelection() ? linkColorAttr() : textStyleAttr(\"color\");\n}\n\nfunction getCurrentLineHeight(): string {\n return (props.editor?.getAttributes(\"paragraph\").lineHeight as string) || \"\";\n}\n\nfunction setLineHeight(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value) chain?.setLineHeight(value).run();\n else chain?.unsetLineHeight().run();\n}\n\nfunction setLetterSpacing(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value && value !== \"normal\") chain?.setLetterSpacing(value).run();\n else chain?.unsetLetterSpacing().run();\n}\n\nfunction getCurrentHighlight(): string {\n return (props.editor?.getAttributes(\"highlight\").color as string) || \"\";\n}\n\nfunction setHighlight(color: string): void {\n const chain = props.editor?.chain().focus();\n if (color) chain?.setHighlight({ color }).run();\n else chain?.unsetHighlight().run();\n}\n</script>\n\n<template>\n <Teleport v-if=\"popoverRoot && !pickerIsOpen\" :to=\"popoverRoot\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.paragraphEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:absolute tpl:z-popover tpl:flex tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n flexDirection: 'column',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Row 1: Font family, Font size, Text color, Bold/Italic/Underline/Strikethrough -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontFamily')\"\n :options=\"fontFamilies\"\n :label=\"t.paragraphEditor.fontFamily\"\n :placeholder=\"t.paragraphEditor.defaultFont\"\n width-class=\"tpl:w-32\"\n @update:model-value=\"setFontFamily\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontSize')\"\n :options=\"FONT_SIZE_OPTIONS\"\n :label=\"t.paragraphEditor.fontSize\"\n :placeholder=\"t.paragraphEditor.defaultSize\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setFontSize\"\n />\n <ToolbarSeparator />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"text-color-picker\"\n :model-value=\"explicitTextColor()\"\n :seed-color=\"effectiveTextColor()\"\n :aria-label=\"t.paragraphEditor.textColor\"\n @update:model-value=\"setColor\"\n />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"highlight-color-picker\"\n :model-value=\"getCurrentHighlight()\"\n :seed-color=\"DEFAULT_HIGHLIGHT_COLOR\"\n :aria-label=\"t.paragraphEditor.highlightColor\"\n @update:model-value=\"setHighlight\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Bold\"\n :label=\"t.paragraphEditor.bold\"\n :active=\"editor.isActive('bold')\"\n :stroke-width=\"2.5\"\n @click=\"editor.chain().focus().toggleBold().run()\"\n />\n <ToolbarIconButton\n :icon=\"Italic\"\n :label=\"t.paragraphEditor.italic\"\n :active=\"editor.isActive('italic')\"\n @click=\"editor.chain().focus().toggleItalic().run()\"\n />\n <ToolbarIconButton\n :icon=\"Underline\"\n :label=\"t.paragraphEditor.underline\"\n :active=\"editor.isActive('underline')\"\n @click=\"editor.chain().focus().toggleUnderline().run()\"\n />\n <ToolbarIconButton\n :icon=\"Strikethrough\"\n :label=\"t.paragraphEditor.strikethrough\"\n :active=\"editor.isActive('strike')\"\n @click=\"editor.chain().focus().toggleStrike().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Subscript\"\n :label=\"t.paragraphEditor.subscript\"\n :active=\"editor.isActive('subscript')\"\n @click=\"editor.chain().focus().toggleSubscript().run()\"\n />\n <ToolbarIconButton\n :icon=\"Superscript\"\n :label=\"t.paragraphEditor.superscript\"\n :active=\"editor.isActive('superscript')\"\n @click=\"editor.chain().focus().toggleSuperscript().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Link\"\n :label=\"t.paragraphEditor.addLink\"\n :active=\"editor.isActive('link')\"\n @click=\"emit('open-link-dialog')\"\n />\n </div>\n <!-- Row 2: Lists, Alignment, LH, LS, Clear, Emoji, Merge tags -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarIconButton\n :icon=\"List\"\n :label=\"t.paragraphEditor.bulletList\"\n :active=\"editor.isActive('bulletList')\"\n @click=\"editor.chain().focus().toggleBulletList().run()\"\n />\n <ToolbarIconButton\n :icon=\"ListOrdered\"\n :label=\"t.paragraphEditor.numberedList\"\n :active=\"editor.isActive('orderedList')\"\n @click=\"editor.chain().focus().toggleOrderedList().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"AlignLeft\"\n :label=\"t.paragraphEditor.alignLeft\"\n :active=\"editor.isActive({ textAlign: 'left' })\"\n @click=\"editor.chain().focus().setTextAlign('left').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignCenter\"\n :label=\"t.paragraphEditor.alignCenter\"\n :active=\"editor.isActive({ textAlign: 'center' })\"\n @click=\"editor.chain().focus().setTextAlign('center').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignRight\"\n :label=\"t.paragraphEditor.alignRight\"\n :active=\"editor.isActive({ textAlign: 'right' })\"\n @click=\"editor.chain().focus().setTextAlign('right').run()\"\n />\n <ToolbarSeparator />\n <ToolbarSelect\n :model-value=\"getCurrentLineHeight()\"\n :options=\"LINE_HEIGHT_OPTIONS\"\n :label=\"t.paragraphEditor.lineHeight\"\n placeholder=\"LH\"\n width-class=\"tpl:w-16\"\n @update:model-value=\"setLineHeight\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('letterSpacing')\"\n :options=\"LETTER_SPACING_OPTIONS\"\n :label=\"t.paragraphEditor.letterSpacing\"\n placeholder=\"LS\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setLetterSpacing\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"RemoveFormatting\"\n :label=\"t.paragraphEditor.clearFormatting\"\n @click=\"editor.chain().focus().clearNodes().unsetAllMarks().run()\"\n />\n <ToolbarSeparator />\n <EmojiPickerDropdown @insert=\"insertEmoji\" />\n <template v-if=\"canRequestMergeTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.insert\"\n :title=\"t.mergeTag.insert\"\n @click=\"emit('add-merge-tag')\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.insertShort }}\n </button>\n </template>\n <template v-if=\"canInsertLogicTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.logicTag.insert\"\n :title=\"t.logicTag.insert\"\n data-testid=\"insert-logic-button\"\n @click=\"emit('add-logic-tag')\"\n >\n <Braces :size=\"16\" :stroke-width=\"2\" />\n {{ t.logicTag.insertShort }}\n </button>\n </template>\n </div>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport EmojiPickerDropdown from \"./EmojiPickerDropdown.vue\";\nimport ToolbarIconButton from \"../toolbar/ToolbarIconButton.vue\";\nimport ToolbarSeparator from \"../toolbar/ToolbarSeparator.vue\";\nimport ToolbarSelect from \"../toolbar/ToolbarSelect.vue\";\nimport { useI18n } from \"../../composables\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { Editor } from \"@tiptap/core\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Italic,\n Braces,\n Link,\n List,\n ListOrdered,\n LoaderCircle,\n RemoveFormatting,\n ScanLine,\n Strikethrough,\n Subscript,\n Superscript,\n Underline,\n} from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n EDITOR_KEY,\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n FONTS_MANAGER_KEY,\n MERGE_TAG_PICKER_KEY,\n LOGIC_TAG_PICKER_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n DEFAULT_HIGHLIGHT_COLOR,\n FONT_SIZE_OPTIONS,\n LINE_HEIGHT_OPTIONS,\n LETTER_SPACING_OPTIONS,\n} from \"../../constants/styleConstants\";\nimport { resolveEffectiveTextColor } from \"../../utils/richTextColor\";\n\nconst props = defineProps<{\n editor: Editor | null;\n toolbarPosition: { top: number; left: number };\n isLoading: boolean;\n canRequestMergeTag: boolean;\n canInsertLogicTag: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"open-link-dialog\"): void;\n (e: \"add-merge-tag\"): void;\n (e: \"add-logic-tag\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\nconst fontsManager = requireInject(FONTS_MANAGER_KEY, \"ParagraphToolbar\");\nconst popoverRoot = usePopoverRoot();\n// Picker may be null in non-editor contexts (e.g. isolated component tests).\n// When it's provided AND open, hide the floating toolbar — leaving it\n// visible behind the modal is visually noisy and the toolbar's Tailwind\n// z-index utility doesn't compile reliably, so it can sometimes paint\n// over the modal backdrop.\nconst picker = inject(MERGE_TAG_PICKER_KEY, null);\nconst logicPicker = inject(LOGIC_TAG_PICKER_KEY, null);\n// Editor may be absent in isolated tests; used only to resolve the inherited\n// document text color for the text-color swatch.\nconst editorReturn = inject(EDITOR_KEY, null);\n// Hide the floating toolbar while either built-in picker modal is open, so it\n// doesn't overlap the dialog.\nconst pickerIsOpen = computed(\n () => (picker?.isOpen.value ?? false) || (logicPicker?.isOpen.value ?? false),\n);\n\nconst { t } = useI18n();\n\nconst fontFamilies = fontsManager.fonts;\n\nfunction insertEmoji(emoji: string): void {\n props.editor?.chain().focus().insertContent(emoji).run();\n}\n\nfunction textStyleAttr(attr: string): string {\n return (props.editor?.getAttributes(\"textStyle\")[attr] as string) || \"\";\n}\n\nfunction setFontFamily(family: string): void {\n const chain = props.editor?.chain().focus();\n if (family) chain?.setFontFamily(family).run();\n else chain?.unsetFontFamily().run();\n}\n\nfunction setFontSize(size: string): void {\n const chain = props.editor?.chain().focus();\n if (size) chain?.setFontSize(size).run();\n else chain?.unsetFontSize().run();\n}\n\n// When the selection is a link, the color control operates on the link itself\n// (its `color` attribute → inline on the `<a>`) so the link's text and underline\n// stay in sync; otherwise it applies a plain inline text-color mark.\nfunction isLinkSelection(): boolean {\n return props.editor?.isActive(\"link\") ?? false;\n}\n\nfunction linkColorAttr(): string {\n return (props.editor?.getAttributes(\"link\").color as string) || \"\";\n}\n\n// Set (or clear, when empty) the color of the current selection. On a link the\n// whole link is recolored (extendMarkRange) so it doesn't split into segments.\nfunction setColor(color: string): void {\n const chain = props.editor?.chain().focus();\n if (!chain) return;\n if (isLinkSelection()) {\n chain.extendMarkRange(\"link\").updateAttributes(\"link\", {\n color: color || null,\n });\n // A per-link color takes absolute priority over any inner text-color: strip\n // the inline text color on the link range so the `<a>` color alone drives\n // the glyphs and the underline (mirrors useRichTextLinkDialog.insertLink).\n // Only when setting a color — clearing leaves the text color untouched.\n if (color) chain.unsetColor();\n chain.run();\n } else if (color) {\n // A text color applied over a selection that includes a link unifies the\n // link with it: update the link's own color so the `<a>` (which paints the\n // underline and is what the dialog/toolbar read) matches the recolored\n // glyphs. A no-op on a selection with no link. Mirror of the link branch\n // above — either way a link never ends up with a text color fighting its\n // own color.\n chain.setColor(color).updateAttributes(\"link\", { color }).run();\n } else {\n chain.unsetColor().run();\n }\n}\n\n// The color the current selection actually renders in — a link's own color (else\n// the effective document link color: link color, then text color), or for plain\n// text the inline mark else the document text color. Keeps the swatch truthful\n// rather than showing a hard-coded default (issue #373 / per-link color).\nfunction effectiveTextColor(): string {\n const settings = editorReturn?.content.value.settings;\n if (isLinkSelection()) {\n return resolveEffectiveTextColor(\n linkColorAttr(),\n settings?.linkColor || settings?.textColor,\n );\n }\n return resolveEffectiveTextColor(textStyleAttr(\"color\"), settings?.textColor);\n}\n\n// The selection's own explicit color: a link's color when on a link, else the\n// inline text-color mark. May be \"\" when the selection only inherits its color\n// — that drives the swatch's set/unset state, while `effectiveTextColor()`\n// seeds the wheel so it still opens on the real rendered color.\nfunction explicitTextColor(): string {\n return isLinkSelection() ? linkColorAttr() : textStyleAttr(\"color\");\n}\n\nfunction getCurrentLineHeight(): string {\n return (props.editor?.getAttributes(\"paragraph\").lineHeight as string) || \"\";\n}\n\nfunction setLineHeight(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value) chain?.setLineHeight(value).run();\n else chain?.unsetLineHeight().run();\n}\n\nfunction setLetterSpacing(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value && value !== \"normal\") chain?.setLetterSpacing(value).run();\n else chain?.unsetLetterSpacing().run();\n}\n\nfunction getCurrentHighlight(): string {\n return (props.editor?.getAttributes(\"highlight\").color as string) || \"\";\n}\n\nfunction setHighlight(color: string): void {\n const chain = props.editor?.chain().focus();\n if (color) chain?.setHighlight({ color }).run();\n else chain?.unsetHighlight().run();\n}\n</script>\n\n<template>\n <Teleport v-if=\"popoverRoot && !pickerIsOpen\" :to=\"popoverRoot\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.paragraphEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:absolute tpl:z-popover tpl:flex tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n flexDirection: 'column',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Row 1: Font family, Font size, Text color, Bold/Italic/Underline/Strikethrough -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontFamily')\"\n :options=\"fontFamilies\"\n :label=\"t.paragraphEditor.fontFamily\"\n :placeholder=\"t.paragraphEditor.defaultFont\"\n width-class=\"tpl:w-32\"\n @update:model-value=\"setFontFamily\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontSize')\"\n :options=\"FONT_SIZE_OPTIONS\"\n :label=\"t.paragraphEditor.fontSize\"\n :placeholder=\"t.paragraphEditor.defaultSize\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setFontSize\"\n />\n <ToolbarSeparator />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"text-color-picker\"\n :model-value=\"explicitTextColor()\"\n :seed-color=\"effectiveTextColor()\"\n :aria-label=\"t.paragraphEditor.textColor\"\n @update:model-value=\"setColor\"\n />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"highlight-color-picker\"\n :model-value=\"getCurrentHighlight()\"\n :seed-color=\"DEFAULT_HIGHLIGHT_COLOR\"\n :aria-label=\"t.paragraphEditor.highlightColor\"\n @update:model-value=\"setHighlight\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Bold\"\n :label=\"t.paragraphEditor.bold\"\n :active=\"editor.isActive('bold')\"\n :stroke-width=\"2.5\"\n @click=\"editor.chain().focus().toggleBold().run()\"\n />\n <ToolbarIconButton\n :icon=\"Italic\"\n :label=\"t.paragraphEditor.italic\"\n :active=\"editor.isActive('italic')\"\n @click=\"editor.chain().focus().toggleItalic().run()\"\n />\n <ToolbarIconButton\n :icon=\"Underline\"\n :label=\"t.paragraphEditor.underline\"\n :active=\"editor.isActive('underline')\"\n @click=\"editor.chain().focus().toggleUnderline().run()\"\n />\n <ToolbarIconButton\n :icon=\"Strikethrough\"\n :label=\"t.paragraphEditor.strikethrough\"\n :active=\"editor.isActive('strike')\"\n @click=\"editor.chain().focus().toggleStrike().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Subscript\"\n :label=\"t.paragraphEditor.subscript\"\n :active=\"editor.isActive('subscript')\"\n @click=\"editor.chain().focus().toggleSubscript().run()\"\n />\n <ToolbarIconButton\n :icon=\"Superscript\"\n :label=\"t.paragraphEditor.superscript\"\n :active=\"editor.isActive('superscript')\"\n @click=\"editor.chain().focus().toggleSuperscript().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Link\"\n :label=\"t.paragraphEditor.addLink\"\n :active=\"editor.isActive('link')\"\n @click=\"emit('open-link-dialog')\"\n />\n </div>\n <!-- Row 2: Lists, Alignment, LH, LS, Clear, Emoji, Merge tags -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarIconButton\n :icon=\"List\"\n :label=\"t.paragraphEditor.bulletList\"\n :active=\"editor.isActive('bulletList')\"\n @click=\"editor.chain().focus().toggleBulletList().run()\"\n />\n <ToolbarIconButton\n :icon=\"ListOrdered\"\n :label=\"t.paragraphEditor.numberedList\"\n :active=\"editor.isActive('orderedList')\"\n @click=\"editor.chain().focus().toggleOrderedList().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"AlignLeft\"\n :label=\"t.paragraphEditor.alignLeft\"\n :active=\"editor.isActive({ textAlign: 'left' })\"\n @click=\"editor.chain().focus().setTextAlign('left').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignCenter\"\n :label=\"t.paragraphEditor.alignCenter\"\n :active=\"editor.isActive({ textAlign: 'center' })\"\n @click=\"editor.chain().focus().setTextAlign('center').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignRight\"\n :label=\"t.paragraphEditor.alignRight\"\n :active=\"editor.isActive({ textAlign: 'right' })\"\n @click=\"editor.chain().focus().setTextAlign('right').run()\"\n />\n <ToolbarSeparator />\n <ToolbarSelect\n :model-value=\"getCurrentLineHeight()\"\n :options=\"LINE_HEIGHT_OPTIONS\"\n :label=\"t.paragraphEditor.lineHeight\"\n placeholder=\"LH\"\n width-class=\"tpl:w-16\"\n @update:model-value=\"setLineHeight\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('letterSpacing')\"\n :options=\"LETTER_SPACING_OPTIONS\"\n :label=\"t.paragraphEditor.letterSpacing\"\n placeholder=\"LS\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setLetterSpacing\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"RemoveFormatting\"\n :label=\"t.paragraphEditor.clearFormatting\"\n @click=\"editor.chain().focus().clearNodes().unsetAllMarks().run()\"\n />\n <ToolbarSeparator />\n <EmojiPickerDropdown @insert=\"insertEmoji\" />\n <template v-if=\"canRequestMergeTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.insert\"\n :title=\"t.mergeTag.insert\"\n @click=\"emit('add-merge-tag')\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.insertShort }}\n </button>\n </template>\n <template v-if=\"canInsertLogicTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.logicTag.insert\"\n :title=\"t.logicTag.insert\"\n data-testid=\"insert-logic-button\"\n @click=\"emit('add-logic-tag')\"\n >\n <Braces :size=\"16\" :stroke-width=\"2\" />\n {{ t.logicTag.insertShort }}\n </button>\n </template>\n </div>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { ParagraphBlock as ParagraphBlockType } from \"@templatical/types\";\nimport ParagraphToolbar from \"./ParagraphToolbar.vue\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\nimport { withLinkColor } from \"../../utils/linkColorExtension\";\n\nconst props = defineProps<{\n block: ParagraphBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst popoverRoot = usePopoverRoot();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkColor,\n linkDialogRef,\n canRequestMergeTag,\n canInsertLogicTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n handleAddLogicTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"ParagraphEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { default: UnderlineExt },\n { default: SubscriptExt },\n { default: SuperscriptExt },\n { default: TextAlign },\n { TextStyle },\n { default: Color },\n { default: FontFamily },\n { default: Highlight },\n {\n MergeTagNode,\n MergeTagSuggestion,\n LogicMergeTagNode,\n FontSize,\n LineHeight,\n LetterSpacing,\n },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"@tiptap/extension-underline\"),\n import(\"@tiptap/extension-subscript\"),\n import(\"@tiptap/extension-superscript\"),\n import(\"@tiptap/extension-text-align\"),\n import(\"@tiptap/extension-text-style\"),\n import(\"@tiptap/extension-color\"),\n import(\"@tiptap/extension-font-family\"),\n import(\"@tiptap/extension-highlight\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n // StarterKit bundles @tiptap/extension-link (openOnClick: true).\n // Disable it so the LinkExt below (openOnClick: false) is the only\n // link extension — otherwise clicking a link while editing opens it.\n link: false,\n // StarterKit also bundles @tiptap/extension-underline; the editor\n // registers its own UnderlineExt below, so disable StarterKit's copy\n // to avoid a duplicate `underline` extension (and its console warning).\n underline: false,\n }),\n UnderlineExt,\n SubscriptExt,\n SuperscriptExt,\n withLinkColor(LinkExt).configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n TextAlign.configure({ types: [\"paragraph\"] }),\n TextStyle,\n Color,\n FontFamily,\n Highlight.configure({ multicolor: true }),\n FontSize,\n LineHeight,\n LetterSpacing,\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n popoverRoot,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <ParagraphToolbar\n :editor=\"editor\"\n :toolbar-position=\"toolbarPosition\"\n :is-loading=\"isLoading\"\n :can-request-merge-tag=\"canRequestMergeTag\"\n :can-insert-logic-tag=\"canInsertLogicTag\"\n @open-link-dialog=\"openLinkDialog\"\n @add-merge-tag=\"handleAddMergeTag\"\n @add-logic-tag=\"handleAddLogicTag\"\n />\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n v-model:link-color=\"linkColor\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { ParagraphBlock as ParagraphBlockType } from \"@templatical/types\";\nimport ParagraphToolbar from \"./ParagraphToolbar.vue\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\nimport { withLinkColor } from \"../../utils/linkColorExtension\";\n\nconst props = defineProps<{\n block: ParagraphBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst popoverRoot = usePopoverRoot();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkColor,\n linkDialogRef,\n canRequestMergeTag,\n canInsertLogicTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n handleAddLogicTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"ParagraphEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { default: UnderlineExt },\n { default: SubscriptExt },\n { default: SuperscriptExt },\n { default: TextAlign },\n { TextStyle },\n { default: Color },\n { default: FontFamily },\n { default: Highlight },\n {\n MergeTagNode,\n MergeTagSuggestion,\n LogicMergeTagNode,\n FontSize,\n LineHeight,\n LetterSpacing,\n },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"@tiptap/extension-underline\"),\n import(\"@tiptap/extension-subscript\"),\n import(\"@tiptap/extension-superscript\"),\n import(\"@tiptap/extension-text-align\"),\n import(\"@tiptap/extension-text-style\"),\n import(\"@tiptap/extension-color\"),\n import(\"@tiptap/extension-font-family\"),\n import(\"@tiptap/extension-highlight\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n // StarterKit bundles @tiptap/extension-link (openOnClick: true).\n // Disable it so the LinkExt below (openOnClick: false) is the only\n // link extension — otherwise clicking a link while editing opens it.\n link: false,\n // StarterKit also bundles @tiptap/extension-underline; the editor\n // registers its own UnderlineExt below, so disable StarterKit's copy\n // to avoid a duplicate `underline` extension (and its console warning).\n underline: false,\n }),\n UnderlineExt,\n SubscriptExt,\n SuperscriptExt,\n withLinkColor(LinkExt).configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n TextAlign.configure({ types: [\"paragraph\"] }),\n TextStyle,\n Color,\n FontFamily,\n Highlight.configure({ multicolor: true }),\n FontSize,\n LineHeight,\n LetterSpacing,\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n popoverRoot,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <ParagraphToolbar\n :editor=\"editor\"\n :toolbar-position=\"toolbarPosition\"\n :is-loading=\"isLoading\"\n :can-request-merge-tag=\"canRequestMergeTag\"\n :can-insert-logic-tag=\"canInsertLogicTag\"\n @open-link-dialog=\"openLinkDialog\"\n @add-merge-tag=\"handleAddMergeTag\"\n @add-logic-tag=\"handleAddLogicTag\"\n />\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n v-model:link-color=\"linkColor\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"ParagraphEditor-CX1yks4N.js","names":[],"sources":["../../../src/components/blocks/EmojiPickerDropdown.vue","../../../src/components/blocks/EmojiPickerDropdown.vue","../../../src/components/toolbar/ToolbarIconButton.vue","../../../src/components/toolbar/ToolbarIconButton.vue","../../../src/components/toolbar/ToolbarSeparator.vue","../../../src/components/toolbar/ToolbarSelect.vue","../../../src/components/toolbar/ToolbarSelect.vue","../../../src/utils/richTextColor.ts","../../../src/components/blocks/ParagraphToolbar.vue","../../../src/components/blocks/ParagraphToolbar.vue","../../../src/components/blocks/ParagraphEditor.vue","../../../src/components/blocks/ParagraphEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useEmoji, useI18n } from \"../../composables\";\nimport { useFocusTrap } from \"../../composables/useFocusTrap\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport { Smile } from \"@lucide/vue\";\nimport { computed, ref } from \"vue\";\n\nconst emit = defineEmits<{\n (e: \"insert\", emoji: string): void;\n}>();\n\nconst {\n categories: emojiCategories,\n isOpen: showEmojiPicker,\n toggle: toggleEmojiPicker,\n close: closeEmojiPicker,\n} = useEmoji();\n\nconst { t, format } = useI18n();\n\nconst pickerRef = ref<HTMLElement | null>(null);\nconst rootRef = ref<HTMLElement | null>(null);\n\nconst isOpenRef = computed(() => showEmojiPicker.value);\nuseFocusTrap(pickerRef, isOpenRef);\n\nonClickOutside(rootRef, () => {\n if (showEmojiPicker.value) {\n closeEmojiPicker();\n }\n});\n\nfunction handleInsert(emoji: string): void {\n emit(\"insert\", emoji);\n closeEmojiPicker();\n}\n</script>\n\n<template>\n <div ref=\"rootRef\" class=\"tpl:relative\">\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': showEmojiPicker,\n }\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n :title=\"t.paragraphEditor.insertEmoji\"\n :aria-expanded=\"showEmojiPicker\"\n aria-haspopup=\"dialog\"\n aria-controls=\"tpl-emoji-picker\"\n @click=\"toggleEmojiPicker\"\n >\n <Smile :size=\"16\" :stroke-width=\"2\" />\n </button>\n <div\n v-if=\"showEmojiPicker\"\n id=\"tpl-emoji-picker\"\n ref=\"pickerRef\"\n role=\"dialog\"\n aria-modal=\"false\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n tabindex=\"-1\"\n class=\"tpl-emoji-picker tpl:absolute tpl:top-full tpl:left-0 tpl:z-10 tpl:mt-2 tpl:w-72 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2 tpl:shadow-lg\"\n @keydown.esc.stop.prevent=\"closeEmojiPicker\"\n >\n <div\n v-for=\"category in emojiCategories\"\n :key=\"category.key\"\n class=\"tpl:mb-2 tpl:last:mb-0\"\n >\n <div\n class=\"tpl:mb-1.5 tpl:text-[10px] tpl:font-medium tpl:tracking-wide tpl:text-[var(--tpl-text-muted)] tpl:uppercase\"\n >\n {{ t.emoji[category.key] }}\n </div>\n <div class=\"tpl:grid tpl:grid-cols-10 tpl:gap-0.5\">\n <button\n v-for=\"emoji in category.emojis\"\n :key=\"emoji\"\n type=\"button\"\n :aria-label=\"format(t.paragraphEditor.emojiItemLabel, { emoji })\"\n class=\"tpl:flex tpl:size-6 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded tpl:border-none tpl:bg-transparent tpl:text-base tpl:transition-all tpl:duration-100 tpl:hover:scale-125 tpl:hover:bg-[var(--tpl-bg-active)]\"\n @click=\"handleInsert(emoji)\"\n >\n {{ emoji }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useEmoji, useI18n } from \"../../composables\";\nimport { useFocusTrap } from \"../../composables/useFocusTrap\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport { Smile } from \"@lucide/vue\";\nimport { computed, ref } from \"vue\";\n\nconst emit = defineEmits<{\n (e: \"insert\", emoji: string): void;\n}>();\n\nconst {\n categories: emojiCategories,\n isOpen: showEmojiPicker,\n toggle: toggleEmojiPicker,\n close: closeEmojiPicker,\n} = useEmoji();\n\nconst { t, format } = useI18n();\n\nconst pickerRef = ref<HTMLElement | null>(null);\nconst rootRef = ref<HTMLElement | null>(null);\n\nconst isOpenRef = computed(() => showEmojiPicker.value);\nuseFocusTrap(pickerRef, isOpenRef);\n\nonClickOutside(rootRef, () => {\n if (showEmojiPicker.value) {\n closeEmojiPicker();\n }\n});\n\nfunction handleInsert(emoji: string): void {\n emit(\"insert\", emoji);\n closeEmojiPicker();\n}\n</script>\n\n<template>\n <div ref=\"rootRef\" class=\"tpl:relative\">\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': showEmojiPicker,\n }\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n :title=\"t.paragraphEditor.insertEmoji\"\n :aria-expanded=\"showEmojiPicker\"\n aria-haspopup=\"dialog\"\n aria-controls=\"tpl-emoji-picker\"\n @click=\"toggleEmojiPicker\"\n >\n <Smile :size=\"16\" :stroke-width=\"2\" />\n </button>\n <div\n v-if=\"showEmojiPicker\"\n id=\"tpl-emoji-picker\"\n ref=\"pickerRef\"\n role=\"dialog\"\n aria-modal=\"false\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n tabindex=\"-1\"\n class=\"tpl-emoji-picker tpl:absolute tpl:top-full tpl:left-0 tpl:z-10 tpl:mt-2 tpl:w-72 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2 tpl:shadow-lg\"\n @keydown.esc.stop.prevent=\"closeEmojiPicker\"\n >\n <div\n v-for=\"category in emojiCategories\"\n :key=\"category.key\"\n class=\"tpl:mb-2 tpl:last:mb-0\"\n >\n <div\n class=\"tpl:mb-1.5 tpl:text-[10px] tpl:font-medium tpl:tracking-wide tpl:text-[var(--tpl-text-muted)] tpl:uppercase\"\n >\n {{ t.emoji[category.key] }}\n </div>\n <div class=\"tpl:grid tpl:grid-cols-10 tpl:gap-0.5\">\n <button\n v-for=\"emoji in category.emojis\"\n :key=\"emoji\"\n type=\"button\"\n :aria-label=\"format(t.paragraphEditor.emojiItemLabel, { emoji })\"\n class=\"tpl:flex tpl:size-6 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded tpl:border-none tpl:bg-transparent tpl:text-base tpl:transition-all tpl:duration-100 tpl:hover:scale-125 tpl:hover:bg-[var(--tpl-bg-active)]\"\n @click=\"handleInsert(emoji)\"\n >\n {{ emoji }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { Component } from \"vue\";\n\ndefineProps<{\n icon: Component;\n label: string;\n active?: boolean;\n strokeWidth?: number;\n size?: number;\n}>();\n</script>\n\n<template>\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{ 'tpl-text-toolbar-btn--active': active }\"\n :aria-label=\"label\"\n :title=\"label\"\n :aria-pressed=\"active ? 'true' : 'false'\"\n >\n <component :is=\"icon\" :size=\"size ?? 16\" :stroke-width=\"strokeWidth ?? 2\" />\n </button>\n</template>\n","<script setup lang=\"ts\">\nimport type { Component } from \"vue\";\n\ndefineProps<{\n icon: Component;\n label: string;\n active?: boolean;\n strokeWidth?: number;\n size?: number;\n}>();\n</script>\n\n<template>\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{ 'tpl-text-toolbar-btn--active': active }\"\n :aria-label=\"label\"\n :title=\"label\"\n :aria-pressed=\"active ? 'true' : 'false'\"\n >\n <component :is=\"icon\" :size=\"size ?? 16\" :stroke-width=\"strokeWidth ?? 2\" />\n </button>\n</template>\n","<template>\n <span\n class=\"tpl:mx-1 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n aria-hidden=\"true\"\n ></span>\n</template>\n","<script setup lang=\"ts\">\ninterface OptionItem {\n value: string;\n label: string;\n}\n\ndefineProps<{\n modelValue: string;\n options: readonly (string | OptionItem)[];\n label: string;\n placeholder?: string;\n widthClass?: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: string): void;\n}>();\n\nfunction onChange(e: Event): void {\n emit(\"update:modelValue\", (e.target as HTMLSelectElement).value);\n}\n\nfunction optionValue(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.value;\n}\n\nfunction optionLabel(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.label;\n}\n</script>\n\n<template>\n <select\n :class=\"[\n 'tpl:h-8 tpl:cursor-pointer tpl:rounded tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text)] tpl:outline-none',\n widthClass ?? 'tpl:w-20',\n ]\"\n :value=\"modelValue\"\n :aria-label=\"label\"\n :title=\"label\"\n @change=\"onChange\"\n >\n <option value=\"\">{{ placeholder ?? \"\" }}</option>\n <option\n v-for=\"opt in options\"\n :key=\"optionValue(opt)\"\n :value=\"optionValue(opt)\"\n >\n {{ optionLabel(opt) }}\n </option>\n </select>\n</template>\n","<script setup lang=\"ts\">\ninterface OptionItem {\n value: string;\n label: string;\n}\n\ndefineProps<{\n modelValue: string;\n options: readonly (string | OptionItem)[];\n label: string;\n placeholder?: string;\n widthClass?: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: string): void;\n}>();\n\nfunction onChange(e: Event): void {\n emit(\"update:modelValue\", (e.target as HTMLSelectElement).value);\n}\n\nfunction optionValue(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.value;\n}\n\nfunction optionLabel(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.label;\n}\n</script>\n\n<template>\n <select\n :class=\"[\n 'tpl:h-8 tpl:cursor-pointer tpl:rounded tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text)] tpl:outline-none',\n widthClass ?? 'tpl:w-20',\n ]\"\n :value=\"modelValue\"\n :aria-label=\"label\"\n :title=\"label\"\n @change=\"onChange\"\n >\n <option value=\"\">{{ placeholder ?? \"\" }}</option>\n <option\n v-for=\"opt in options\"\n :key=\"optionValue(opt)\"\n :value=\"optionValue(opt)\"\n >\n {{ optionLabel(opt) }}\n </option>\n </select>\n</template>\n","import { DEFAULT_TEXT_COLOR } from \"../constants/styleConstants\";\n\n/**\n * The color a rich-text selection actually renders as, for display in the\n * text-color control (issue #373).\n *\n * Priority: an explicit inline text-color mark on the selection wins; otherwise\n * the text inherits the document-level `textColor`; if that too is unset (older\n * content predating document text color), fall back to the built-in default.\n *\n * A native `<input type=\"color\">` can't represent \"no color\", so before this it\n * always painted a hard-coded `#000000` when no inline mark existed — which both\n * looked like an explicit choice and didn't even match the real inherited color\n * (`#1a1a1a`). Resolving the effective color keeps the swatch truthful: it shows\n * the color the text is actually rendered in, whatever level it comes from.\n */\nexport function resolveEffectiveTextColor(\n explicitColor: string,\n documentTextColor: string | undefined,\n): string {\n return explicitColor || documentTextColor || DEFAULT_TEXT_COLOR;\n}\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport EmojiPickerDropdown from \"./EmojiPickerDropdown.vue\";\nimport ToolbarIconButton from \"../toolbar/ToolbarIconButton.vue\";\nimport ToolbarSeparator from \"../toolbar/ToolbarSeparator.vue\";\nimport ToolbarSelect from \"../toolbar/ToolbarSelect.vue\";\nimport { useI18n } from \"../../composables\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { Editor } from \"@tiptap/core\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Italic,\n Braces,\n Link,\n List,\n ListOrdered,\n LoaderCircle,\n RemoveFormatting,\n ScanLine,\n Strikethrough,\n Subscript,\n Superscript,\n Underline,\n} from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n EDITOR_KEY,\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n FONTS_MANAGER_KEY,\n MERGE_TAG_PICKER_KEY,\n LOGIC_TAG_PICKER_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n DEFAULT_HIGHLIGHT_COLOR,\n FONT_SIZE_OPTIONS,\n LINE_HEIGHT_OPTIONS,\n LETTER_SPACING_OPTIONS,\n} from \"../../constants/styleConstants\";\nimport { resolveEffectiveTextColor } from \"../../utils/richTextColor\";\n\nconst props = defineProps<{\n editor: Editor | null;\n toolbarPosition: { top: number; left: number };\n isLoading: boolean;\n canRequestMergeTag: boolean;\n canInsertLogicTag: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"open-link-dialog\"): void;\n (e: \"add-merge-tag\"): void;\n (e: \"add-logic-tag\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\nconst fontsManager = requireInject(FONTS_MANAGER_KEY, \"ParagraphToolbar\");\nconst popoverRoot = usePopoverRoot();\n// Picker may be null in non-editor contexts (e.g. isolated component tests).\n// When it's provided AND open, hide the floating toolbar — leaving it\n// visible behind the modal is visually noisy and the toolbar's Tailwind\n// z-index utility doesn't compile reliably, so it can sometimes paint\n// over the modal backdrop.\nconst picker = inject(MERGE_TAG_PICKER_KEY, null);\nconst logicPicker = inject(LOGIC_TAG_PICKER_KEY, null);\n// Editor may be absent in isolated tests; used only to resolve the inherited\n// document text color for the text-color swatch.\nconst editorReturn = inject(EDITOR_KEY, null);\n// Hide the floating toolbar while either built-in picker modal is open, so it\n// doesn't overlap the dialog.\nconst pickerIsOpen = computed(\n () => (picker?.isOpen.value ?? false) || (logicPicker?.isOpen.value ?? false),\n);\n\nconst { t } = useI18n();\n\nconst fontFamilies = fontsManager.fonts;\n\nfunction insertEmoji(emoji: string): void {\n props.editor?.chain().focus().insertContent(emoji).run();\n}\n\nfunction textStyleAttr(attr: string): string {\n return (props.editor?.getAttributes(\"textStyle\")[attr] as string) || \"\";\n}\n\nfunction setFontFamily(family: string): void {\n const chain = props.editor?.chain().focus();\n if (family) chain?.setFontFamily(family).run();\n else chain?.unsetFontFamily().run();\n}\n\nfunction setFontSize(size: string): void {\n const chain = props.editor?.chain().focus();\n if (size) chain?.setFontSize(size).run();\n else chain?.unsetFontSize().run();\n}\n\n// When the selection is a link, the color control operates on the link itself\n// (its `color` attribute → inline on the `<a>`) so the link's text and underline\n// stay in sync; otherwise it applies a plain inline text-color mark.\nfunction isLinkSelection(): boolean {\n return props.editor?.isActive(\"link\") ?? false;\n}\n\nfunction linkColorAttr(): string {\n return (props.editor?.getAttributes(\"link\").color as string) || \"\";\n}\n\n// Set (or clear, when empty) the color of the current selection. On a link the\n// whole link is recolored (extendMarkRange) so it doesn't split into segments.\nfunction setColor(color: string): void {\n const chain = props.editor?.chain().focus();\n if (!chain) return;\n if (isLinkSelection()) {\n chain.extendMarkRange(\"link\").updateAttributes(\"link\", {\n color: color || null,\n });\n // A per-link color takes absolute priority over any inner text-color: strip\n // the inline text color on the link range so the `<a>` color alone drives\n // the glyphs and the underline (mirrors useRichTextLinkDialog.insertLink).\n // Only when setting a color — clearing leaves the text color untouched.\n if (color) chain.unsetColor();\n chain.run();\n } else if (color) {\n // A text color applied over a selection that includes a link unifies the\n // link with it: update the link's own color so the `<a>` (which paints the\n // underline and is what the dialog/toolbar read) matches the recolored\n // glyphs. A no-op on a selection with no link. Mirror of the link branch\n // above — either way a link never ends up with a text color fighting its\n // own color.\n chain.setColor(color).updateAttributes(\"link\", { color }).run();\n } else {\n chain.unsetColor().run();\n }\n}\n\n// The color the current selection actually renders in — a link's own color (else\n// the effective document link color: link color, then text color), or for plain\n// text the inline mark else the document text color. Keeps the swatch truthful\n// rather than showing a hard-coded default (issue #373 / per-link color).\nfunction effectiveTextColor(): string {\n const settings = editorReturn?.content.value.settings;\n if (isLinkSelection()) {\n return resolveEffectiveTextColor(\n linkColorAttr(),\n settings?.linkColor || settings?.textColor,\n );\n }\n return resolveEffectiveTextColor(textStyleAttr(\"color\"), settings?.textColor);\n}\n\n// The selection's own explicit color: a link's color when on a link, else the\n// inline text-color mark. May be \"\" when the selection only inherits its color\n// — that drives the swatch's set/unset state, while `effectiveTextColor()`\n// seeds the wheel so it still opens on the real rendered color.\nfunction explicitTextColor(): string {\n return isLinkSelection() ? linkColorAttr() : textStyleAttr(\"color\");\n}\n\nfunction getCurrentLineHeight(): string {\n return (props.editor?.getAttributes(\"paragraph\").lineHeight as string) || \"\";\n}\n\nfunction setLineHeight(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value) chain?.setLineHeight(value).run();\n else chain?.unsetLineHeight().run();\n}\n\nfunction setLetterSpacing(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value && value !== \"normal\") chain?.setLetterSpacing(value).run();\n else chain?.unsetLetterSpacing().run();\n}\n\nfunction getCurrentHighlight(): string {\n return (props.editor?.getAttributes(\"highlight\").color as string) || \"\";\n}\n\nfunction setHighlight(color: string): void {\n const chain = props.editor?.chain().focus();\n if (color) chain?.setHighlight({ color }).run();\n else chain?.unsetHighlight().run();\n}\n</script>\n\n<template>\n <Teleport v-if=\"popoverRoot && !pickerIsOpen\" :to=\"popoverRoot\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.paragraphEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:absolute tpl:z-popover tpl:flex tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n flexDirection: 'column',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Row 1: Font family, Font size, Text color, Bold/Italic/Underline/Strikethrough -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontFamily')\"\n :options=\"fontFamilies\"\n :label=\"t.paragraphEditor.fontFamily\"\n :placeholder=\"t.paragraphEditor.defaultFont\"\n width-class=\"tpl:w-32\"\n @update:model-value=\"setFontFamily\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontSize')\"\n :options=\"FONT_SIZE_OPTIONS\"\n :label=\"t.paragraphEditor.fontSize\"\n :placeholder=\"t.paragraphEditor.defaultSize\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setFontSize\"\n />\n <ToolbarSeparator />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"text-color-picker\"\n :model-value=\"explicitTextColor()\"\n :seed-color=\"effectiveTextColor()\"\n :aria-label=\"t.paragraphEditor.textColor\"\n @update:model-value=\"setColor\"\n />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"highlight-color-picker\"\n :model-value=\"getCurrentHighlight()\"\n :seed-color=\"DEFAULT_HIGHLIGHT_COLOR\"\n :aria-label=\"t.paragraphEditor.highlightColor\"\n @update:model-value=\"setHighlight\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Bold\"\n :label=\"t.paragraphEditor.bold\"\n :active=\"editor.isActive('bold')\"\n :stroke-width=\"2.5\"\n @click=\"editor.chain().focus().toggleBold().run()\"\n />\n <ToolbarIconButton\n :icon=\"Italic\"\n :label=\"t.paragraphEditor.italic\"\n :active=\"editor.isActive('italic')\"\n @click=\"editor.chain().focus().toggleItalic().run()\"\n />\n <ToolbarIconButton\n :icon=\"Underline\"\n :label=\"t.paragraphEditor.underline\"\n :active=\"editor.isActive('underline')\"\n @click=\"editor.chain().focus().toggleUnderline().run()\"\n />\n <ToolbarIconButton\n :icon=\"Strikethrough\"\n :label=\"t.paragraphEditor.strikethrough\"\n :active=\"editor.isActive('strike')\"\n @click=\"editor.chain().focus().toggleStrike().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Subscript\"\n :label=\"t.paragraphEditor.subscript\"\n :active=\"editor.isActive('subscript')\"\n @click=\"editor.chain().focus().toggleSubscript().run()\"\n />\n <ToolbarIconButton\n :icon=\"Superscript\"\n :label=\"t.paragraphEditor.superscript\"\n :active=\"editor.isActive('superscript')\"\n @click=\"editor.chain().focus().toggleSuperscript().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Link\"\n :label=\"t.paragraphEditor.addLink\"\n :active=\"editor.isActive('link')\"\n @click=\"emit('open-link-dialog')\"\n />\n </div>\n <!-- Row 2: Lists, Alignment, LH, LS, Clear, Emoji, Merge tags -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarIconButton\n :icon=\"List\"\n :label=\"t.paragraphEditor.bulletList\"\n :active=\"editor.isActive('bulletList')\"\n @click=\"editor.chain().focus().toggleBulletList().run()\"\n />\n <ToolbarIconButton\n :icon=\"ListOrdered\"\n :label=\"t.paragraphEditor.numberedList\"\n :active=\"editor.isActive('orderedList')\"\n @click=\"editor.chain().focus().toggleOrderedList().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"AlignLeft\"\n :label=\"t.paragraphEditor.alignLeft\"\n :active=\"editor.isActive({ textAlign: 'left' })\"\n @click=\"editor.chain().focus().setTextAlign('left').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignCenter\"\n :label=\"t.paragraphEditor.alignCenter\"\n :active=\"editor.isActive({ textAlign: 'center' })\"\n @click=\"editor.chain().focus().setTextAlign('center').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignRight\"\n :label=\"t.paragraphEditor.alignRight\"\n :active=\"editor.isActive({ textAlign: 'right' })\"\n @click=\"editor.chain().focus().setTextAlign('right').run()\"\n />\n <ToolbarSeparator />\n <ToolbarSelect\n :model-value=\"getCurrentLineHeight()\"\n :options=\"LINE_HEIGHT_OPTIONS\"\n :label=\"t.paragraphEditor.lineHeight\"\n placeholder=\"LH\"\n width-class=\"tpl:w-16\"\n @update:model-value=\"setLineHeight\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('letterSpacing')\"\n :options=\"LETTER_SPACING_OPTIONS\"\n :label=\"t.paragraphEditor.letterSpacing\"\n placeholder=\"LS\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setLetterSpacing\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"RemoveFormatting\"\n :label=\"t.paragraphEditor.clearFormatting\"\n @click=\"editor.chain().focus().clearNodes().unsetAllMarks().run()\"\n />\n <ToolbarSeparator />\n <EmojiPickerDropdown @insert=\"insertEmoji\" />\n <template v-if=\"canRequestMergeTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.insert\"\n :title=\"t.mergeTag.insert\"\n @click=\"emit('add-merge-tag')\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.insertShort }}\n </button>\n </template>\n <template v-if=\"canInsertLogicTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.logicTag.insert\"\n :title=\"t.logicTag.insert\"\n data-testid=\"insert-logic-button\"\n @click=\"emit('add-logic-tag')\"\n >\n <Braces :size=\"16\" :stroke-width=\"2\" />\n {{ t.logicTag.insertShort }}\n </button>\n </template>\n </div>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport EmojiPickerDropdown from \"./EmojiPickerDropdown.vue\";\nimport ToolbarIconButton from \"../toolbar/ToolbarIconButton.vue\";\nimport ToolbarSeparator from \"../toolbar/ToolbarSeparator.vue\";\nimport ToolbarSelect from \"../toolbar/ToolbarSelect.vue\";\nimport { useI18n } from \"../../composables\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { Editor } from \"@tiptap/core\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Italic,\n Braces,\n Link,\n List,\n ListOrdered,\n LoaderCircle,\n RemoveFormatting,\n ScanLine,\n Strikethrough,\n Subscript,\n Superscript,\n Underline,\n} from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n EDITOR_KEY,\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n FONTS_MANAGER_KEY,\n MERGE_TAG_PICKER_KEY,\n LOGIC_TAG_PICKER_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n DEFAULT_HIGHLIGHT_COLOR,\n FONT_SIZE_OPTIONS,\n LINE_HEIGHT_OPTIONS,\n LETTER_SPACING_OPTIONS,\n} from \"../../constants/styleConstants\";\nimport { resolveEffectiveTextColor } from \"../../utils/richTextColor\";\n\nconst props = defineProps<{\n editor: Editor | null;\n toolbarPosition: { top: number; left: number };\n isLoading: boolean;\n canRequestMergeTag: boolean;\n canInsertLogicTag: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"open-link-dialog\"): void;\n (e: \"add-merge-tag\"): void;\n (e: \"add-logic-tag\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\nconst fontsManager = requireInject(FONTS_MANAGER_KEY, \"ParagraphToolbar\");\nconst popoverRoot = usePopoverRoot();\n// Picker may be null in non-editor contexts (e.g. isolated component tests).\n// When it's provided AND open, hide the floating toolbar — leaving it\n// visible behind the modal is visually noisy and the toolbar's Tailwind\n// z-index utility doesn't compile reliably, so it can sometimes paint\n// over the modal backdrop.\nconst picker = inject(MERGE_TAG_PICKER_KEY, null);\nconst logicPicker = inject(LOGIC_TAG_PICKER_KEY, null);\n// Editor may be absent in isolated tests; used only to resolve the inherited\n// document text color for the text-color swatch.\nconst editorReturn = inject(EDITOR_KEY, null);\n// Hide the floating toolbar while either built-in picker modal is open, so it\n// doesn't overlap the dialog.\nconst pickerIsOpen = computed(\n () => (picker?.isOpen.value ?? false) || (logicPicker?.isOpen.value ?? false),\n);\n\nconst { t } = useI18n();\n\nconst fontFamilies = fontsManager.fonts;\n\nfunction insertEmoji(emoji: string): void {\n props.editor?.chain().focus().insertContent(emoji).run();\n}\n\nfunction textStyleAttr(attr: string): string {\n return (props.editor?.getAttributes(\"textStyle\")[attr] as string) || \"\";\n}\n\nfunction setFontFamily(family: string): void {\n const chain = props.editor?.chain().focus();\n if (family) chain?.setFontFamily(family).run();\n else chain?.unsetFontFamily().run();\n}\n\nfunction setFontSize(size: string): void {\n const chain = props.editor?.chain().focus();\n if (size) chain?.setFontSize(size).run();\n else chain?.unsetFontSize().run();\n}\n\n// When the selection is a link, the color control operates on the link itself\n// (its `color` attribute → inline on the `<a>`) so the link's text and underline\n// stay in sync; otherwise it applies a plain inline text-color mark.\nfunction isLinkSelection(): boolean {\n return props.editor?.isActive(\"link\") ?? false;\n}\n\nfunction linkColorAttr(): string {\n return (props.editor?.getAttributes(\"link\").color as string) || \"\";\n}\n\n// Set (or clear, when empty) the color of the current selection. On a link the\n// whole link is recolored (extendMarkRange) so it doesn't split into segments.\nfunction setColor(color: string): void {\n const chain = props.editor?.chain().focus();\n if (!chain) return;\n if (isLinkSelection()) {\n chain.extendMarkRange(\"link\").updateAttributes(\"link\", {\n color: color || null,\n });\n // A per-link color takes absolute priority over any inner text-color: strip\n // the inline text color on the link range so the `<a>` color alone drives\n // the glyphs and the underline (mirrors useRichTextLinkDialog.insertLink).\n // Only when setting a color — clearing leaves the text color untouched.\n if (color) chain.unsetColor();\n chain.run();\n } else if (color) {\n // A text color applied over a selection that includes a link unifies the\n // link with it: update the link's own color so the `<a>` (which paints the\n // underline and is what the dialog/toolbar read) matches the recolored\n // glyphs. A no-op on a selection with no link. Mirror of the link branch\n // above — either way a link never ends up with a text color fighting its\n // own color.\n chain.setColor(color).updateAttributes(\"link\", { color }).run();\n } else {\n chain.unsetColor().run();\n }\n}\n\n// The color the current selection actually renders in — a link's own color (else\n// the effective document link color: link color, then text color), or for plain\n// text the inline mark else the document text color. Keeps the swatch truthful\n// rather than showing a hard-coded default (issue #373 / per-link color).\nfunction effectiveTextColor(): string {\n const settings = editorReturn?.content.value.settings;\n if (isLinkSelection()) {\n return resolveEffectiveTextColor(\n linkColorAttr(),\n settings?.linkColor || settings?.textColor,\n );\n }\n return resolveEffectiveTextColor(textStyleAttr(\"color\"), settings?.textColor);\n}\n\n// The selection's own explicit color: a link's color when on a link, else the\n// inline text-color mark. May be \"\" when the selection only inherits its color\n// — that drives the swatch's set/unset state, while `effectiveTextColor()`\n// seeds the wheel so it still opens on the real rendered color.\nfunction explicitTextColor(): string {\n return isLinkSelection() ? linkColorAttr() : textStyleAttr(\"color\");\n}\n\nfunction getCurrentLineHeight(): string {\n return (props.editor?.getAttributes(\"paragraph\").lineHeight as string) || \"\";\n}\n\nfunction setLineHeight(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value) chain?.setLineHeight(value).run();\n else chain?.unsetLineHeight().run();\n}\n\nfunction setLetterSpacing(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value && value !== \"normal\") chain?.setLetterSpacing(value).run();\n else chain?.unsetLetterSpacing().run();\n}\n\nfunction getCurrentHighlight(): string {\n return (props.editor?.getAttributes(\"highlight\").color as string) || \"\";\n}\n\nfunction setHighlight(color: string): void {\n const chain = props.editor?.chain().focus();\n if (color) chain?.setHighlight({ color }).run();\n else chain?.unsetHighlight().run();\n}\n</script>\n\n<template>\n <Teleport v-if=\"popoverRoot && !pickerIsOpen\" :to=\"popoverRoot\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.paragraphEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:absolute tpl:z-popover tpl:flex tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n flexDirection: 'column',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Row 1: Font family, Font size, Text color, Bold/Italic/Underline/Strikethrough -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontFamily')\"\n :options=\"fontFamilies\"\n :label=\"t.paragraphEditor.fontFamily\"\n :placeholder=\"t.paragraphEditor.defaultFont\"\n width-class=\"tpl:w-32\"\n @update:model-value=\"setFontFamily\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontSize')\"\n :options=\"FONT_SIZE_OPTIONS\"\n :label=\"t.paragraphEditor.fontSize\"\n :placeholder=\"t.paragraphEditor.defaultSize\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setFontSize\"\n />\n <ToolbarSeparator />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"text-color-picker\"\n :model-value=\"explicitTextColor()\"\n :seed-color=\"effectiveTextColor()\"\n :aria-label=\"t.paragraphEditor.textColor\"\n @update:model-value=\"setColor\"\n />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"highlight-color-picker\"\n :model-value=\"getCurrentHighlight()\"\n :seed-color=\"DEFAULT_HIGHLIGHT_COLOR\"\n :aria-label=\"t.paragraphEditor.highlightColor\"\n @update:model-value=\"setHighlight\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Bold\"\n :label=\"t.paragraphEditor.bold\"\n :active=\"editor.isActive('bold')\"\n :stroke-width=\"2.5\"\n @click=\"editor.chain().focus().toggleBold().run()\"\n />\n <ToolbarIconButton\n :icon=\"Italic\"\n :label=\"t.paragraphEditor.italic\"\n :active=\"editor.isActive('italic')\"\n @click=\"editor.chain().focus().toggleItalic().run()\"\n />\n <ToolbarIconButton\n :icon=\"Underline\"\n :label=\"t.paragraphEditor.underline\"\n :active=\"editor.isActive('underline')\"\n @click=\"editor.chain().focus().toggleUnderline().run()\"\n />\n <ToolbarIconButton\n :icon=\"Strikethrough\"\n :label=\"t.paragraphEditor.strikethrough\"\n :active=\"editor.isActive('strike')\"\n @click=\"editor.chain().focus().toggleStrike().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Subscript\"\n :label=\"t.paragraphEditor.subscript\"\n :active=\"editor.isActive('subscript')\"\n @click=\"editor.chain().focus().toggleSubscript().run()\"\n />\n <ToolbarIconButton\n :icon=\"Superscript\"\n :label=\"t.paragraphEditor.superscript\"\n :active=\"editor.isActive('superscript')\"\n @click=\"editor.chain().focus().toggleSuperscript().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Link\"\n :label=\"t.paragraphEditor.addLink\"\n :active=\"editor.isActive('link')\"\n @click=\"emit('open-link-dialog')\"\n />\n </div>\n <!-- Row 2: Lists, Alignment, LH, LS, Clear, Emoji, Merge tags -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarIconButton\n :icon=\"List\"\n :label=\"t.paragraphEditor.bulletList\"\n :active=\"editor.isActive('bulletList')\"\n @click=\"editor.chain().focus().toggleBulletList().run()\"\n />\n <ToolbarIconButton\n :icon=\"ListOrdered\"\n :label=\"t.paragraphEditor.numberedList\"\n :active=\"editor.isActive('orderedList')\"\n @click=\"editor.chain().focus().toggleOrderedList().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"AlignLeft\"\n :label=\"t.paragraphEditor.alignLeft\"\n :active=\"editor.isActive({ textAlign: 'left' })\"\n @click=\"editor.chain().focus().setTextAlign('left').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignCenter\"\n :label=\"t.paragraphEditor.alignCenter\"\n :active=\"editor.isActive({ textAlign: 'center' })\"\n @click=\"editor.chain().focus().setTextAlign('center').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignRight\"\n :label=\"t.paragraphEditor.alignRight\"\n :active=\"editor.isActive({ textAlign: 'right' })\"\n @click=\"editor.chain().focus().setTextAlign('right').run()\"\n />\n <ToolbarSeparator />\n <ToolbarSelect\n :model-value=\"getCurrentLineHeight()\"\n :options=\"LINE_HEIGHT_OPTIONS\"\n :label=\"t.paragraphEditor.lineHeight\"\n placeholder=\"LH\"\n width-class=\"tpl:w-16\"\n @update:model-value=\"setLineHeight\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('letterSpacing')\"\n :options=\"LETTER_SPACING_OPTIONS\"\n :label=\"t.paragraphEditor.letterSpacing\"\n placeholder=\"LS\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setLetterSpacing\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"RemoveFormatting\"\n :label=\"t.paragraphEditor.clearFormatting\"\n @click=\"editor.chain().focus().clearNodes().unsetAllMarks().run()\"\n />\n <ToolbarSeparator />\n <EmojiPickerDropdown @insert=\"insertEmoji\" />\n <template v-if=\"canRequestMergeTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.insert\"\n :title=\"t.mergeTag.insert\"\n @click=\"emit('add-merge-tag')\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.insertShort }}\n </button>\n </template>\n <template v-if=\"canInsertLogicTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.logicTag.insert\"\n :title=\"t.logicTag.insert\"\n data-testid=\"insert-logic-button\"\n @click=\"emit('add-logic-tag')\"\n >\n <Braces :size=\"16\" :stroke-width=\"2\" />\n {{ t.logicTag.insertShort }}\n </button>\n </template>\n </div>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { ParagraphBlock as ParagraphBlockType } from \"@templatical/types\";\nimport ParagraphToolbar from \"./ParagraphToolbar.vue\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\nimport { withLinkColor } from \"../../utils/linkColorExtension\";\n\nconst props = defineProps<{\n block: ParagraphBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst popoverRoot = usePopoverRoot();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkColor,\n linkDialogRef,\n canRequestMergeTag,\n canInsertLogicTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n handleAddLogicTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"ParagraphEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { default: UnderlineExt },\n { default: SubscriptExt },\n { default: SuperscriptExt },\n { default: TextAlign },\n { TextStyle },\n { default: Color },\n { default: FontFamily },\n { default: Highlight },\n {\n MergeTagNode,\n MergeTagSuggestion,\n LogicMergeTagNode,\n FontSize,\n LineHeight,\n LetterSpacing,\n },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"@tiptap/extension-underline\"),\n import(\"@tiptap/extension-subscript\"),\n import(\"@tiptap/extension-superscript\"),\n import(\"@tiptap/extension-text-align\"),\n import(\"@tiptap/extension-text-style\"),\n import(\"@tiptap/extension-color\"),\n import(\"@tiptap/extension-font-family\"),\n import(\"@tiptap/extension-highlight\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n // StarterKit bundles @tiptap/extension-link (openOnClick: true).\n // Disable it so the LinkExt below (openOnClick: false) is the only\n // link extension — otherwise clicking a link while editing opens it.\n link: false,\n // StarterKit also bundles @tiptap/extension-underline; the editor\n // registers its own UnderlineExt below, so disable StarterKit's copy\n // to avoid a duplicate `underline` extension (and its console warning).\n underline: false,\n }),\n UnderlineExt,\n SubscriptExt,\n SuperscriptExt,\n withLinkColor(LinkExt).configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n TextAlign.configure({ types: [\"paragraph\"] }),\n TextStyle,\n Color,\n FontFamily,\n Highlight.configure({ multicolor: true }),\n FontSize,\n LineHeight,\n LetterSpacing,\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n popoverRoot,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <ParagraphToolbar\n :editor=\"editor\"\n :toolbar-position=\"toolbarPosition\"\n :is-loading=\"isLoading\"\n :can-request-merge-tag=\"canRequestMergeTag\"\n :can-insert-logic-tag=\"canInsertLogicTag\"\n @open-link-dialog=\"openLinkDialog\"\n @add-merge-tag=\"handleAddMergeTag\"\n @add-logic-tag=\"handleAddLogicTag\"\n />\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n v-model:link-color=\"linkColor\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { ParagraphBlock as ParagraphBlockType } from \"@templatical/types\";\nimport ParagraphToolbar from \"./ParagraphToolbar.vue\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\nimport { withLinkColor } from \"../../utils/linkColorExtension\";\n\nconst props = defineProps<{\n block: ParagraphBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst popoverRoot = usePopoverRoot();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkColor,\n linkDialogRef,\n canRequestMergeTag,\n canInsertLogicTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n handleAddLogicTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"ParagraphEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { default: UnderlineExt },\n { default: SubscriptExt },\n { default: SuperscriptExt },\n { default: TextAlign },\n { TextStyle },\n { default: Color },\n { default: FontFamily },\n { default: Highlight },\n {\n MergeTagNode,\n MergeTagSuggestion,\n LogicMergeTagNode,\n FontSize,\n LineHeight,\n LetterSpacing,\n },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"@tiptap/extension-underline\"),\n import(\"@tiptap/extension-subscript\"),\n import(\"@tiptap/extension-superscript\"),\n import(\"@tiptap/extension-text-align\"),\n import(\"@tiptap/extension-text-style\"),\n import(\"@tiptap/extension-color\"),\n import(\"@tiptap/extension-font-family\"),\n import(\"@tiptap/extension-highlight\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n // StarterKit bundles @tiptap/extension-link (openOnClick: true).\n // Disable it so the LinkExt below (openOnClick: false) is the only\n // link extension — otherwise clicking a link while editing opens it.\n link: false,\n // StarterKit also bundles @tiptap/extension-underline; the editor\n // registers its own UnderlineExt below, so disable StarterKit's copy\n // to avoid a duplicate `underline` extension (and its console warning).\n underline: false,\n }),\n UnderlineExt,\n SubscriptExt,\n SuperscriptExt,\n withLinkColor(LinkExt).configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n TextAlign.configure({ types: [\"paragraph\"] }),\n TextStyle,\n Color,\n FontFamily,\n Highlight.configure({ multicolor: true }),\n FontSize,\n LineHeight,\n LetterSpacing,\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n popoverRoot,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <ParagraphToolbar\n :editor=\"editor\"\n :toolbar-position=\"toolbarPosition\"\n :is-loading=\"isLoading\"\n :can-request-merge-tag=\"canRequestMergeTag\"\n :can-insert-logic-tag=\"canInsertLogicTag\"\n @open-link-dialog=\"openLinkDialog\"\n @add-merge-tag=\"handleAddMergeTag\"\n @add-logic-tag=\"handleAddLogicTag\"\n />\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n v-model:link-color=\"linkColor\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { E as e, H as t, L as n, M as r, R as i, T as a, ct as o, d as s, f as c, g as l, h as u, it as d, l as f, m as p, o as m, p as h, st as g, v as _, x as v, y } from "./draggable-D840DIZB.js";
2
- import { L as b, h as x, z as S } from "./keys-D7kUmfpE.js";
3
- import { t as C } from "./useI18n-8Wd7G-cq.js";
4
- import { n as w } from "./usePopoverPosition-Bx0QewTv.js";
5
- import { n as T } from "./icons-CYWw8Xfp.js";
6
- import { t as E } from "./ColorPicker-DZSzZ5ZP.js";
2
+ import { B as b, R as x, h as S } from "./keys-B5uoP9P7.js";
3
+ import { t as C } from "./useI18n-graz19nI.js";
4
+ import { n as w } from "./usePopoverPosition-BaFxLP3w.js";
5
+ import { n as T } from "./icons-Cqxvwgz7.js";
6
+ import { t as E } from "./ColorPicker-BckwEfcN.js";
7
7
  //#region src/components/blocks/RichTextLinkDialog.vue?vue&type=script&setup=true&lang.ts
8
8
  var D = ["data-tpl-theme"], O = { class: "tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-5 tpl:py-4" }, k = {
9
9
  id: "tpl-link-dialog-title",
@@ -35,7 +35,7 @@ var D = ["data-tpl-theme"], O = { class: "tpl:flex tpl:items-center tpl:justify-
35
35
  "update:dialogRef"
36
36
  ]),
37
37
  setup(e, { emit: n }) {
38
- let _ = i(e, "linkUrl"), v = i(e, "linkColor"), z = i(e, "dialogRef"), B = n, V = a(b, null), H = a(S, null), U = w(), W = a(x, null), G = c(() => W?.content.value.settings.linkColor || "#2c85de"), { t: K } = C();
38
+ let _ = i(e, "linkUrl"), v = i(e, "linkColor"), z = i(e, "dialogRef"), B = n, V = a(x, null), H = a(b, null), U = w(), W = a(S, null), G = c(() => W?.content.value.settings.linkColor || "#2c85de"), { t: K } = C();
39
39
  return (n, i) => d(U) ? (r(), p(s, {
40
40
  key: 0,
41
41
  to: d(U)
@@ -120,4 +120,4 @@ var D = ["data-tpl-theme"], O = { class: "tpl:flex tpl:items-center tpl:justify-
120
120
  //#endregion
121
121
  export { z as n, U as t };
122
122
 
123
- //# sourceMappingURL=RichTextEditorContent-BbdgJqWM.js.map
123
+ //# sourceMappingURL=RichTextEditorContent-z9s7qxs3.js.map