@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 +1 @@
1
- {"version":3,"file":"es-sQ9SdI0l.js","names":[],"sources":["../../../src/i18n/locales/es.ts"],"sourcesContent":["import type en from \"./en\";\n\nconst es: typeof en = {\n // Footer (OSS only)\n footer: {\n poweredBy: \"Con la tecnología de\",\n openSource: \"Código abierto\",\n },\n\n // History (undo/redo)\n history: {\n undo: \"Deshacer\",\n redo: \"Rehacer\",\n collabWarning:\n \"Deshacer puede afectar a los cambios recientes de los colaboradores\",\n },\n\n // Viewport toggle\n viewport: {\n label: \"Área de visualización\",\n desktop: \"Escritorio\",\n mobile: \"Móvil\",\n },\n\n // Dark mode preview\n darkMode: {\n enable: \"Vista previa en modo oscuro\",\n disable: \"Vista previa en modo claro\",\n },\n\n // Preview mode\n previewMode: {\n enable: \"Modo vista previa\",\n disable: \"Salir de la vista previa\",\n },\n\n // Sidebar - Block types\n blocks: {\n section: \"Sección\",\n image: \"Imagen\",\n title: \"Título\",\n paragraph: \"Párrafo\",\n button: \"Botón\",\n divider: \"Divisor\",\n video: \"Vídeo\",\n social: \"Redes sociales\",\n spacer: \"Espaciador\",\n html: \"HTML\",\n menu: \"Menú\",\n table: \"Tabla\",\n countdown: \"Cuenta atrás\",\n },\n\n // Right sidebar\n sidebar: {\n content: \"Contenido\",\n settings: \"Configuración\",\n noSelection: \"Ningún elemento seleccionado\",\n noSelectionHint: \"Selecciona un bloque en el lienzo para editarlo\",\n },\n\n // Toolbar - Common\n toolbar: {\n duplicate: \"Duplicar\",\n delete: \"Eliminar\",\n },\n\n // Title editor toolbar\n titleEditor: {\n toolbar: \"Formato del título\",\n bold: \"Negrita (Ctrl+B)\",\n italic: \"Cursiva (Ctrl+I)\",\n addLink: \"Añadir enlace\",\n },\n\n // Paragraph editor toolbar\n paragraphEditor: {\n toolbar: \"Formato del texto\",\n bold: \"Negrita (Ctrl+B)\",\n italic: \"Cursiva (Ctrl+I)\",\n underline: \"Subrayado (Ctrl+U)\",\n strikethrough: \"Tachado\",\n subscript: \"Subíndice\",\n superscript: \"Superíndice\",\n addLink: \"Añadir enlace\",\n bulletList: \"Lista con viñetas\",\n numberedList: \"Lista numerada\",\n alignLeft: \"Alinear a la izquierda\",\n alignCenter: \"Alinear al centro\",\n alignRight: \"Alinear a la derecha\",\n clearFormatting: \"Borrar formato\",\n insertEmoji: \"Insertar emoji\",\n fontFamily: \"Familia tipográfica\",\n defaultFont: \"Por defecto\",\n fontSize: \"Tamaño de fuente\",\n defaultSize: \"Por defecto\",\n textColor: \"Color del texto\",\n highlightColor: \"Color de resaltado\",\n lineHeight: \"Interlineado\",\n letterSpacing: \"Espaciado entre letras\",\n emojiItemLabel: \"Insertar emoji {emoji}\",\n closeEmojiPicker: \"Cerrar selector de emojis\",\n },\n\n // Block actions (BlockWrapper)\n blockActions: {\n drag: \"Arrastra para reordenar o pulsa Espacio para mover con el teclado\",\n dragLifted:\n \"Moviendo {block}. Usa las flechas arriba y abajo para reposicionar, Espacio o Intro para soltar, Esc para cancelar.\",\n duplicate: \"Duplicar bloque\",\n delete: \"Eliminar bloque\",\n hiddenOnViewport: \"Oculto en {viewport}\",\n saveAsBlock: \"Guardar como bloque\",\n conditionToggle: \"Alternar condición de visualización\",\n comments: \"Comentarios ({count})\",\n lifted: \"{block} levantado. Posición {position} de {total}.\",\n moved: \"{block} movido a la posición {position} de {total}.\",\n dropped: \"{block} soltado en la posición {position} de {total}.\",\n cancelled: \"Movimiento cancelado. {block} volvió a la posición {position}.\",\n },\n\n // Toolbar - Section\n section: {\n dropHere: \"Suelta los bloques aquí\",\n columns: \"Columnas\",\n column1: \"1 columna\",\n column2: \"2 columnas\",\n column3: \"3 columnas\",\n ratio12: \"Proporción 1:2\",\n ratio21: \"Proporción 2:1\",\n borderRadius: \"Radio del borde\",\n wrapperEnable: \"Añadir contenedor\",\n stackOnMobile: \"Apilar en móvil\",\n },\n\n // Text editor link dialog\n linkDialog: {\n editLink: \"Editar enlace\",\n insertLink: \"Insertar enlace\",\n updateLink: \"Actualizar enlace\",\n removeLink: \"Eliminar enlace\",\n cancel: \"Cancelar\",\n urlPlaceholder: \"https://example.com\",\n urlLabel: \"URL\",\n colorLabel: \"Color del enlace\",\n },\n\n // Toolbar - Title\n title: {\n level: \"Nivel de encabezado\",\n heading1: \"Encabezado 1 (36px)\",\n heading2: \"Encabezado 2 (28px)\",\n heading3: \"Encabezado 3 (22px)\",\n heading4: \"Encabezado 4 (18px)\",\n fontFamily: \"Familia tipográfica\",\n inheritFont: \"Usar fuente de la plantilla\",\n color: \"Color\",\n align: \"Alineación\",\n alignLeft: \"Izquierda\",\n alignCenter: \"Centro\",\n alignRight: \"Derecha\",\n },\n\n // Emoji picker\n emoji: {\n smileys: \"Emoticonos\",\n gestures: \"Gestos\",\n objects: \"Objetos\",\n },\n\n // Toolbar - Image\n image: {\n imageUrl: \"URL de la imagen\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Texto alternativo\",\n altTextPlaceholder: \"Descripción de la imagen\",\n width: \"Ancho\",\n fullWidth: \"Ancho completo\",\n widthCustom: \"Personalizado\",\n linkUrl: \"URL del enlace\",\n openInNewTab: \"Abrir en una nueva pestaña\",\n placeholderUrl: \"Imagen de muestra\",\n placeholderUrlPlaceholder: \"https://... (solo para diseño)\",\n placeholderUrlTooltip:\n \"Dado que la URL de la imagen utiliza una etiqueta de combinación, puedes proporcionar una imagen real aquí para previsualizar el diseño mientras diseñas. Esto no se incluirá en el resultado final.\",\n clickToAdd: \"Haz clic para añadir la URL de la imagen\",\n browseMedia: \"Explorar archivos multimedia\",\n dropToUpload: \"Suelta la imagen para subirla\",\n uploading: \"Subiendo...\",\n decorative: \"Imagen decorativa\",\n decorativeHint:\n \"Oculto para los lectores de pantalla. Utilízalo solo para espaciadores y adornos visuales.\",\n },\n\n // Toolbar - Video\n video: {\n videoUrl: \"URL del vídeo\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n youtube: \"YouTube\",\n vimeo: \"Vimeo\",\n detected: \"Vídeo detectado: la miniatura se generará automáticamente\",\n openInNewTab: \"Abrir en una nueva pestaña\",\n customThumbnail: \"Miniatura personalizada\",\n optional: \"(opcional)\",\n thumbnailPlaceholder: \"Generada automáticamente desde la URL del vídeo\",\n altText: \"Texto alternativo\",\n altTextPlaceholder: \"Descripción del vídeo\",\n width: \"Ancho\",\n fullWidth: \"Ancho completo\",\n placeholderUrl: \"Miniatura de muestra\",\n placeholderUrlPlaceholder: \"https://... (solo para diseño)\",\n placeholderUrlTooltip:\n \"Dado que la URL del vídeo utiliza una etiqueta de combinación, puedes proporcionar una miniatura real aquí para previsualizar el diseño mientras diseñas. Esto no se incluirá en el resultado final.\",\n addVideo: \"Añadir una URL de vídeo\",\n },\n\n // Toolbar - Button\n button: {\n fontFamily: \"Familia tipográfica\",\n inheritFont: \"Usar fuente de la plantilla\",\n text: \"Texto\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"Abrir en una nueva pestaña\",\n background: \"Fondo\",\n textColor: \"Color del texto\",\n borderRadius: \"Radio del borde\",\n fontSize: \"Tamaño de fuente\",\n width: \"Ancho\",\n widthAuto: \"Ajustar al contenido\",\n fullWidth: \"Ancho completo\",\n widthCustom: \"Personalizado\",\n },\n\n // Toolbar - Divider\n divider: {\n style: \"Estilo\",\n solid: \"Sólido\",\n dashed: \"Discontinuo\",\n dotted: \"Punteado\",\n color: \"Color\",\n thickness: \"Grosor\",\n },\n\n // Toolbar - Social Icons\n social: {\n icons: \"Iconos\",\n addIcon: \"Añadir icono\",\n addIcons: \"Añadir iconos de redes sociales\",\n removeIcon: \"Eliminar\",\n platform: \"Plataforma\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n style: \"Estilo\",\n styleSolid: \"Sólido\",\n styleOutlined: \"Contorneado\",\n styleRounded: \"Redondeado\",\n styleSquare: \"Cuadrado\",\n styleCircle: \"Círculo\",\n size: \"Tamaño\",\n sizeSmall: \"S\",\n sizeMedium: \"M\",\n sizeLarge: \"L\",\n spacing: \"Espaciado\",\n align: \"Alineación\",\n platforms: {\n facebook: \"Facebook\",\n twitter: \"X (Twitter)\",\n instagram: \"Instagram\",\n linkedin: \"LinkedIn\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n pinterest: \"Pinterest\",\n email: \"Correo electrónico\",\n website: \"Sitio web\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n\n // Toolbar - Menu\n menu: {\n items: \"Elementos del menú\",\n addItem: \"Añadir elemento\",\n removeItem: \"Eliminar\",\n text: \"Texto\",\n url: \"URL\",\n urlPlaceholder: \"https://example.com\",\n openInNewTab: \"Abrir en una nueva pestaña\",\n bold: \"Negrita\",\n underline: \"Subrayado\",\n color: \"Color\",\n linkColor: \"Color del enlace\",\n fontSize: \"Tamaño de fuente\",\n fontFamily: \"Familia tipográfica\",\n separator: \"Separador\",\n separatorColor: \"Color del separador\",\n spacing: \"Espaciado\",\n textAlign: \"Alineación\",\n addLinks: \"Añadir enlaces al menú\",\n },\n\n // Toolbar - Table\n table: {\n dimensions: \"Dimensiones\",\n rows: \"Filas\",\n columns: \"Columnas\",\n addRow: \"Añadir fila\",\n removeRow: \"Eliminar fila\",\n addColumn: \"Añadir columna\",\n removeColumn: \"Eliminar columna\",\n hasHeaderRow: \"Fila de encabezado\",\n headerBackgroundColor: \"Fondo del encabezado\",\n noHeaderBg: \"Sin fondo\",\n borderColor: \"Color del borde\",\n borderWidth: \"Grosor del borde\",\n cellPadding: \"Relleno de la celda\",\n fontFamily: \"Familia tipográfica\",\n fontSize: \"Tamaño de fuente\",\n color: \"Color del texto\",\n textAlign: \"Alineación\",\n cellPlaceholder: \"Introduce el texto...\",\n empty: \"Añadir una tabla\",\n },\n\n // Toolbar - Spacer\n spacer: {\n height: \"Altura\",\n },\n\n // Toolbar - Countdown\n countdown: {\n targetDate: \"Fecha límite\",\n timezone: \"Zona horaria\",\n display: \"Visualización\",\n days: \"Días\",\n hours: \"Horas\",\n minutes: \"Minutos\",\n seconds: \"Segundos\",\n separator: \"Separador\",\n fontFamily: \"Familia tipográfica\",\n inheritFont: \"Por defecto\",\n digitFontSize: \"Tamaño de los dígitos\",\n digitColor: \"Color de los dígitos\",\n labelColor: \"Color de la etiqueta\",\n labelFontSize: \"Tamaño de la etiqueta\",\n background: \"Fondo\",\n labels: \"Etiquetas\",\n expiry: \"Mensaje de expiración\",\n expiredMessagePlaceholder: \"Esta oferta ha expirado\",\n expiredImageUrl: \"URL de la imagen caducada\",\n hideOnExpiry: \"Ocultar al expirar\",\n setDate: \"Establece una fecha límite en el panel de configuración\",\n hidden: \"Oculto (expirado)\",\n },\n\n // Custom Blocks\n customBlocks: {\n definitionNotFound:\n \"Tipo de bloque desconocido: este bloque no está registrado\",\n renderError:\n \"No se pudo renderizar este bloque. Comprueba si hay errores en la plantilla del bloque.\",\n fields: {\n required: \"Obligatorio\",\n addItem: \"Añadir elemento\",\n removeItem: \"Eliminar\",\n maxItemsReached: \"Se ha alcanzado el máximo de elementos\",\n minItemsRequired: \"Se requiere un mínimo de {count} elementos\",\n },\n toolbar: {\n noDefinition:\n \"Registra este tipo de bloque en la configuración de tu SDK para editar sus propiedades\",\n },\n dataSource: {\n fetchButton: \"Cargar contenido\",\n changeButton: \"Cambiar\",\n fetching: \"Cargando...\",\n readOnlyTooltip: \"Este valor se carga desde tu fuente de datos\",\n fetchError: \"Error al cargar el contenido\",\n },\n },\n\n // Toolbar - HTML\n html: {\n content: \"Contenido HTML\",\n preview: \"Bloque HTML personalizado\",\n empty: \"Añadir contenido HTML en el panel\",\n sanitizationHint:\n \"El HTML se exporta tal cual y no se sanea — asegúrate de que el contenido sea seguro.\",\n },\n\n // Toolbar - Common block settings\n blockSettings: {\n spacing: \"Espaciado\",\n padding: \"Relleno\",\n background: \"Fondo\",\n color: \"Color\",\n display: \"Visualización\",\n showOnDesktop: \"Mostrar en escritorio\",\n showOnMobile: \"Mostrar en móvil\",\n hiddenOnDevice: \"Oculto en {device}\",\n displayCondition: \"Condición de visualización\",\n selectCondition: \"Seleccionar condición\",\n removeCondition: \"Eliminar condición\",\n noCondition: \"Siempre visible\",\n conditionApplied: \"Condición aplicada\",\n customCondition: \"Condición personalizada\",\n customConditionLabel: \"Nombre de la condición\",\n customConditionBefore: \"Antes (lógica de apertura)\",\n customConditionAfter: \"Después (lógica de cierre)\",\n applyCondition: \"Aplicar\",\n cancelCondition: \"Cancelar\",\n customBadge: \"Personalizado\",\n restoreHiddenBlocks: \"Mostrar todos los bloques ocultos\",\n },\n\n // Template settings\n templateSettings: {\n layout: \"Diseño\",\n widthPreset: \"Ancho predefinido\",\n customWidth: \"Ancho personalizado\",\n appearance: \"Apariencia\",\n backgroundColor: \"Color de fondo\",\n textColor: \"Color del texto\",\n linkColor: \"Color del enlace\",\n linkUnderline: \"Subrayar enlaces\",\n fontFamily: \"Familia tipográfica\",\n preheaderText: \"Texto del preencabezado\",\n preheaderTextPlaceholder:\n \"Texto de vista previa que se muestra después del asunto en la bandeja de entrada...\",\n preheaderTextHint:\n \"Este texto aparece después del asunto en las vistas previas de los clientes de correo electrónico. Admite etiquetas de combinación.\",\n language: \"Idioma\",\n contentLocale: \"Idioma del contenido\",\n contentLocaleHint:\n \"Código BCP 47 (por ejemplo, es, en, de). Establece el atributo lang del correo electrónico renderizado para que los lectores de pantalla pronuncien el contenido correctamente.\",\n tips: \"Consejos\",\n tip1: \"600px es el ancho estándar para las plantillas de correo electrónico\",\n tip2: \"Usa fuentes seguras para la web para una mejor compatibilidad\",\n tip3: \"Los fondos claros funcionan mejor para la legibilidad\",\n },\n\n // Spacing control\n spacingControl: {\n lockAll: \"Bloquear todos los lados\",\n unlock: \"Desbloquear lados\",\n top: \"Superior\",\n right: \"Derecho\",\n bottom: \"Inferior\",\n left: \"Izquierdo\",\n decreaseTop: \"Disminuir superior\",\n increaseTop: \"Aumentar superior\",\n decreaseLeft: \"Disminuir izquierdo\",\n increaseLeft: \"Aumentar izquierdo\",\n decreaseRight: \"Disminuir derecho\",\n increaseRight: \"Aumentar derecho\",\n decreaseBottom: \"Disminuir inferior\",\n increaseBottom: \"Aumentar inferior\",\n },\n\n // Color Picker\n colorPicker: {\n pickColor: \"Elegir un color\",\n hexValue: \"Valor de color Hex\",\n notSet: \"No establecido\",\n clear: \"Limpiar color\",\n presetColors: \"Colores predefinidos\",\n },\n\n // Merge Tag\n mergeTag: {\n clickToEdit: \"Haz clic para editar\",\n remove: \"Eliminar etiqueta de combinación\",\n insert: \"Insertar etiqueta de combinación\",\n insertShort: \"Etiqueta de combinación\",\n editValue: \"Editar valor de la etiqueta de combinación\",\n deleteMergeTag: \"Eliminar etiqueta de combinación\",\n suggestionEmpty: \"No hay etiquetas de combinación coincidentes\",\n picker: {\n title: \"Insertar etiqueta de combinación\",\n searchPlaceholder: \"Buscar etiquetas de combinación\",\n searchAriaLabel: \"Buscar etiquetas de combinación\",\n noResults: \"No hay etiquetas de combinación coincidentes\",\n empty: \"No hay etiquetas de combinación configuradas\",\n otherGroup: \"Otro\",\n cancel: \"Cancelar\",\n close: \"Cerrar\",\n groupCount: \"{count}\",\n },\n },\n\n // Logic tags (standalone, separate from merge tags)\n logicTag: {\n insert: \"Insertar lógica\",\n insertShort: \"Lógica\",\n picker: {\n title: \"Insertar lógica\",\n searchPlaceholder: \"Buscar etiquetas de lógica\",\n searchAriaLabel: \"Buscar etiquetas de lógica\",\n noResults: \"No hay etiquetas de lógica coincidentes\",\n empty: \"No hay etiquetas de lógica configuradas\",\n otherGroup: \"Otro\",\n close: \"Cerrar\",\n },\n },\n\n // Canvas\n canvas: {\n noBlocks: \"Aún no hay bloques\",\n dragHint: \"Comienza desde cero arrastrando bloques desde la barra lateral\",\n dropHere: \"Suelta aquí\",\n aiHintChat: \"o deja que\",\n aiHintChatSuffix: \"genere una plantilla completa para ti en segundos\",\n aiHintDesign:\n \"¿Tienes un diseño existente? Sube una captura de pantalla, imagen o PDF y\",\n aiHintDesignSuffix: \"lo recreará instantáneamente\",\n },\n\n // Media Library (cloud)\n mediaLibrary: {\n title: \"Biblioteca de medios\",\n searchPlaceholder: \"Buscar archivos...\",\n allFiles: \"Todos los archivos\",\n filterAll: \"Todos los tipos\",\n filterImages: \"Imágenes\",\n filterDocuments: \"Documentos\",\n filterVideos: \"Vídeos\",\n filterAudio: \"Audio\",\n newFolder: \"Nueva carpeta\",\n folderName: \"Nombre de la carpeta\",\n noFiles: \"No se encontraron archivos\",\n dropOrClick: \"Suelta los archivos aquí o haz clic para subirlos\",\n acceptedFormats: \"Imágenes, PDF, Vídeo, Audio, Documentos (máx. 10MB)\",\n uploading: \"Subiendo...\",\n uploadingProgress: \"Subiendo {current} de {total}...\",\n selectImage: \"Seleccionar imagen\",\n selectFile: \"Seleccionar archivo\",\n deleteSelected: \"Eliminar\",\n copyUrl: \"Copiar URL\",\n copied: \"¡Copiado!\",\n browseMedia: \"Explorar biblioteca de medios\",\n renameFolder: \"Cambiar nombre de la carpeta\",\n addSubfolder: \"Añadir subcarpeta\",\n subfolderName: \"Nombre de la subcarpeta\",\n sortNewest: \"Más recientes primero\",\n sortOldest: \"Más antiguos primero\",\n sortNameAsc: \"Nombre A-Z\",\n sortNameDesc: \"Nombre Z-A\",\n sortSizeAsc: \"Más pequeños primero\",\n sortSizeDesc: \"Más grandes primero\",\n moveSelected: \"Mover\",\n moveToRoot: \"Todos los archivos\",\n currentFolder: \"(actual)\",\n confirmDelete: \"¿Eliminar este archivo?\",\n renameFile: \"Cambiar nombre\",\n editFile: \"Editar archivo\",\n fileName: \"Nombre del archivo\",\n altText: \"Texto alternativo\",\n altTextPlaceholder: \"Describe esta imagen para la accesibilidad\",\n saveChanges: \"Guardar\",\n cancel: \"Cancelar\",\n frequentlyUsed: \"Usados con frecuencia\",\n deleteWarningTitle: \"Eliminar archivo\",\n deleteWarningMessage:\n \"Este archivo se eliminará permanentemente y no se podrá recuperar.\",\n deleteWarningUsageNote:\n \"Los siguientes archivos se usan en plantilles. Eliminarlos puede romper esas plantilles.\",\n deleteAnyway: \"Eliminar archivo de todos modos\",\n usedInTemplates: \"Usado en {count} plantilla(s)\",\n viewGrid: \"Vista de cuadrícula\",\n viewList: \"Vista de lista\",\n showFolders: \"Mostrar carpetas\",\n hideFolders: \"Ocultar carpetas\",\n importFromUrl: \"Importar desde URL\",\n importUrlPlaceholder: \"https://example.com/image.jpg\",\n import: \"Importar\",\n importing: \"Importando...\",\n importError: \"Error al importar desde la URL\",\n conversionLabel: \"Tamaño\",\n conversionOriginal: \"Original\",\n conversionSmall: \"Pequeño (150px)\",\n conversionMedium: \"Mediano (600px)\",\n conversionLarge: \"Grande (1200px)\",\n replaceFile: \"Reemplazar archivo\",\n replaceWarningTitle: \"Reemplazar archivo\",\n replaceWarningMessage:\n \"Estás a punto de reemplazar este archivo. El reemplazo debe tener la misma extensión de archivo ({extension}).\",\n replaceWarningUsageNote:\n \"Este archivo se usa en {count} plantilla(s). Reemplazarlo actualizará todas las referencias.\",\n replaceSelectFile: \"Seleccionar archivo de reemplazo\",\n replace: \"Reemplazar\",\n replacing: \"Reemplazando...\",\n replaceError: \"Error al reemplazar el archivo\",\n saving: \"Guardando...\",\n cropAspectRatio: \"Relación de aspecto\",\n cropFree: \"Libre\",\n cropSquare: \"1:1\",\n cropLandscape43: \"4:3\",\n cropLandscape169: \"16:9\",\n cropOriginal: \"Original\",\n cropMaxWidth: \"Ancho máximo\",\n cropMaxHeight: \"Altura máxima\",\n cropOutputSize: \"Tamaño de salida\",\n cropPixels: \"px\",\n cropOptional: \"(opcional)\",\n storageTooltip: \"{used} de {total} usados (quedan {remaining})\",\n },\n\n // Sidebar\n savedBlocks: {\n title: \"Bloques guardados\",\n saveAsBlock: \"Guardar como bloque\",\n name: \"Nombre\",\n namePlaceholder: \"p. ej. Encabezado, Pie de página, CTA...\",\n save: \"Guardar bloque\",\n saving: \"Guardando...\",\n cancel: \"Cancelar\",\n empty: \"Aún no hay bloques guardados\",\n emptyHint: \"Guarda bloques de tus plantillas para reutilizarlos más tarde.\",\n noResults: \"Ningún bloque guardado coincide con tu búsqueda\",\n search: \"Buscar bloques guardados...\",\n loading: \"Cargando bloques guardados…\",\n category: \"Categoría\",\n categoryPlaceholder: \"p. ej. Cabeceras, Promociones... (opcional)\",\n allCategories: \"Todas las categorías\",\n filterByCategory: \"Filtrar por categoría\",\n insert: \"Insertar\",\n rename: \"Cambiar nombre\",\n delete: \"Eliminar\",\n deleteConfirm: \"¿Eliminar este bloque guardado?\",\n blockCount: \"{count} bloque(s)\",\n browse: \"Explorar bloques guardados\",\n selectToPreview: \"Selecciona un bloque guardado para previsualizarlo\",\n insertAtBeginning: \"Al principio\",\n insertAfterBlock: \"Después de {block}\",\n insertAtEnd: \"Al final\",\n insertPosition: \"Posición de inserción\",\n close: \"Cerrar\",\n pickToolbar: \"Selección de bloque guardado\",\n pickCount: \"{count} bloque(s) seleccionado(s)\",\n pickHint: \"Haz clic en los bloques para añadirlos o quitarlos\",\n savingCount: \"Guardando {count} bloque(s):\",\n reorderHint:\n \"Arrastra para reordenar: los bloques se guardan en este orden\",\n reorderHandle: \"Reordenar {block}, posición {position} de {total}\",\n reorderAnnouncement: \"{block} movido a la posición {position} de {total}\",\n expand: \"Expandir\",\n collapse: \"Contraer\",\n expandPreview: \"Expandir la vista previa de {block}\",\n collapsePreview: \"Contraer la vista previa de {block}\",\n time: {\n justNow: \"Ahora mismo\",\n minutesAgo: \"hace {minutes} min\",\n hoursAgo: \"hace {hours} h\",\n daysAgo: \"hace {days} d\",\n },\n },\n testEmail: {\n title: \"Enviar correo de prueba\",\n recipientLabel: \"Destinatario\",\n recipientPlaceholder: \"tu@ejemplo.com\",\n invalidAddress: \"Introduce una dirección de correo válida.\",\n preview: \"Vista previa\",\n previewHint:\n \"Las etiquetas de combinación se muestran sin resolver — tu backend las rellena.\",\n recipientNotAllowed:\n \"Esa dirección no está en la lista de destinatarios permitidos.\",\n send: \"Enviar\",\n sending: \"Enviando...\",\n cancel: \"Cancelar\",\n success: \"Correo de prueba enviado correctamente\",\n button: \"Prueba\",\n },\n sidebarNav: {\n browseSavedBlocks: \"Explorar bloques guardados\",\n expandSidebar: \"Expandir barra lateral de bloques\",\n palette: \"Paleta de bloques\",\n insertBlock: \"Insertar bloque {block}\",\n },\n\n // Landmark region labels for assistive technology\n landmarks: {\n canvas: \"Lienzo del correo electrónico\",\n blockToolbar: \"Propiedades del bloque\",\n rightSidebar: \"Propiedades del bloque y configuración de la plantilla\",\n reorderAnnouncements: \"Anuncios de reordenación de bloques\",\n },\n\n // Design Reference (cloud)\n errors: {\n editorLoading: \"Cargando el editor...\",\n editorLoadFailed: \"Error al cargar el editor.\",\n retry: \"Reintentar\",\n },\n\n issues: {\n panelTitle: \"Problemes\",\n panelTabLabel: \"Problemes\",\n groupErrors: \"Errores\",\n groupWarnings: \"Advertencias\",\n groupInfo: \"Información\",\n jump: \"Saltar al bloque\",\n fix: \"Corregir\",\n emptyState: \"Sin problemas, todo se ve bien.\",\n badgeError: \"Tiene errores\",\n badgeWarning: \"Tiene advertencias\",\n issueCountTooltip: \"{count} problema(s)\",\n },\n\n smallScreen: {\n title: \"Se requiere una pantalla más grande\",\n message:\n \"El editor necesita más espacio del que ofrece esta pantalla. Ábrelo en una tableta o computadora de escritorio para comenzar a editar.\",\n },\n};\n\nexport default es;\n"],"mappings":"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"}
1
+ {"version":3,"file":"es-BSiH7YkP.js","names":[],"sources":["../../../src/i18n/locales/es.ts"],"sourcesContent":["import type en from \"./en\";\n\nconst es: typeof en = {\n // Footer (OSS only)\n footer: {\n poweredBy: \"Con la tecnología de\",\n openSource: \"Código abierto\",\n },\n\n // History (undo/redo)\n history: {\n undo: \"Deshacer\",\n redo: \"Rehacer\",\n collabWarning:\n \"Deshacer puede afectar a los cambios recientes de los colaboradores\",\n },\n\n // Viewport toggle\n viewport: {\n label: \"Área de visualización\",\n desktop: \"Escritorio\",\n mobile: \"Móvil\",\n },\n\n // Dark mode preview\n darkMode: {\n enable: \"Vista previa en modo oscuro\",\n disable: \"Vista previa en modo claro\",\n },\n\n // Preview mode\n previewMode: {\n enable: \"Modo vista previa\",\n disable: \"Salir de la vista previa\",\n },\n\n // Sidebar - Block types\n blocks: {\n section: \"Sección\",\n image: \"Imagen\",\n title: \"Título\",\n paragraph: \"Párrafo\",\n button: \"Botón\",\n divider: \"Divisor\",\n video: \"Vídeo\",\n social: \"Redes sociales\",\n spacer: \"Espaciador\",\n html: \"HTML\",\n menu: \"Menú\",\n table: \"Tabla\",\n countdown: \"Cuenta atrás\",\n },\n\n // Right sidebar\n sidebar: {\n content: \"Contenido\",\n settings: \"Configuración\",\n noSelection: \"Ningún elemento seleccionado\",\n noSelectionHint: \"Selecciona un bloque en el lienzo para editarlo\",\n },\n\n // Toolbar - Common\n toolbar: {\n duplicate: \"Duplicar\",\n delete: \"Eliminar\",\n },\n\n // Title editor toolbar\n titleEditor: {\n toolbar: \"Formato del título\",\n bold: \"Negrita (Ctrl+B)\",\n italic: \"Cursiva (Ctrl+I)\",\n addLink: \"Añadir enlace\",\n },\n\n // Paragraph editor toolbar\n paragraphEditor: {\n toolbar: \"Formato del texto\",\n bold: \"Negrita (Ctrl+B)\",\n italic: \"Cursiva (Ctrl+I)\",\n underline: \"Subrayado (Ctrl+U)\",\n strikethrough: \"Tachado\",\n subscript: \"Subíndice\",\n superscript: \"Superíndice\",\n addLink: \"Añadir enlace\",\n bulletList: \"Lista con viñetas\",\n numberedList: \"Lista numerada\",\n alignLeft: \"Alinear a la izquierda\",\n alignCenter: \"Alinear al centro\",\n alignRight: \"Alinear a la derecha\",\n clearFormatting: \"Borrar formato\",\n insertEmoji: \"Insertar emoji\",\n fontFamily: \"Familia tipográfica\",\n defaultFont: \"Por defecto\",\n fontSize: \"Tamaño de fuente\",\n defaultSize: \"Por defecto\",\n textColor: \"Color del texto\",\n highlightColor: \"Color de resaltado\",\n lineHeight: \"Interlineado\",\n letterSpacing: \"Espaciado entre letras\",\n emojiItemLabel: \"Insertar emoji {emoji}\",\n closeEmojiPicker: \"Cerrar selector de emojis\",\n },\n\n // Block actions (BlockWrapper)\n blockActions: {\n drag: \"Arrastra para reordenar o pulsa Espacio para mover con el teclado\",\n dragLifted:\n \"Moviendo {block}. Usa las flechas arriba y abajo para reposicionar, Espacio o Intro para soltar, Esc para cancelar.\",\n duplicate: \"Duplicar bloque\",\n delete: \"Eliminar bloque\",\n hiddenOnViewport: \"Oculto en {viewport}\",\n saveAsBlock: \"Guardar como bloque\",\n conditionToggle: \"Alternar condición de visualización\",\n comments: \"Comentarios ({count})\",\n lifted: \"{block} levantado. Posición {position} de {total}.\",\n moved: \"{block} movido a la posición {position} de {total}.\",\n dropped: \"{block} soltado en la posición {position} de {total}.\",\n cancelled: \"Movimiento cancelado. {block} volvió a la posición {position}.\",\n },\n\n // Toolbar - Section\n section: {\n dropHere: \"Suelta los bloques aquí\",\n columns: \"Columnas\",\n column1: \"1 columna\",\n column2: \"2 columnas\",\n column3: \"3 columnas\",\n ratio12: \"Proporción 1:2\",\n ratio21: \"Proporción 2:1\",\n borderRadius: \"Radio del borde\",\n wrapperEnable: \"Añadir contenedor\",\n stackOnMobile: \"Apilar en móvil\",\n },\n\n // Text editor link dialog\n linkDialog: {\n editLink: \"Editar enlace\",\n insertLink: \"Insertar enlace\",\n updateLink: \"Actualizar enlace\",\n removeLink: \"Eliminar enlace\",\n cancel: \"Cancelar\",\n urlPlaceholder: \"https://example.com\",\n urlLabel: \"URL\",\n colorLabel: \"Color del enlace\",\n },\n\n // Toolbar - Title\n title: {\n level: \"Nivel de encabezado\",\n heading1: \"Encabezado 1 (36px)\",\n heading2: \"Encabezado 2 (28px)\",\n heading3: \"Encabezado 3 (22px)\",\n heading4: \"Encabezado 4 (18px)\",\n fontFamily: \"Familia tipográfica\",\n inheritFont: \"Usar fuente de la plantilla\",\n color: \"Color\",\n align: \"Alineación\",\n alignLeft: \"Izquierda\",\n alignCenter: \"Centro\",\n alignRight: \"Derecha\",\n },\n\n // Emoji picker\n emoji: {\n smileys: \"Emoticonos\",\n gestures: \"Gestos\",\n objects: \"Objetos\",\n },\n\n // Toolbar - Image\n image: {\n imageUrl: \"URL de la imagen\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Texto alternativo\",\n altTextPlaceholder: \"Descripción de la imagen\",\n width: \"Ancho\",\n fullWidth: \"Ancho completo\",\n widthCustom: \"Personalizado\",\n linkUrl: \"URL del enlace\",\n openInNewTab: \"Abrir en una nueva pestaña\",\n placeholderUrl: \"Imagen de muestra\",\n placeholderUrlPlaceholder: \"https://... (solo para diseño)\",\n placeholderUrlTooltip:\n \"Dado que la URL de la imagen utiliza una etiqueta de combinación, puedes proporcionar una imagen real aquí para previsualizar el diseño mientras diseñas. Esto no se incluirá en el resultado final.\",\n clickToAdd: \"Haz clic para añadir la URL de la imagen\",\n browseMedia: \"Explorar archivos multimedia\",\n dropToUpload: \"Suelta la imagen para subirla\",\n uploading: \"Subiendo...\",\n decorative: \"Imagen decorativa\",\n decorativeHint:\n \"Oculto para los lectores de pantalla. Utilízalo solo para espaciadores y adornos visuales.\",\n },\n\n // Toolbar - Video\n video: {\n videoUrl: \"URL del vídeo\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n youtube: \"YouTube\",\n vimeo: \"Vimeo\",\n detected: \"Vídeo detectado: la miniatura se generará automáticamente\",\n openInNewTab: \"Abrir en una nueva pestaña\",\n customThumbnail: \"Miniatura personalizada\",\n optional: \"(opcional)\",\n thumbnailPlaceholder: \"Generada automáticamente desde la URL del vídeo\",\n altText: \"Texto alternativo\",\n altTextPlaceholder: \"Descripción del vídeo\",\n width: \"Ancho\",\n fullWidth: \"Ancho completo\",\n placeholderUrl: \"Miniatura de muestra\",\n placeholderUrlPlaceholder: \"https://... (solo para diseño)\",\n placeholderUrlTooltip:\n \"Dado que la URL del vídeo utiliza una etiqueta de combinación, puedes proporcionar una miniatura real aquí para previsualizar el diseño mientras diseñas. Esto no se incluirá en el resultado final.\",\n addVideo: \"Añadir una URL de vídeo\",\n },\n\n // Toolbar - Button\n button: {\n fontFamily: \"Familia tipográfica\",\n inheritFont: \"Usar fuente de la plantilla\",\n text: \"Texto\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"Abrir en una nueva pestaña\",\n background: \"Fondo\",\n textColor: \"Color del texto\",\n borderRadius: \"Radio del borde\",\n fontSize: \"Tamaño de fuente\",\n width: \"Ancho\",\n widthAuto: \"Ajustar al contenido\",\n fullWidth: \"Ancho completo\",\n widthCustom: \"Personalizado\",\n },\n\n // Toolbar - Divider\n divider: {\n style: \"Estilo\",\n solid: \"Sólido\",\n dashed: \"Discontinuo\",\n dotted: \"Punteado\",\n color: \"Color\",\n thickness: \"Grosor\",\n },\n\n // Toolbar - Social Icons\n social: {\n icons: \"Iconos\",\n addIcon: \"Añadir icono\",\n addIcons: \"Añadir iconos de redes sociales\",\n removeIcon: \"Eliminar\",\n platform: \"Plataforma\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n style: \"Estilo\",\n styleSolid: \"Sólido\",\n styleOutlined: \"Contorneado\",\n styleRounded: \"Redondeado\",\n styleSquare: \"Cuadrado\",\n styleCircle: \"Círculo\",\n size: \"Tamaño\",\n sizeSmall: \"S\",\n sizeMedium: \"M\",\n sizeLarge: \"L\",\n spacing: \"Espaciado\",\n align: \"Alineación\",\n platforms: {\n facebook: \"Facebook\",\n twitter: \"X (Twitter)\",\n instagram: \"Instagram\",\n linkedin: \"LinkedIn\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n pinterest: \"Pinterest\",\n email: \"Correo electrónico\",\n website: \"Sitio web\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n\n // Toolbar - Menu\n menu: {\n items: \"Elementos del menú\",\n addItem: \"Añadir elemento\",\n removeItem: \"Eliminar\",\n text: \"Texto\",\n url: \"URL\",\n urlPlaceholder: \"https://example.com\",\n openInNewTab: \"Abrir en una nueva pestaña\",\n bold: \"Negrita\",\n underline: \"Subrayado\",\n color: \"Color\",\n linkColor: \"Color del enlace\",\n fontSize: \"Tamaño de fuente\",\n fontFamily: \"Familia tipográfica\",\n separator: \"Separador\",\n separatorColor: \"Color del separador\",\n spacing: \"Espaciado\",\n textAlign: \"Alineación\",\n addLinks: \"Añadir enlaces al menú\",\n },\n\n // Toolbar - Table\n table: {\n dimensions: \"Dimensiones\",\n rows: \"Filas\",\n columns: \"Columnas\",\n addRow: \"Añadir fila\",\n removeRow: \"Eliminar fila\",\n addColumn: \"Añadir columna\",\n removeColumn: \"Eliminar columna\",\n hasHeaderRow: \"Fila de encabezado\",\n headerBackgroundColor: \"Fondo del encabezado\",\n noHeaderBg: \"Sin fondo\",\n borderColor: \"Color del borde\",\n borderWidth: \"Grosor del borde\",\n cellPadding: \"Relleno de la celda\",\n fontFamily: \"Familia tipográfica\",\n fontSize: \"Tamaño de fuente\",\n color: \"Color del texto\",\n textAlign: \"Alineación\",\n cellPlaceholder: \"Introduce el texto...\",\n empty: \"Añadir una tabla\",\n },\n\n // Toolbar - Spacer\n spacer: {\n height: \"Altura\",\n },\n\n // Toolbar - Countdown\n countdown: {\n targetDate: \"Fecha límite\",\n timezone: \"Zona horaria\",\n display: \"Visualización\",\n days: \"Días\",\n hours: \"Horas\",\n minutes: \"Minutos\",\n seconds: \"Segundos\",\n separator: \"Separador\",\n fontFamily: \"Familia tipográfica\",\n inheritFont: \"Por defecto\",\n digitFontSize: \"Tamaño de los dígitos\",\n digitColor: \"Color de los dígitos\",\n labelColor: \"Color de la etiqueta\",\n labelFontSize: \"Tamaño de la etiqueta\",\n background: \"Fondo\",\n labels: \"Etiquetas\",\n expiry: \"Mensaje de expiración\",\n expiredMessagePlaceholder: \"Esta oferta ha expirado\",\n expiredImageUrl: \"URL de la imagen caducada\",\n hideOnExpiry: \"Ocultar al expirar\",\n setDate: \"Establece una fecha límite en el panel de configuración\",\n hidden: \"Oculto (expirado)\",\n },\n\n // Custom Blocks\n customBlocks: {\n definitionNotFound:\n \"Tipo de bloque desconocido: este bloque no está registrado\",\n renderError:\n \"No se pudo renderizar este bloque. Comprueba si hay errores en la plantilla del bloque.\",\n fields: {\n required: \"Obligatorio\",\n addItem: \"Añadir elemento\",\n removeItem: \"Eliminar\",\n maxItemsReached: \"Se ha alcanzado el máximo de elementos\",\n minItemsRequired: \"Se requiere un mínimo de {count} elementos\",\n },\n toolbar: {\n noDefinition:\n \"Registra este tipo de bloque en la configuración de tu SDK para editar sus propiedades\",\n },\n dataSource: {\n fetchButton: \"Cargar contenido\",\n changeButton: \"Cambiar\",\n fetching: \"Cargando...\",\n readOnlyTooltip: \"Este valor se carga desde tu fuente de datos\",\n fetchError: \"Error al cargar el contenido\",\n },\n },\n\n // Toolbar - HTML\n html: {\n content: \"Contenido HTML\",\n preview: \"Bloque HTML personalizado\",\n empty: \"Añadir contenido HTML en el panel\",\n sanitizationHint:\n \"El HTML se exporta tal cual y no se sanea — asegúrate de que el contenido sea seguro.\",\n },\n\n // Toolbar - Common block settings\n blockSettings: {\n spacing: \"Espaciado\",\n padding: \"Relleno\",\n background: \"Fondo\",\n color: \"Color\",\n display: \"Visualización\",\n showOnDesktop: \"Mostrar en escritorio\",\n showOnMobile: \"Mostrar en móvil\",\n hiddenOnDevice: \"Oculto en {device}\",\n displayCondition: \"Condición de visualización\",\n selectCondition: \"Seleccionar condición\",\n removeCondition: \"Eliminar condición\",\n noCondition: \"Siempre visible\",\n conditionApplied: \"Condición aplicada\",\n customCondition: \"Condición personalizada\",\n customConditionLabel: \"Nombre de la condición\",\n customConditionBefore: \"Antes (lógica de apertura)\",\n customConditionAfter: \"Después (lógica de cierre)\",\n applyCondition: \"Aplicar\",\n cancelCondition: \"Cancelar\",\n customBadge: \"Personalizado\",\n restoreHiddenBlocks: \"Mostrar todos los bloques ocultos\",\n },\n\n // Template settings\n templateSettings: {\n layout: \"Diseño\",\n widthPreset: \"Ancho predefinido\",\n customWidth: \"Ancho personalizado\",\n appearance: \"Apariencia\",\n backgroundColor: \"Color de fondo\",\n textColor: \"Color del texto\",\n linkColor: \"Color del enlace\",\n linkUnderline: \"Subrayar enlaces\",\n fontFamily: \"Familia tipográfica\",\n preheaderText: \"Texto del preencabezado\",\n preheaderTextPlaceholder:\n \"Texto de vista previa que se muestra después del asunto en la bandeja de entrada...\",\n preheaderTextHint:\n \"Este texto aparece después del asunto en las vistas previas de los clientes de correo electrónico. Admite etiquetas de combinación.\",\n language: \"Idioma\",\n contentLocale: \"Idioma del contenido\",\n contentLocaleHint:\n \"Código BCP 47 (por ejemplo, es, en, de). Establece el atributo lang del correo electrónico renderizado para que los lectores de pantalla pronuncien el contenido correctamente.\",\n tips: \"Consejos\",\n tip1: \"600px es el ancho estándar para las plantillas de correo electrónico\",\n tip2: \"Usa fuentes seguras para la web para una mejor compatibilidad\",\n tip3: \"Los fondos claros funcionan mejor para la legibilidad\",\n },\n\n // Spacing control\n spacingControl: {\n lockAll: \"Bloquear todos los lados\",\n unlock: \"Desbloquear lados\",\n top: \"Superior\",\n right: \"Derecho\",\n bottom: \"Inferior\",\n left: \"Izquierdo\",\n decreaseTop: \"Disminuir superior\",\n increaseTop: \"Aumentar superior\",\n decreaseLeft: \"Disminuir izquierdo\",\n increaseLeft: \"Aumentar izquierdo\",\n decreaseRight: \"Disminuir derecho\",\n increaseRight: \"Aumentar derecho\",\n decreaseBottom: \"Disminuir inferior\",\n increaseBottom: \"Aumentar inferior\",\n },\n\n // Color Picker\n colorPicker: {\n pickColor: \"Elegir un color\",\n hexValue: \"Valor de color Hex\",\n notSet: \"No establecido\",\n clear: \"Limpiar color\",\n presetColors: \"Colores predefinidos\",\n },\n\n // Merge Tag\n mergeTag: {\n clickToEdit: \"Haz clic para editar\",\n remove: \"Eliminar etiqueta de combinación\",\n insert: \"Insertar etiqueta de combinación\",\n insertShort: \"Etiqueta de combinación\",\n editValue: \"Editar valor de la etiqueta de combinación\",\n deleteMergeTag: \"Eliminar etiqueta de combinación\",\n suggestionEmpty: \"No hay etiquetas de combinación coincidentes\",\n picker: {\n title: \"Insertar etiqueta de combinación\",\n searchPlaceholder: \"Buscar etiquetas de combinación\",\n searchAriaLabel: \"Buscar etiquetas de combinación\",\n noResults: \"No hay etiquetas de combinación coincidentes\",\n empty: \"No hay etiquetas de combinación configuradas\",\n otherGroup: \"Otro\",\n cancel: \"Cancelar\",\n close: \"Cerrar\",\n groupCount: \"{count}\",\n sample: \"Vista previa: {sample}\",\n },\n },\n\n // Logic tags (standalone, separate from merge tags)\n logicTag: {\n insert: \"Insertar lógica\",\n insertShort: \"Lógica\",\n picker: {\n title: \"Insertar lógica\",\n searchPlaceholder: \"Buscar etiquetas de lógica\",\n searchAriaLabel: \"Buscar etiquetas de lógica\",\n noResults: \"No hay etiquetas de lógica coincidentes\",\n empty: \"No hay etiquetas de lógica configuradas\",\n otherGroup: \"Otro\",\n close: \"Cerrar\",\n },\n },\n\n // Canvas\n canvas: {\n noBlocks: \"Aún no hay bloques\",\n dragHint: \"Comienza desde cero arrastrando bloques desde la barra lateral\",\n dropHere: \"Suelta aquí\",\n aiHintChat: \"o deja que\",\n aiHintChatSuffix: \"genere una plantilla completa para ti en segundos\",\n aiHintDesign:\n \"¿Tienes un diseño existente? Sube una captura de pantalla, imagen o PDF y\",\n aiHintDesignSuffix: \"lo recreará instantáneamente\",\n },\n\n // Media Library (cloud)\n mediaLibrary: {\n title: \"Biblioteca de medios\",\n searchPlaceholder: \"Buscar archivos...\",\n allFiles: \"Todos los archivos\",\n filterAll: \"Todos los tipos\",\n filterImages: \"Imágenes\",\n filterDocuments: \"Documentos\",\n filterVideos: \"Vídeos\",\n filterAudio: \"Audio\",\n newFolder: \"Nueva carpeta\",\n folderName: \"Nombre de la carpeta\",\n noFiles: \"No se encontraron archivos\",\n dropOrClick: \"Suelta los archivos aquí o haz clic para subirlos\",\n acceptedFormats: \"Imágenes, PDF, Vídeo, Audio, Documentos (máx. 10MB)\",\n uploading: \"Subiendo...\",\n uploadingProgress: \"Subiendo {current} de {total}...\",\n selectImage: \"Seleccionar imagen\",\n selectFile: \"Seleccionar archivo\",\n deleteSelected: \"Eliminar\",\n copyUrl: \"Copiar URL\",\n copied: \"¡Copiado!\",\n browseMedia: \"Explorar biblioteca de medios\",\n renameFolder: \"Cambiar nombre de la carpeta\",\n addSubfolder: \"Añadir subcarpeta\",\n subfolderName: \"Nombre de la subcarpeta\",\n sortNewest: \"Más recientes primero\",\n sortOldest: \"Más antiguos primero\",\n sortNameAsc: \"Nombre A-Z\",\n sortNameDesc: \"Nombre Z-A\",\n sortSizeAsc: \"Más pequeños primero\",\n sortSizeDesc: \"Más grandes primero\",\n moveSelected: \"Mover\",\n moveToRoot: \"Todos los archivos\",\n currentFolder: \"(actual)\",\n confirmDelete: \"¿Eliminar este archivo?\",\n renameFile: \"Cambiar nombre\",\n editFile: \"Editar archivo\",\n fileName: \"Nombre del archivo\",\n altText: \"Texto alternativo\",\n altTextPlaceholder: \"Describe esta imagen para la accesibilidad\",\n saveChanges: \"Guardar\",\n cancel: \"Cancelar\",\n frequentlyUsed: \"Usados con frecuencia\",\n deleteWarningTitle: \"Eliminar archivo\",\n deleteWarningMessage:\n \"Este archivo se eliminará permanentemente y no se podrá recuperar.\",\n deleteWarningUsageNote:\n \"Los siguientes archivos se usan en plantilles. Eliminarlos puede romper esas plantilles.\",\n deleteAnyway: \"Eliminar archivo de todos modos\",\n usedInTemplates: \"Usado en {count} plantilla(s)\",\n viewGrid: \"Vista de cuadrícula\",\n viewList: \"Vista de lista\",\n showFolders: \"Mostrar carpetas\",\n hideFolders: \"Ocultar carpetas\",\n importFromUrl: \"Importar desde URL\",\n importUrlPlaceholder: \"https://example.com/image.jpg\",\n import: \"Importar\",\n importing: \"Importando...\",\n importError: \"Error al importar desde la URL\",\n conversionLabel: \"Tamaño\",\n conversionOriginal: \"Original\",\n conversionSmall: \"Pequeño (150px)\",\n conversionMedium: \"Mediano (600px)\",\n conversionLarge: \"Grande (1200px)\",\n replaceFile: \"Reemplazar archivo\",\n replaceWarningTitle: \"Reemplazar archivo\",\n replaceWarningMessage:\n \"Estás a punto de reemplazar este archivo. El reemplazo debe tener la misma extensión de archivo ({extension}).\",\n replaceWarningUsageNote:\n \"Este archivo se usa en {count} plantilla(s). Reemplazarlo actualizará todas las referencias.\",\n replaceSelectFile: \"Seleccionar archivo de reemplazo\",\n replace: \"Reemplazar\",\n replacing: \"Reemplazando...\",\n replaceError: \"Error al reemplazar el archivo\",\n saving: \"Guardando...\",\n cropAspectRatio: \"Relación de aspecto\",\n cropFree: \"Libre\",\n cropSquare: \"1:1\",\n cropLandscape43: \"4:3\",\n cropLandscape169: \"16:9\",\n cropOriginal: \"Original\",\n cropMaxWidth: \"Ancho máximo\",\n cropMaxHeight: \"Altura máxima\",\n cropOutputSize: \"Tamaño de salida\",\n cropPixels: \"px\",\n cropOptional: \"(opcional)\",\n storageTooltip: \"{used} de {total} usados (quedan {remaining})\",\n },\n\n // Sidebar\n savedBlocks: {\n title: \"Bloques guardados\",\n saveAsBlock: \"Guardar como bloque\",\n name: \"Nombre\",\n namePlaceholder: \"p. ej. Encabezado, Pie de página, CTA...\",\n save: \"Guardar bloque\",\n saving: \"Guardando...\",\n cancel: \"Cancelar\",\n empty: \"Aún no hay bloques guardados\",\n emptyHint: \"Guarda bloques de tus plantillas para reutilizarlos más tarde.\",\n noResults: \"Ningún bloque guardado coincide con tu búsqueda\",\n search: \"Buscar bloques guardados...\",\n loading: \"Cargando bloques guardados…\",\n category: \"Categoría\",\n categoryPlaceholder: \"p. ej. Cabeceras, Promociones... (opcional)\",\n allCategories: \"Todas las categorías\",\n filterByCategory: \"Filtrar por categoría\",\n insert: \"Insertar\",\n rename: \"Cambiar nombre\",\n delete: \"Eliminar\",\n deleteConfirm: \"¿Eliminar este bloque guardado?\",\n blockCount: \"{count} bloque(s)\",\n browse: \"Explorar bloques guardados\",\n selectToPreview: \"Selecciona un bloque guardado para previsualizarlo\",\n insertAtBeginning: \"Al principio\",\n insertAfterBlock: \"Después de {block}\",\n insertAtEnd: \"Al final\",\n insertPosition: \"Posición de inserción\",\n close: \"Cerrar\",\n pickToolbar: \"Selección de bloque guardado\",\n pickCount: \"{count} bloque(s) seleccionado(s)\",\n pickHint: \"Haz clic en los bloques para añadirlos o quitarlos\",\n savingCount: \"Guardando {count} bloque(s):\",\n reorderHint:\n \"Arrastra para reordenar: los bloques se guardan en este orden\",\n reorderHandle: \"Reordenar {block}, posición {position} de {total}\",\n reorderAnnouncement: \"{block} movido a la posición {position} de {total}\",\n expand: \"Expandir\",\n collapse: \"Contraer\",\n expandPreview: \"Expandir la vista previa de {block}\",\n collapsePreview: \"Contraer la vista previa de {block}\",\n time: {\n justNow: \"Ahora mismo\",\n minutesAgo: \"hace {minutes} min\",\n hoursAgo: \"hace {hours} h\",\n daysAgo: \"hace {days} d\",\n },\n },\n mergeTagPreview: {\n label: \"Vista de etiquetas de combinación\",\n sample: \"Ejemplo\",\n labelView: \"Etiqueta\",\n },\n testEmail: {\n title: \"Enviar correo de prueba\",\n recipientLabel: \"Destinatario\",\n recipientPlaceholder: \"tu@ejemplo.com\",\n invalidAddress: \"Introduce una dirección de correo válida.\",\n preview: \"Vista previa\",\n previewHint:\n \"Las etiquetas de combinación se muestran sin resolver — tu backend las rellena.\",\n previewHintSample:\n \"Las etiquetas de combinación muestran valores de ejemplo; tu backend inserta los datos reales.\",\n recipientNotAllowed:\n \"Esa dirección no está en la lista de destinatarios permitidos.\",\n send: \"Enviar\",\n sending: \"Enviando...\",\n cancel: \"Cancelar\",\n success: \"Correo de prueba enviado correctamente\",\n button: \"Prueba\",\n },\n sidebarNav: {\n browseSavedBlocks: \"Explorar bloques guardados\",\n expandSidebar: \"Expandir barra lateral de bloques\",\n palette: \"Paleta de bloques\",\n insertBlock: \"Insertar bloque {block}\",\n },\n\n // Landmark region labels for assistive technology\n landmarks: {\n canvas: \"Lienzo del correo electrónico\",\n blockToolbar: \"Propiedades del bloque\",\n rightSidebar: \"Propiedades del bloque y configuración de la plantilla\",\n reorderAnnouncements: \"Anuncios de reordenación de bloques\",\n },\n\n // Design Reference (cloud)\n errors: {\n editorLoading: \"Cargando el editor...\",\n editorLoadFailed: \"Error al cargar el editor.\",\n retry: \"Reintentar\",\n },\n\n issues: {\n panelTitle: \"Problemes\",\n panelTabLabel: \"Problemes\",\n groupErrors: \"Errores\",\n groupWarnings: \"Advertencias\",\n groupInfo: \"Información\",\n jump: \"Saltar al bloque\",\n fix: \"Corregir\",\n emptyState: \"Sin problemas, todo se ve bien.\",\n badgeError: \"Tiene errores\",\n badgeWarning: \"Tiene advertencias\",\n issueCountTooltip: \"{count} problema(s)\",\n },\n\n smallScreen: {\n title: \"Se requiere una pantalla más grande\",\n message:\n \"El editor necesita más espacio del que ofrece esta pantalla. Ábrelo en una tableta o computadora de escritorio para comenzar a editar.\",\n },\n};\n\nexport default es;\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { H as e, M as t, O as n, V as r, Z as i, c as a, ct as o, f as s, g as c, h as l, it as u, l as d, m as f, o as p, ot as m, p as h, st as g, x as _ } from "./draggable-D840DIZB.js";
2
- import { a as v, c as y, i as b, n as x } from "./src-BKI1x1k7.js";
3
- import { t as S } from "./useI18n-8Wd7G-cq.js";
4
- import { t as C } from "./useMergeTag-C7G31KV-.js";
5
- import { _ as w, g as T, h as E, n as D, t as O, v as k, y as A } from "./tiptap-DUTbZTeR.js";
6
- import { i as j, r as M, t as N } from "./MergeTagSuggestion-BM349_QH.js";
2
+ import { a as v, i as y, n as b, u as x } from "./src-BCJna-6p.js";
3
+ import { t as S } from "./useI18n-graz19nI.js";
4
+ import { t as C } from "./useMergeTag-rTzAFMlr.js";
5
+ import { _ as w, g as T, h as E, n as D, t as O, v as k, y as A } from "./tiptap-DRKu__AX.js";
6
+ import { i as j, r as M, t as N } from "./MergeTagSuggestion-Cvlkw_PM.js";
7
7
  //#region src/extensions/FontSize.ts
8
8
  var P = E.create({
9
9
  name: "fontSize",
@@ -85,7 +85,7 @@ var P = E.create({
85
85
  updateAttributes: { type: Function }
86
86
  },
87
87
  setup(_) {
88
- let v = _, { syntax: x } = C(), { t: w } = S(), T = s(() => y(v.node.attrs.value, x)), E = s(() => b(v.node.attrs.value, x)), D = i(!1), k = i(""), A = i(null), j = !1;
88
+ let v = _, { syntax: b } = C(), { t: w } = S(), T = s(() => x(v.node.attrs.value, b)), E = s(() => y(v.node.attrs.value, b)), D = i(!1), k = i(""), A = i(null), j = !1;
89
89
  function M() {
90
90
  k.value = v.node.attrs.value, j = !1, D.value = !0, n(() => {
91
91
  A.value?.focus(), A.value?.select();
@@ -101,7 +101,7 @@ var P = E.create({
101
101
  }
102
102
  e !== v.node.attrs.value && v.updateAttributes({
103
103
  value: e,
104
- keyword: y(e, x) ? b(e, x) : ""
104
+ keyword: x(e, b) ? y(e, b) : ""
105
105
  }), D.value = !1;
106
106
  }
107
107
  function P(e) {
@@ -187,7 +187,7 @@ var U = w.create({
187
187
  inline: !0,
188
188
  atom: !0,
189
189
  addOptions() {
190
- return { syntax: x.liquid };
190
+ return { syntax: b.liquid };
191
191
  },
192
192
  addAttributes() {
193
193
  return {
@@ -205,12 +205,12 @@ var U = w.create({
205
205
  return [{ tag: "span[data-logic-merge-tag]" }];
206
206
  },
207
207
  renderHTML({ node: e, HTMLAttributes: t }) {
208
- if (!y(e.attrs.value, this.options.syntax)) return [
208
+ if (!x(e.attrs.value, this.options.syntax)) return [
209
209
  "span",
210
210
  {},
211
211
  e.attrs.value
212
212
  ];
213
- let n = b(e.attrs.value, this.options.syntax);
213
+ let n = y(e.attrs.value, this.options.syntax);
214
214
  return [
215
215
  "span",
216
216
  A(t, {
@@ -234,8 +234,8 @@ var U = w.create({
234
234
  find: RegExp(this.options.syntax.logic.source + "$", ""),
235
235
  handler: ({ state: e, range: t, match: n }) => {
236
236
  let r = n[0];
237
- if (!y(r, this.options.syntax)) return;
238
- let i = b(r, this.options.syntax), a = this.type.create({
237
+ if (!x(r, this.options.syntax)) return;
238
+ let i = y(r, this.options.syntax), a = this.type.create({
239
239
  value: r,
240
240
  keyword: i
241
241
  });
@@ -248,8 +248,8 @@ var U = w.create({
248
248
  find: new RegExp(this.options.syntax.logic.source, "g"),
249
249
  handler: ({ state: e, range: t, match: n }) => {
250
250
  let r = n[0];
251
- if (!y(r, this.options.syntax)) return;
252
- let i = b(r, this.options.syntax), a = this.type.create({
251
+ if (!x(r, this.options.syntax)) return;
252
+ let i = y(r, this.options.syntax), a = this.type.create({
253
253
  value: r,
254
254
  keyword: i
255
255
  });
@@ -345,7 +345,7 @@ var U = w.create({
345
345
  addOptions() {
346
346
  return {
347
347
  mergeTags: [],
348
- syntax: x.liquid
348
+ syntax: b.liquid
349
349
  };
350
350
  },
351
351
  addAttributes() {
@@ -420,4 +420,4 @@ var U = w.create({
420
420
  //#endregion
421
421
  export { P as FontSize, F as LetterSpacing, I as LineHeight, U as LogicMergeTagNode, q as MergeTagNode, N as MergeTagSuggestion, M as filterMergeTags, j as handleSuggestionKeyDown };
422
422
 
423
- //# sourceMappingURL=extensions-C49c51P1.js.map
423
+ //# sourceMappingURL=extensions-DBWF_lxx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensions-C49c51P1.js","names":[],"sources":["../../../src/extensions/FontSize.ts","../../../src/extensions/LetterSpacing.ts","../../../src/extensions/LineHeight.ts","../../../src/extensions/LogicMergeTagNodeView.vue","../../../src/extensions/LogicMergeTagNodeView.vue","../../../src/extensions/isNodeSelected.ts","../../../src/extensions/renderVueNodeView.ts","../../../src/extensions/LogicMergeTagNode.ts","../../../src/extensions/MergeTagNodeView.vue","../../../src/extensions/MergeTagNodeView.vue","../../../src/extensions/MergeTagNode.ts"],"sourcesContent":["import { Extension } from \"@tiptap/core\";\n\nexport interface FontSizeOptions {\n types: string[];\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n fontSize: {\n setFontSize: (size: string) => ReturnType;\n unsetFontSize: () => ReturnType;\n };\n }\n}\n\nexport const FontSize = Extension.create<FontSizeOptions>({\n name: \"fontSize\",\n\n addOptions() {\n return {\n types: [\"textStyle\"],\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n fontSize: {\n default: null,\n parseHTML: (element) =>\n element.style.fontSize?.replace(/['\"]+/g, \"\") || null,\n renderHTML: (attributes) => {\n if (!attributes.fontSize) {\n return {};\n }\n return {\n style: `font-size: ${attributes.fontSize}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setFontSize:\n (size: string) =>\n ({ chain }) => {\n return chain().setMark(\"textStyle\", { fontSize: size }).run();\n },\n unsetFontSize:\n () =>\n ({ chain }) => {\n return chain()\n .setMark(\"textStyle\", { fontSize: null })\n .removeEmptyTextStyle()\n .run();\n },\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\n\nexport interface LetterSpacingOptions {\n types: string[];\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n letterSpacing: {\n setLetterSpacing: (spacing: string) => ReturnType;\n unsetLetterSpacing: () => ReturnType;\n };\n }\n}\n\nexport const LetterSpacing = Extension.create<LetterSpacingOptions>({\n name: \"letterSpacing\",\n\n addOptions() {\n return {\n types: [\"textStyle\"],\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n letterSpacing: {\n default: null,\n parseHTML: (element) =>\n element.style.letterSpacing?.replace(/['\"]+/g, \"\") || null,\n renderHTML: (attributes) => {\n if (!attributes.letterSpacing) {\n return {};\n }\n return {\n style: `letter-spacing: ${attributes.letterSpacing}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setLetterSpacing:\n (spacing: string) =>\n ({ chain }) => {\n return chain().setMark(\"textStyle\", { letterSpacing: spacing }).run();\n },\n unsetLetterSpacing:\n () =>\n ({ chain }) => {\n return chain()\n .setMark(\"textStyle\", { letterSpacing: null })\n .removeEmptyTextStyle()\n .run();\n },\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\n\nexport interface LineHeightOptions {\n types: string[];\n defaultLineHeight: string;\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n lineHeight: {\n setLineHeight: (lineHeight: string) => ReturnType;\n unsetLineHeight: () => ReturnType;\n };\n }\n}\n\nexport const LineHeight = Extension.create<LineHeightOptions>({\n name: \"lineHeight\",\n\n addOptions() {\n return {\n types: [\"paragraph\"],\n defaultLineHeight: \"1.5\",\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n lineHeight: {\n default: null,\n parseHTML: (element) => element.style.lineHeight || null,\n renderHTML: (attributes) => {\n if (!attributes.lineHeight) {\n return {};\n }\n return {\n style: `line-height: ${attributes.lineHeight}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setLineHeight:\n (lineHeight: string) =>\n ({ commands }) => {\n return this.options.types.every((type) =>\n commands.updateAttributes(type, { lineHeight }),\n );\n },\n unsetLineHeight:\n () =>\n ({ commands }) => {\n return this.options.types.every((type) =>\n commands.resetAttributes(type, \"lineHeight\"),\n );\n },\n };\n },\n});\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n} from \"@templatical/types\";\nimport type { Editor } from \"@tiptap/core\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n value: string;\n keyword: string;\n };\n };\n editor: Editor;\n getPos: () => number;\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { syntax } = useMergeTag();\nconst { t } = useI18n();\n\nconst isValid = computed(() =>\n isLogicMergeTagValue(props.node.attrs.value, syntax),\n);\nconst displayKeyword = computed(() =>\n getLogicMergeTagKeyword(props.node.attrs.value, syntax),\n);\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\nlet handled = false;\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n handled = false;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n if (handled) {\n return;\n }\n handled = true;\n\n const newValue = editValue.value.trim();\n if (!newValue) {\n isEditing.value = false;\n return;\n }\n\n if (newValue !== props.node.attrs.value) {\n props.updateAttributes({\n value: newValue,\n keyword: isLogicMergeTagValue(newValue, syntax)\n ? getLogicMergeTagKeyword(newValue, syntax)\n : \"\",\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n :class=\"\n isValid\n ? 'tpl-logic-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.8em] tpl:font-bold tpl:tracking-wide tpl:uppercase tpl:select-none'\n : ''\n \"\n :style=\"\n isValid\n ? 'background-color: transparent; border: 1.5px solid color-mix(in srgb, var(--tpl-primary) 50%, transparent); color: var(--tpl-primary);'\n : ''\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-40 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:normal-case tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode: valid merge tag -->\n <span\n v-else-if=\"isValid\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayKeyword }}\n </span>\n <!-- Display mode: invalid (plain text) -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ node.attrs.value }}\n </span>\n <button\n v-if=\"isValid\"\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n} from \"@templatical/types\";\nimport type { Editor } from \"@tiptap/core\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n value: string;\n keyword: string;\n };\n };\n editor: Editor;\n getPos: () => number;\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { syntax } = useMergeTag();\nconst { t } = useI18n();\n\nconst isValid = computed(() =>\n isLogicMergeTagValue(props.node.attrs.value, syntax),\n);\nconst displayKeyword = computed(() =>\n getLogicMergeTagKeyword(props.node.attrs.value, syntax),\n);\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\nlet handled = false;\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n handled = false;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n if (handled) {\n return;\n }\n handled = true;\n\n const newValue = editValue.value.trim();\n if (!newValue) {\n isEditing.value = false;\n return;\n }\n\n if (newValue !== props.node.attrs.value) {\n props.updateAttributes({\n value: newValue,\n keyword: isLogicMergeTagValue(newValue, syntax)\n ? getLogicMergeTagKeyword(newValue, syntax)\n : \"\",\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n :class=\"\n isValid\n ? 'tpl-logic-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.8em] tpl:font-bold tpl:tracking-wide tpl:uppercase tpl:select-none'\n : ''\n \"\n :style=\"\n isValid\n ? 'background-color: transparent; border: 1.5px solid color-mix(in srgb, var(--tpl-primary) 50%, transparent); color: var(--tpl-primary);'\n : ''\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-40 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:normal-case tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode: valid merge tag -->\n <span\n v-else-if=\"isValid\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayKeyword }}\n </span>\n <!-- Display mode: invalid (plain text) -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ node.attrs.value }}\n </span>\n <button\n v-if=\"isValid\"\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","import type { Editor } from \"@tiptap/core\";\n\n/**\n * Decides whether MergeTagNode / LogicMergeTagNode should swallow a\n * Backspace/Delete keystroke (returning `true` from a TipTap keymap\n * suppresses the default behavior).\n *\n * Only suppresses in the cursor-adjacent case so the \"first press\n * selects the atom, second press deletes it\" UX works. Range selections\n * (Cmd+A, drag-select, double-click-word) explicitly fall through —\n * default `replaceSelection` then deletes the entire range including\n * any merge-tag atoms inside it.\n *\n * Earlier revisions also returned `true` whenever `nodesBetween($from,\n * $to)` found a merge tag anywhere in the selection range — which\n * silently broke Cmd+A + Backspace for any paragraph containing a\n * merge tag (entire deletion was cancelled, nothing happened). The\n * cursor-adjacent protection is the only piece that should survive.\n */\nexport function isNodeSelected(editor: Editor, nodeTypeName: string): boolean {\n const { $from, $to } = editor.state.selection;\n\n // Range selection: let TipTap's default range-delete run. Even when\n // the range contains atom nodes, ProseMirror's replaceSelection\n // handles atomic deletion correctly.\n if ($from.pos !== $to.pos) return false;\n\n // Cursor-adjacent atom: protect from single-keystroke deletion.\n // (`$from.pos > 0` guards against reading `nodeBefore` at doc start\n // where ProseMirror's index would be undefined for nodeBefore.)\n if ($from.pos > 0 && $from.nodeBefore?.type.name === nodeTypeName) {\n return true;\n }\n if ($from.nodeAfter?.type.name === nodeTypeName) {\n return true;\n }\n\n return false;\n}\n","import type { Component } from \"vue\";\nimport { VueNodeViewRenderer } from \"@tiptap/vue-3\";\n\n/**\n * Typed wrapper for VueNodeViewRenderer that handles the known type mismatch\n * between Vue SFC default exports and TipTap's expected component type.\n */\nexport function renderVueNodeView(component: Component) {\n return VueNodeViewRenderer(\n component as Parameters<typeof VueNodeViewRenderer>[0],\n );\n}\n","import LogicMergeTagNodeView from \"./LogicMergeTagNodeView.vue\";\nimport type { SyntaxPreset } from \"@templatical/types\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n SYNTAX_PRESETS,\n} from \"@templatical/types\";\nimport { InputRule, mergeAttributes, Node, PasteRule } from \"@tiptap/core\";\nimport { isNodeSelected } from \"./isNodeSelected\";\nimport { renderVueNodeView } from \"./renderVueNodeView\";\n\nexport interface LogicMergeTagNodeOptions {\n syntax: SyntaxPreset;\n}\n\nexport const LogicMergeTagNode = Node.create<LogicMergeTagNodeOptions>({\n name: \"logicMergeTagNode\",\n\n group: \"inline\",\n\n inline: true,\n\n atom: true,\n\n addOptions() {\n return {\n syntax: SYNTAX_PRESETS.liquid,\n };\n },\n\n addAttributes() {\n return {\n value: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-logic-merge-tag\") || \"\",\n },\n keyword: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-keyword\") || element.textContent || \"\",\n },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: \"span[data-logic-merge-tag]\",\n },\n ];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n if (!isLogicMergeTagValue(node.attrs.value, this.options.syntax)) {\n return [\"span\", {}, node.attrs.value];\n }\n\n const keyword = getLogicMergeTagKeyword(\n node.attrs.value,\n this.options.syntax,\n );\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-logic-merge-tag\": node.attrs.value,\n \"data-keyword\": keyword,\n }),\n keyword,\n ];\n },\n\n addNodeView() {\n return renderVueNodeView(LogicMergeTagNodeView);\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => isNodeSelected(this.editor, this.name),\n Delete: () => isNodeSelected(this.editor, this.name),\n };\n },\n\n addInputRules() {\n const inputRegex = new RegExp(this.options.syntax.logic.source + \"$\", \"\");\n\n return [\n new InputRule({\n find: inputRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n if (!isLogicMergeTagValue(fullValue, this.options.syntax)) {\n return;\n }\n\n const keyword = getLogicMergeTagKeyword(\n fullValue,\n this.options.syntax,\n );\n\n const node = this.type.create({\n value: fullValue,\n keyword,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n\n addPasteRules() {\n const pasteRegex = new RegExp(this.options.syntax.logic.source, \"g\");\n\n return [\n new PasteRule({\n find: pasteRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n if (!isLogicMergeTagValue(fullValue, this.options.syntax)) {\n return;\n }\n\n const keyword = getLogicMergeTagKeyword(\n fullValue,\n this.options.syntax,\n );\n\n const node = this.type.create({\n value: fullValue,\n keyword,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n});\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n label: string;\n value: string;\n };\n };\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { getMergeTagLabel } = useMergeTag();\nconst { t } = useI18n();\n\nconst displayLabel = computed(() => getMergeTagLabel(props.node.attrs.value));\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n const newValue = editValue.value.trim();\n if (newValue && newValue !== props.node.attrs.value) {\n // Update with new value and derive label from it\n props.updateAttributes({\n value: newValue,\n label: getMergeTagLabel(newValue),\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n class=\"tpl-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.9em] tpl:font-medium tpl:select-none tpl:text-[var(--tpl-primary)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-primary) 20%, transparent);\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-32 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayLabel }}\n </span>\n <button\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n label: string;\n value: string;\n };\n };\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { getMergeTagLabel } = useMergeTag();\nconst { t } = useI18n();\n\nconst displayLabel = computed(() => getMergeTagLabel(props.node.attrs.value));\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n const newValue = editValue.value.trim();\n if (newValue && newValue !== props.node.attrs.value) {\n // Update with new value and derive label from it\n props.updateAttributes({\n value: newValue,\n label: getMergeTagLabel(newValue),\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n class=\"tpl-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.9em] tpl:font-medium tpl:select-none tpl:text-[var(--tpl-primary)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-primary) 20%, transparent);\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-32 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayLabel }}\n </span>\n <button\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","import MergeTagNodeView from \"./MergeTagNodeView.vue\";\nimport type { MergeTag, SyntaxPreset } from \"@templatical/types\";\nimport { getMergeTagLabel, SYNTAX_PRESETS } from \"@templatical/types\";\nimport { InputRule, mergeAttributes, Node, PasteRule } from \"@tiptap/core\";\nimport { isNodeSelected } from \"./isNodeSelected\";\nimport { renderVueNodeView } from \"./renderVueNodeView\";\n\nexport interface MergeTagNodeOptions {\n mergeTags: MergeTag[];\n syntax: SyntaxPreset;\n}\n\n/**\n * Inserted-node attrs are intentionally limited to `label` + `value`. The\n * `MergeTag` interface also carries optional `group` / `description` for\n * the built-in picker, but those are display-only and must NOT leak into\n * the document JSON — they would bloat templates and pollute serialized\n * state. `Pick<>` makes the constraint explicit at the type level.\n */\nexport type InsertMergeTagAttrs = Pick<MergeTag, \"label\" | \"value\">;\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n mergeTagNode: {\n insertMergeTag: (attrs: InsertMergeTagAttrs) => ReturnType;\n };\n }\n}\n\nexport const MergeTagNode = Node.create<MergeTagNodeOptions>({\n name: \"mergeTagNode\",\n\n group: \"inline\",\n\n inline: true,\n\n atom: true,\n\n addOptions() {\n return {\n mergeTags: [],\n syntax: SYNTAX_PRESETS.liquid,\n };\n },\n\n addAttributes() {\n return {\n label: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-label\") || element.textContent || \"\",\n },\n value: {\n default: \"\",\n parseHTML: (element) => element.getAttribute(\"data-merge-tag\") || \"\",\n },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: \"span[data-merge-tag]\",\n },\n ];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const label = getMergeTagLabel(node.attrs.value, this.options.mergeTags);\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-merge-tag\": node.attrs.value,\n \"data-label\": label,\n }),\n label,\n ];\n },\n\n addNodeView() {\n return renderVueNodeView(MergeTagNodeView);\n },\n\n addCommands() {\n return {\n insertMergeTag:\n (attrs: InsertMergeTagAttrs) =>\n ({ commands }) => {\n // Whitelist explicitly — even if a caller smuggles extra keys via\n // a wider type assertion, only label/value reach the node attrs.\n return commands.insertContent({\n type: this.name,\n attrs: { label: attrs.label, value: attrs.value },\n });\n },\n };\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => isNodeSelected(this.editor, this.name),\n Delete: () => isNodeSelected(this.editor, this.name),\n };\n },\n\n addInputRules() {\n const inputRegex = new RegExp(this.options.syntax.value.source + \"$\", \"\");\n\n return [\n new InputRule({\n find: inputRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n const label = getMergeTagLabel(fullValue, this.options.mergeTags);\n\n const node = this.type.create({\n label,\n value: fullValue,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n\n addPasteRules() {\n const pasteRegex = new RegExp(this.options.syntax.value.source, \"g\");\n\n return [\n new PasteRule({\n find: pasteRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n const label = getMergeTagLabel(fullValue, this.options.mergeTags);\n\n const node = this.type.create({\n label,\n value: fullValue,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"extensions-DBWF_lxx.js","names":[],"sources":["../../../src/extensions/FontSize.ts","../../../src/extensions/LetterSpacing.ts","../../../src/extensions/LineHeight.ts","../../../src/extensions/LogicMergeTagNodeView.vue","../../../src/extensions/LogicMergeTagNodeView.vue","../../../src/extensions/isNodeSelected.ts","../../../src/extensions/renderVueNodeView.ts","../../../src/extensions/LogicMergeTagNode.ts","../../../src/extensions/MergeTagNodeView.vue","../../../src/extensions/MergeTagNodeView.vue","../../../src/extensions/MergeTagNode.ts"],"sourcesContent":["import { Extension } from \"@tiptap/core\";\n\nexport interface FontSizeOptions {\n types: string[];\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n fontSize: {\n setFontSize: (size: string) => ReturnType;\n unsetFontSize: () => ReturnType;\n };\n }\n}\n\nexport const FontSize = Extension.create<FontSizeOptions>({\n name: \"fontSize\",\n\n addOptions() {\n return {\n types: [\"textStyle\"],\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n fontSize: {\n default: null,\n parseHTML: (element) =>\n element.style.fontSize?.replace(/['\"]+/g, \"\") || null,\n renderHTML: (attributes) => {\n if (!attributes.fontSize) {\n return {};\n }\n return {\n style: `font-size: ${attributes.fontSize}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setFontSize:\n (size: string) =>\n ({ chain }) => {\n return chain().setMark(\"textStyle\", { fontSize: size }).run();\n },\n unsetFontSize:\n () =>\n ({ chain }) => {\n return chain()\n .setMark(\"textStyle\", { fontSize: null })\n .removeEmptyTextStyle()\n .run();\n },\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\n\nexport interface LetterSpacingOptions {\n types: string[];\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n letterSpacing: {\n setLetterSpacing: (spacing: string) => ReturnType;\n unsetLetterSpacing: () => ReturnType;\n };\n }\n}\n\nexport const LetterSpacing = Extension.create<LetterSpacingOptions>({\n name: \"letterSpacing\",\n\n addOptions() {\n return {\n types: [\"textStyle\"],\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n letterSpacing: {\n default: null,\n parseHTML: (element) =>\n element.style.letterSpacing?.replace(/['\"]+/g, \"\") || null,\n renderHTML: (attributes) => {\n if (!attributes.letterSpacing) {\n return {};\n }\n return {\n style: `letter-spacing: ${attributes.letterSpacing}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setLetterSpacing:\n (spacing: string) =>\n ({ chain }) => {\n return chain().setMark(\"textStyle\", { letterSpacing: spacing }).run();\n },\n unsetLetterSpacing:\n () =>\n ({ chain }) => {\n return chain()\n .setMark(\"textStyle\", { letterSpacing: null })\n .removeEmptyTextStyle()\n .run();\n },\n };\n },\n});\n","import { Extension } from \"@tiptap/core\";\n\nexport interface LineHeightOptions {\n types: string[];\n defaultLineHeight: string;\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n lineHeight: {\n setLineHeight: (lineHeight: string) => ReturnType;\n unsetLineHeight: () => ReturnType;\n };\n }\n}\n\nexport const LineHeight = Extension.create<LineHeightOptions>({\n name: \"lineHeight\",\n\n addOptions() {\n return {\n types: [\"paragraph\"],\n defaultLineHeight: \"1.5\",\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n lineHeight: {\n default: null,\n parseHTML: (element) => element.style.lineHeight || null,\n renderHTML: (attributes) => {\n if (!attributes.lineHeight) {\n return {};\n }\n return {\n style: `line-height: ${attributes.lineHeight}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setLineHeight:\n (lineHeight: string) =>\n ({ commands }) => {\n return this.options.types.every((type) =>\n commands.updateAttributes(type, { lineHeight }),\n );\n },\n unsetLineHeight:\n () =>\n ({ commands }) => {\n return this.options.types.every((type) =>\n commands.resetAttributes(type, \"lineHeight\"),\n );\n },\n };\n },\n});\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n} from \"@templatical/types\";\nimport type { Editor } from \"@tiptap/core\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n value: string;\n keyword: string;\n };\n };\n editor: Editor;\n getPos: () => number;\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { syntax } = useMergeTag();\nconst { t } = useI18n();\n\nconst isValid = computed(() =>\n isLogicMergeTagValue(props.node.attrs.value, syntax),\n);\nconst displayKeyword = computed(() =>\n getLogicMergeTagKeyword(props.node.attrs.value, syntax),\n);\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\nlet handled = false;\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n handled = false;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n if (handled) {\n return;\n }\n handled = true;\n\n const newValue = editValue.value.trim();\n if (!newValue) {\n isEditing.value = false;\n return;\n }\n\n if (newValue !== props.node.attrs.value) {\n props.updateAttributes({\n value: newValue,\n keyword: isLogicMergeTagValue(newValue, syntax)\n ? getLogicMergeTagKeyword(newValue, syntax)\n : \"\",\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n :class=\"\n isValid\n ? 'tpl-logic-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.8em] tpl:font-bold tpl:tracking-wide tpl:uppercase tpl:select-none'\n : ''\n \"\n :style=\"\n isValid\n ? 'background-color: transparent; border: 1.5px solid color-mix(in srgb, var(--tpl-primary) 50%, transparent); color: var(--tpl-primary);'\n : ''\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-40 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:normal-case tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode: valid merge tag -->\n <span\n v-else-if=\"isValid\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayKeyword }}\n </span>\n <!-- Display mode: invalid (plain text) -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ node.attrs.value }}\n </span>\n <button\n v-if=\"isValid\"\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n} from \"@templatical/types\";\nimport type { Editor } from \"@tiptap/core\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n value: string;\n keyword: string;\n };\n };\n editor: Editor;\n getPos: () => number;\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { syntax } = useMergeTag();\nconst { t } = useI18n();\n\nconst isValid = computed(() =>\n isLogicMergeTagValue(props.node.attrs.value, syntax),\n);\nconst displayKeyword = computed(() =>\n getLogicMergeTagKeyword(props.node.attrs.value, syntax),\n);\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\nlet handled = false;\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n handled = false;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n if (handled) {\n return;\n }\n handled = true;\n\n const newValue = editValue.value.trim();\n if (!newValue) {\n isEditing.value = false;\n return;\n }\n\n if (newValue !== props.node.attrs.value) {\n props.updateAttributes({\n value: newValue,\n keyword: isLogicMergeTagValue(newValue, syntax)\n ? getLogicMergeTagKeyword(newValue, syntax)\n : \"\",\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n :class=\"\n isValid\n ? 'tpl-logic-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.8em] tpl:font-bold tpl:tracking-wide tpl:uppercase tpl:select-none'\n : ''\n \"\n :style=\"\n isValid\n ? 'background-color: transparent; border: 1.5px solid color-mix(in srgb, var(--tpl-primary) 50%, transparent); color: var(--tpl-primary);'\n : ''\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-40 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:normal-case tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode: valid merge tag -->\n <span\n v-else-if=\"isValid\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayKeyword }}\n </span>\n <!-- Display mode: invalid (plain text) -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ node.attrs.value }}\n </span>\n <button\n v-if=\"isValid\"\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","import type { Editor } from \"@tiptap/core\";\n\n/**\n * Decides whether MergeTagNode / LogicMergeTagNode should swallow a\n * Backspace/Delete keystroke (returning `true` from a TipTap keymap\n * suppresses the default behavior).\n *\n * Only suppresses in the cursor-adjacent case so the \"first press\n * selects the atom, second press deletes it\" UX works. Range selections\n * (Cmd+A, drag-select, double-click-word) explicitly fall through —\n * default `replaceSelection` then deletes the entire range including\n * any merge-tag atoms inside it.\n *\n * Earlier revisions also returned `true` whenever `nodesBetween($from,\n * $to)` found a merge tag anywhere in the selection range — which\n * silently broke Cmd+A + Backspace for any paragraph containing a\n * merge tag (entire deletion was cancelled, nothing happened). The\n * cursor-adjacent protection is the only piece that should survive.\n */\nexport function isNodeSelected(editor: Editor, nodeTypeName: string): boolean {\n const { $from, $to } = editor.state.selection;\n\n // Range selection: let TipTap's default range-delete run. Even when\n // the range contains atom nodes, ProseMirror's replaceSelection\n // handles atomic deletion correctly.\n if ($from.pos !== $to.pos) return false;\n\n // Cursor-adjacent atom: protect from single-keystroke deletion.\n // (`$from.pos > 0` guards against reading `nodeBefore` at doc start\n // where ProseMirror's index would be undefined for nodeBefore.)\n if ($from.pos > 0 && $from.nodeBefore?.type.name === nodeTypeName) {\n return true;\n }\n if ($from.nodeAfter?.type.name === nodeTypeName) {\n return true;\n }\n\n return false;\n}\n","import type { Component } from \"vue\";\nimport { VueNodeViewRenderer } from \"@tiptap/vue-3\";\n\n/**\n * Typed wrapper for VueNodeViewRenderer that handles the known type mismatch\n * between Vue SFC default exports and TipTap's expected component type.\n */\nexport function renderVueNodeView(component: Component) {\n return VueNodeViewRenderer(\n component as Parameters<typeof VueNodeViewRenderer>[0],\n );\n}\n","import LogicMergeTagNodeView from \"./LogicMergeTagNodeView.vue\";\nimport type { SyntaxPreset } from \"@templatical/types\";\nimport {\n getLogicMergeTagKeyword,\n isLogicMergeTagValue,\n SYNTAX_PRESETS,\n} from \"@templatical/types\";\nimport { InputRule, mergeAttributes, Node, PasteRule } from \"@tiptap/core\";\nimport { isNodeSelected } from \"./isNodeSelected\";\nimport { renderVueNodeView } from \"./renderVueNodeView\";\n\nexport interface LogicMergeTagNodeOptions {\n syntax: SyntaxPreset;\n}\n\nexport const LogicMergeTagNode = Node.create<LogicMergeTagNodeOptions>({\n name: \"logicMergeTagNode\",\n\n group: \"inline\",\n\n inline: true,\n\n atom: true,\n\n addOptions() {\n return {\n syntax: SYNTAX_PRESETS.liquid,\n };\n },\n\n addAttributes() {\n return {\n value: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-logic-merge-tag\") || \"\",\n },\n keyword: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-keyword\") || element.textContent || \"\",\n },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: \"span[data-logic-merge-tag]\",\n },\n ];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n if (!isLogicMergeTagValue(node.attrs.value, this.options.syntax)) {\n return [\"span\", {}, node.attrs.value];\n }\n\n const keyword = getLogicMergeTagKeyword(\n node.attrs.value,\n this.options.syntax,\n );\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-logic-merge-tag\": node.attrs.value,\n \"data-keyword\": keyword,\n }),\n keyword,\n ];\n },\n\n addNodeView() {\n return renderVueNodeView(LogicMergeTagNodeView);\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => isNodeSelected(this.editor, this.name),\n Delete: () => isNodeSelected(this.editor, this.name),\n };\n },\n\n addInputRules() {\n const inputRegex = new RegExp(this.options.syntax.logic.source + \"$\", \"\");\n\n return [\n new InputRule({\n find: inputRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n if (!isLogicMergeTagValue(fullValue, this.options.syntax)) {\n return;\n }\n\n const keyword = getLogicMergeTagKeyword(\n fullValue,\n this.options.syntax,\n );\n\n const node = this.type.create({\n value: fullValue,\n keyword,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n\n addPasteRules() {\n const pasteRegex = new RegExp(this.options.syntax.logic.source, \"g\");\n\n return [\n new PasteRule({\n find: pasteRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n if (!isLogicMergeTagValue(fullValue, this.options.syntax)) {\n return;\n }\n\n const keyword = getLogicMergeTagKeyword(\n fullValue,\n this.options.syntax,\n );\n\n const node = this.type.create({\n value: fullValue,\n keyword,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n});\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n label: string;\n value: string;\n };\n };\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { getMergeTagLabel } = useMergeTag();\nconst { t } = useI18n();\n\nconst displayLabel = computed(() => getMergeTagLabel(props.node.attrs.value));\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n const newValue = editValue.value.trim();\n if (newValue && newValue !== props.node.attrs.value) {\n // Update with new value and derive label from it\n props.updateAttributes({\n value: newValue,\n label: getMergeTagLabel(newValue),\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n class=\"tpl-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.9em] tpl:font-medium tpl:select-none tpl:text-[var(--tpl-primary)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-primary) 20%, transparent);\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-32 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayLabel }}\n </span>\n <button\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../composables/useI18n\";\nimport { useMergeTag } from \"../composables/useMergeTag\";\nimport { NodeViewWrapper } from \"@tiptap/vue-3\";\nimport { computed, nextTick, ref } from \"vue\";\n\nconst props = defineProps<{\n node: {\n attrs: {\n label: string;\n value: string;\n };\n };\n deleteNode: () => void;\n updateAttributes: (attrs: Record<string, unknown>) => void;\n}>();\n\nconst { getMergeTagLabel } = useMergeTag();\nconst { t } = useI18n();\n\nconst displayLabel = computed(() => getMergeTagLabel(props.node.attrs.value));\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\n\nfunction startEditing(): void {\n editValue.value = props.node.attrs.value;\n isEditing.value = true;\n nextTick(() => {\n inputRef.value?.focus();\n inputRef.value?.select();\n });\n}\n\nfunction finishEditing(): void {\n const newValue = editValue.value.trim();\n if (newValue && newValue !== props.node.attrs.value) {\n // Update with new value and derive label from it\n props.updateAttributes({\n value: newValue,\n label: getMergeTagLabel(newValue),\n });\n }\n isEditing.value = false;\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\") {\n event.preventDefault();\n finishEditing();\n } else if (event.key === \"Escape\") {\n isEditing.value = false;\n }\n}\n</script>\n\n<template>\n <NodeViewWrapper\n as=\"span\"\n class=\"tpl-merge-tag-node tpl:group tpl:mx-0.5 tpl:inline-flex tpl:items-center tpl:gap-1 tpl:rounded tpl:px-1.5 tpl:py-0.5 tpl:text-[0.9em] tpl:font-medium tpl:select-none tpl:text-[var(--tpl-primary)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-primary) 20%, transparent);\n \"\n contenteditable=\"false\"\n >\n <!-- Edit mode -->\n <input\n v-if=\"isEditing\"\n ref=\"inputRef\"\n v-model=\"editValue\"\n type=\"text\"\n class=\"tpl:w-32 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-0.5 tpl:py-0 tpl:text-[1em] tpl:font-medium tpl:outline-none tpl:text-[var(--tpl-primary)]\"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"t.mergeTag.editValue\"\n class=\"tpl-tooltip tpl:cursor-pointer\"\n :data-tooltip=\"node.attrs.value\"\n @click.stop=\"startEditing\"\n @keydown.enter.stop=\"startEditing\"\n @keydown.space.prevent.stop=\"startEditing\"\n >\n {{ displayLabel }}\n </span>\n <button\n type=\"button\"\n :aria-label=\"t.mergeTag.deleteMergeTag\"\n class=\"tpl-merge-tag-delete tpl:flex tpl:size-5 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-full tpl:border-none tpl:bg-transparent tpl:p-0 tpl:opacity-60 tpl:transition-all hover:tpl:opacity-100 tpl:text-[var(--tpl-primary)]\"\n contenteditable=\"false\"\n @click.stop.prevent=\"deleteNode\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </NodeViewWrapper>\n</template>\n","import MergeTagNodeView from \"./MergeTagNodeView.vue\";\nimport type { MergeTag, SyntaxPreset } from \"@templatical/types\";\nimport { getMergeTagLabel, SYNTAX_PRESETS } from \"@templatical/types\";\nimport { InputRule, mergeAttributes, Node, PasteRule } from \"@tiptap/core\";\nimport { isNodeSelected } from \"./isNodeSelected\";\nimport { renderVueNodeView } from \"./renderVueNodeView\";\n\nexport interface MergeTagNodeOptions {\n mergeTags: MergeTag[];\n syntax: SyntaxPreset;\n}\n\n/**\n * Inserted-node attrs are intentionally limited to `label` + `value`. The\n * `MergeTag` interface also carries optional `group` / `description` for\n * the built-in picker, but those are display-only and must NOT leak into\n * the document JSON — they would bloat templates and pollute serialized\n * state. `Pick<>` makes the constraint explicit at the type level.\n */\nexport type InsertMergeTagAttrs = Pick<MergeTag, \"label\" | \"value\">;\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n mergeTagNode: {\n insertMergeTag: (attrs: InsertMergeTagAttrs) => ReturnType;\n };\n }\n}\n\nexport const MergeTagNode = Node.create<MergeTagNodeOptions>({\n name: \"mergeTagNode\",\n\n group: \"inline\",\n\n inline: true,\n\n atom: true,\n\n addOptions() {\n return {\n mergeTags: [],\n syntax: SYNTAX_PRESETS.liquid,\n };\n },\n\n addAttributes() {\n return {\n label: {\n default: \"\",\n parseHTML: (element) =>\n element.getAttribute(\"data-label\") || element.textContent || \"\",\n },\n value: {\n default: \"\",\n parseHTML: (element) => element.getAttribute(\"data-merge-tag\") || \"\",\n },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: \"span[data-merge-tag]\",\n },\n ];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const label = getMergeTagLabel(node.attrs.value, this.options.mergeTags);\n\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n \"data-merge-tag\": node.attrs.value,\n \"data-label\": label,\n }),\n label,\n ];\n },\n\n addNodeView() {\n return renderVueNodeView(MergeTagNodeView);\n },\n\n addCommands() {\n return {\n insertMergeTag:\n (attrs: InsertMergeTagAttrs) =>\n ({ commands }) => {\n // Whitelist explicitly — even if a caller smuggles extra keys via\n // a wider type assertion, only label/value reach the node attrs.\n return commands.insertContent({\n type: this.name,\n attrs: { label: attrs.label, value: attrs.value },\n });\n },\n };\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => isNodeSelected(this.editor, this.name),\n Delete: () => isNodeSelected(this.editor, this.name),\n };\n },\n\n addInputRules() {\n const inputRegex = new RegExp(this.options.syntax.value.source + \"$\", \"\");\n\n return [\n new InputRule({\n find: inputRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n const label = getMergeTagLabel(fullValue, this.options.mergeTags);\n\n const node = this.type.create({\n label,\n value: fullValue,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n\n addPasteRules() {\n const pasteRegex = new RegExp(this.options.syntax.value.source, \"g\");\n\n return [\n new PasteRule({\n find: pasteRegex,\n handler: ({ state, range, match }) => {\n const fullValue = match[0];\n const label = getMergeTagLabel(fullValue, this.options.mergeTags);\n\n const node = this.type.create({\n label,\n value: fullValue,\n });\n\n state.tr.replaceWith(range.from, range.to, node);\n },\n }),\n ];\n },\n});\n"],"mappings":"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"}
@@ -413,7 +413,8 @@ var e = {
413
413
  otherGroup: "Autres",
414
414
  cancel: "Annuler",
415
415
  close: "Fermer",
416
- groupCount: "{count}"
416
+ groupCount: "{count}",
417
+ sample: "Aperçu : {sample}"
417
418
  }
418
419
  },
419
420
  logicTag: {
@@ -569,6 +570,11 @@ var e = {
569
570
  daysAgo: "il y a {days} j"
570
571
  }
571
572
  },
573
+ mergeTagPreview: {
574
+ label: "Affichage des balises de fusion",
575
+ sample: "Exemple",
576
+ labelView: "Libellé"
577
+ },
572
578
  testEmail: {
573
579
  title: "Envoyer un e-mail de test",
574
580
  recipientLabel: "Destinataire",
@@ -576,6 +582,7 @@ var e = {
576
582
  invalidAddress: "Saisissez une adresse e-mail valide.",
577
583
  preview: "Aperçu",
578
584
  previewHint: "Les balises de fusion sont affichées non résolues — votre backend les remplace.",
585
+ previewHintSample: "Les balises de fusion affichent des valeurs d’exemple — votre backend insère les données réelles.",
579
586
  recipientNotAllowed: "Cette adresse ne figure pas dans la liste des destinataires autorisés.",
580
587
  send: "Envoyer",
581
588
  sending: "Envoi en cours...",
@@ -620,3 +627,5 @@ var e = {
620
627
  };
621
628
  //#endregion
622
629
  export { e as default };
630
+
631
+ //# sourceMappingURL=fr-DTVJ3det.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fr-DTVJ3det.js","names":[],"sources":["../../../src/i18n/locales/fr.ts"],"sourcesContent":["import type en from \"./en\";\n\nconst fr: typeof en = {\n footer: {\n poweredBy: \"Propulsé par\",\n openSource: \"Open Source\",\n },\n history: {\n undo: \"Annuler\",\n redo: \"Rétablir\",\n collabWarning:\n \"Annuler peut affecter les modifications récentes de vos collaborateurs\",\n },\n viewport: {\n label: \"Affichage\",\n desktop: \"Ordinateur\",\n mobile: \"Mobile\",\n },\n darkMode: {\n enable: \"Aperçu en mode sombre\",\n disable: \"Aperçu en mode clair\",\n },\n previewMode: {\n enable: \"Mode aperçu\",\n disable: \"Quitter l'aperçu\",\n },\n blocks: {\n section: \"Section\",\n image: \"Image\",\n title: \"Titre\",\n paragraph: \"Paragraphe\",\n button: \"Bouton\",\n divider: \"Séparateur\",\n video: \"Vidéo\",\n social: \"Réseaux sociaux\",\n spacer: \"Espaceur\",\n html: \"HTML\",\n menu: \"Menu\",\n table: \"Tableau\",\n countdown: \"Compte à rebours\",\n },\n sidebar: {\n content: \"Contenu\",\n settings: \"Paramètres\",\n noSelection: \"Aucun élément sélectionné\",\n noSelectionHint: \"Sélectionnez un bloc sur le canevas pour le modifier\",\n },\n toolbar: {\n duplicate: \"Dupliquer\",\n delete: \"Supprimer\",\n },\n titleEditor: {\n toolbar: \"Mise en forme du titre\",\n bold: \"Gras (Ctrl+B)\",\n italic: \"Italique (Ctrl+I)\",\n addLink: \"Ajouter un lien\",\n },\n paragraphEditor: {\n toolbar: \"Mise en forme du texte\",\n bold: \"Gras (Ctrl+B)\",\n italic: \"Italique (Ctrl+I)\",\n underline: \"Souligné (Ctrl+U)\",\n strikethrough: \"Barré\",\n subscript: \"Indice\",\n superscript: \"Exposant\",\n addLink: \"Ajouter un lien\",\n bulletList: \"Liste à puces\",\n numberedList: \"Liste numérotée\",\n alignLeft: \"Aligner à gauche\",\n alignCenter: \"Centrer\",\n alignRight: \"Aligner à droite\",\n clearFormatting: \"Effacer la mise en forme\",\n insertEmoji: \"Insérer un émoji\",\n fontFamily: \"Police\",\n defaultFont: \"Par défaut\",\n fontSize: \"Taille de police\",\n defaultSize: \"Par défaut\",\n textColor: \"Couleur du texte\",\n highlightColor: \"Couleur de surlignage\",\n lineHeight: \"Interligne\",\n letterSpacing: \"Espacement des lettres\",\n emojiItemLabel: \"Insérer l'émoji {emoji}\",\n closeEmojiPicker: \"Fermer le sélecteur d'émojis\",\n },\n blockActions: {\n drag: \"Faites glisser pour réorganiser, ou appuyez sur Espace pour déplacer au clavier\",\n dragLifted:\n \"Déplacement de {block}. Utilisez les flèches haut et bas pour repositionner, Espace ou Entrée pour déposer, Échap pour annuler.\",\n duplicate: \"Dupliquer le bloc\",\n delete: \"Supprimer le bloc\",\n hiddenOnViewport: \"Masqué sur {viewport}\",\n saveAsBlock: \"Enregistrer comme bloc\",\n conditionToggle: \"Basculer la condition d'affichage\",\n comments: \"Commentaires ({count})\",\n lifted: \"{block} saisi. Position {position} sur {total}.\",\n moved: \"{block} déplacé en position {position} sur {total}.\",\n dropped: \"{block} déposé en position {position} sur {total}.\",\n cancelled: \"Déplacement annulé. {block} est revenu en position {position}.\",\n },\n section: {\n dropHere: \"Déposez des blocs ici\",\n columns: \"Colonnes\",\n column1: \"1 colonne\",\n column2: \"2 colonnes\",\n column3: \"3 colonnes\",\n ratio12: \"Ratio 1:2\",\n ratio21: \"Ratio 2:1\",\n borderRadius: \"Rayon de bordure\",\n wrapperEnable: \"Ajouter un conteneur\",\n stackOnMobile: \"Empiler sur mobile\",\n },\n linkDialog: {\n editLink: \"Modifier le lien\",\n insertLink: \"Insérer un lien\",\n updateLink: \"Mettre à jour le lien\",\n removeLink: \"Supprimer le lien\",\n cancel: \"Annuler\",\n urlPlaceholder: \"https://example.com\",\n urlLabel: \"URL\",\n colorLabel: \"Couleur du lien\",\n },\n title: {\n level: \"Niveau de titre\",\n heading1: \"Titre 1 (36px)\",\n heading2: \"Titre 2 (28px)\",\n heading3: \"Titre 3 (22px)\",\n heading4: \"Titre 4 (18px)\",\n fontFamily: \"Police\",\n inheritFont: \"Utiliser la police du modèle\",\n color: \"Couleur\",\n align: \"Aligner\",\n alignLeft: \"Gauche\",\n alignCenter: \"Centre\",\n alignRight: \"Droite\",\n },\n emoji: {\n smileys: \"Smileys\",\n gestures: \"Gestes\",\n objects: \"Objets\",\n },\n image: {\n imageUrl: \"URL de l'image\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Texte alternatif\",\n altTextPlaceholder: \"Description de l'image\",\n width: \"Largeur\",\n fullWidth: \"Pleine largeur\",\n widthCustom: \"Personnalisée\",\n linkUrl: \"URL du lien\",\n openInNewTab: \"Ouvrir dans un nouvel onglet\",\n placeholderUrl: \"Image de substitution\",\n placeholderUrlPlaceholder: \"https://... (conception uniquement)\",\n placeholderUrlTooltip:\n \"L'URL de l'image utilisant une balise de fusion, vous pouvez fournir ici une vraie image pour prévisualiser la mise en page pendant la conception. Elle n'est pas incluse dans le résultat final.\",\n clickToAdd: \"Cliquez pour ajouter l'URL de l'image\",\n browseMedia: \"Parcourir la médiathèque\",\n dropToUpload: \"Déposez une image pour la téléverser\",\n uploading: \"Téléversement…\",\n decorative: \"Image décorative\",\n decorativeHint:\n \"Masquée pour les lecteurs d'écran. À réserver aux espaceurs et ornements visuels.\",\n },\n video: {\n videoUrl: \"URL de la vidéo\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n youtube: \"YouTube\",\n vimeo: \"Vimeo\",\n detected: \"Vidéo détectée — la miniature sera générée automatiquement\",\n openInNewTab: \"Ouvrir dans un nouvel onglet\",\n customThumbnail: \"Miniature personnalisée\",\n optional: \"(facultatif)\",\n thumbnailPlaceholder: \"Générée automatiquement depuis l'URL de la vidéo\",\n altText: \"Texte alternatif\",\n altTextPlaceholder: \"Description de la vidéo\",\n width: \"Largeur\",\n fullWidth: \"Pleine largeur\",\n placeholderUrl: \"Miniature de substitution\",\n placeholderUrlPlaceholder: \"https://... (conception uniquement)\",\n placeholderUrlTooltip:\n \"L'URL de la vidéo utilisant une balise de fusion, vous pouvez fournir ici une vraie miniature pour prévisualiser la mise en page pendant la conception. Elle n'est pas incluse dans le résultat final.\",\n addVideo: \"Ajoutez une URL de vidéo\",\n },\n button: {\n fontFamily: \"Police\",\n inheritFont: \"Utiliser la police du modèle\",\n text: \"Texte\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"Ouvrir dans un nouvel onglet\",\n background: \"Fond\",\n textColor: \"Couleur du texte\",\n borderRadius: \"Rayon de bordure\",\n fontSize: \"Taille de police\",\n width: \"Largeur\",\n widthAuto: \"Ajuster au contenu\",\n fullWidth: \"Pleine largeur\",\n widthCustom: \"Personnalisée\",\n },\n divider: {\n style: \"Style\",\n solid: \"Continu\",\n dashed: \"Tirets\",\n dotted: \"Pointillés\",\n color: \"Couleur\",\n thickness: \"Épaisseur\",\n },\n social: {\n icons: \"Icônes\",\n addIcon: \"Ajouter une icône\",\n addIcons: \"Ajoutez des icônes de réseaux sociaux\",\n removeIcon: \"Supprimer\",\n platform: \"Plateforme\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n style: \"Style\",\n styleSolid: \"Plein\",\n styleOutlined: \"Contour\",\n styleRounded: \"Arrondi\",\n styleSquare: \"Carré\",\n styleCircle: \"Cercle\",\n size: \"Taille\",\n sizeSmall: \"S\",\n sizeMedium: \"M\",\n sizeLarge: \"L\",\n spacing: \"Espacement\",\n align: \"Alignement\",\n platforms: {\n facebook: \"Facebook\",\n twitter: \"X (Twitter)\",\n instagram: \"Instagram\",\n linkedin: \"LinkedIn\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n pinterest: \"Pinterest\",\n email: \"E-mail\",\n website: \"Site web\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n menu: {\n items: \"Éléments du menu\",\n addItem: \"Ajouter un élément\",\n removeItem: \"Supprimer\",\n text: \"Texte\",\n url: \"URL\",\n urlPlaceholder: \"https://example.com\",\n openInNewTab: \"Ouvrir dans un nouvel onglet\",\n bold: \"Gras\",\n underline: \"Souligné\",\n color: \"Couleur\",\n linkColor: \"Couleur des liens\",\n fontSize: \"Taille de police\",\n fontFamily: \"Police\",\n separator: \"Séparateur\",\n separatorColor: \"Couleur du séparateur\",\n spacing: \"Espacement\",\n textAlign: \"Alignement\",\n addLinks: \"Ajoutez des liens de menu\",\n },\n table: {\n dimensions: \"Dimensions\",\n rows: \"Lignes\",\n columns: \"Colonnes\",\n addRow: \"Ajouter une ligne\",\n removeRow: \"Supprimer la ligne\",\n addColumn: \"Ajouter une colonne\",\n removeColumn: \"Supprimer la colonne\",\n hasHeaderRow: \"Ligne d'en-tête\",\n headerBackgroundColor: \"Fond de l'en-tête\",\n noHeaderBg: \"Sans fond\",\n borderColor: \"Couleur de bordure\",\n borderWidth: \"Épaisseur de bordure\",\n cellPadding: \"Marge intérieure des cellules\",\n fontFamily: \"Police\",\n fontSize: \"Taille de police\",\n color: \"Couleur du texte\",\n textAlign: \"Alignement\",\n cellPlaceholder: \"Saisissez du texte...\",\n empty: \"Ajoutez un tableau\",\n },\n spacer: {\n height: \"Hauteur\",\n },\n countdown: {\n targetDate: \"Date cible\",\n timezone: \"Fuseau horaire\",\n display: \"Affichage\",\n days: \"Jours\",\n hours: \"Heures\",\n minutes: \"Minutes\",\n seconds: \"Secondes\",\n separator: \"Séparateur\",\n fontFamily: \"Police\",\n inheritFont: \"Par défaut\",\n digitFontSize: \"Taille des chiffres\",\n digitColor: \"Couleur des chiffres\",\n labelColor: \"Couleur des libellés\",\n labelFontSize: \"Taille des libellés\",\n background: \"Fond\",\n labels: \"Libellés\",\n expiry: \"Message d'expiration\",\n expiredMessagePlaceholder: \"Cette offre a expiré\",\n expiredImageUrl: \"URL de l'image d'expiration\",\n hideOnExpiry: \"Masquer à l'expiration\",\n setDate: \"Définissez une date cible dans le panneau des paramètres\",\n hidden: \"Masqué (expiré)\",\n },\n customBlocks: {\n definitionNotFound: \"Type de bloc inconnu — ce bloc n'est pas enregistré\",\n renderError:\n \"Ce bloc n'a pas pu être rendu. Vérifiez les erreurs dans le modèle du bloc.\",\n fields: {\n required: \"Obligatoire\",\n addItem: \"Ajouter un élément\",\n removeItem: \"Supprimer\",\n maxItemsReached: \"Nombre maximal d'éléments atteint\",\n minItemsRequired: \"Minimum {count} éléments requis\",\n },\n toolbar: {\n noDefinition:\n \"Enregistrez ce type de bloc dans la configuration du SDK pour modifier ses propriétés\",\n },\n dataSource: {\n fetchButton: \"Charger le contenu\",\n changeButton: \"Changer\",\n fetching: \"Chargement...\",\n readOnlyTooltip: \"Cette valeur provient de votre source de données\",\n fetchError: \"Échec du chargement du contenu\",\n },\n },\n html: {\n content: \"Contenu HTML\",\n preview: \"Bloc HTML personnalisé\",\n empty: \"Ajoutez du contenu HTML dans le panneau\",\n sanitizationHint:\n \"Le HTML est exporté tel quel, sans assainissement — assurez-vous que le contenu est sûr.\",\n },\n blockSettings: {\n spacing: \"Espacement\",\n padding: \"Marge intérieure\",\n background: \"Fond\",\n color: \"Couleur\",\n display: \"Affichage\",\n showOnDesktop: \"Afficher sur ordinateur\",\n showOnMobile: \"Afficher sur mobile\",\n hiddenOnDevice: \"Masqué sur {device}\",\n displayCondition: \"Condition d'affichage\",\n selectCondition: \"Sélectionner une condition\",\n removeCondition: \"Supprimer la condition\",\n noCondition: \"Toujours visible\",\n conditionApplied: \"Condition appliquée\",\n customCondition: \"Condition personnalisée\",\n customConditionLabel: \"Nom de la condition\",\n customConditionBefore: \"Avant (logique d'ouverture)\",\n customConditionAfter: \"Après (logique de fermeture)\",\n applyCondition: \"Appliquer\",\n cancelCondition: \"Annuler\",\n customBadge: \"Personnalisée\",\n restoreHiddenBlocks: \"Afficher tous les blocs masqués\",\n },\n templateSettings: {\n layout: \"Mise en page\",\n widthPreset: \"Largeur prédéfinie\",\n customWidth: \"Largeur personnalisée\",\n appearance: \"Apparence\",\n backgroundColor: \"Couleur de fond\",\n textColor: \"Couleur du texte\",\n linkColor: \"Couleur des liens\",\n linkUnderline: \"Souligner les liens\",\n fontFamily: \"Police\",\n preheaderText: \"Texte d'aperçu (preheader)\",\n preheaderTextPlaceholder:\n \"Texte d'aperçu affiché après l'objet dans la boîte de réception...\",\n preheaderTextHint:\n \"Ce texte apparaît après l'objet dans les aperçus des clients de messagerie. Les balises de fusion sont prises en charge.\",\n language: \"Langue\",\n contentLocale: \"Langue du contenu\",\n contentLocaleHint:\n \"Code BCP 47 (ex. fr, de, pt-BR). Définit l'attribut lang de l'e-mail rendu pour que les lecteurs d'écran prononcent correctement le contenu.\",\n tips: \"Conseils\",\n tip1: \"600px est la largeur standard des modèles d'e-mail\",\n tip2: \"Utilisez des polices web sûres pour une compatibilité maximale\",\n tip3: \"Les fonds clairs offrent la meilleure lisibilité\",\n },\n spacingControl: {\n lockAll: \"Verrouiller tous les côtés\",\n unlock: \"Déverrouiller les côtés\",\n top: \"Haut\",\n right: \"Droite\",\n bottom: \"Bas\",\n left: \"Gauche\",\n decreaseTop: \"Réduire en haut\",\n increaseTop: \"Augmenter en haut\",\n decreaseLeft: \"Réduire à gauche\",\n increaseLeft: \"Augmenter à gauche\",\n decreaseRight: \"Réduire à droite\",\n increaseRight: \"Augmenter à droite\",\n decreaseBottom: \"Réduire en bas\",\n increaseBottom: \"Augmenter en bas\",\n },\n colorPicker: {\n pickColor: \"Choisir une couleur\",\n hexValue: \"Valeur hexadécimale de la couleur\",\n notSet: \"Non définie\",\n clear: \"Effacer la couleur\",\n presetColors: \"Couleurs prédéfinies\",\n },\n mergeTag: {\n clickToEdit: \"Cliquez pour modifier\",\n remove: \"Supprimer la balise de fusion\",\n insert: \"Insérer une balise de fusion\",\n insertShort: \"Balise de fusion\",\n editValue: \"Modifier la valeur de la balise de fusion\",\n deleteMergeTag: \"Supprimer la balise de fusion\",\n suggestionEmpty: \"Aucune balise de fusion correspondante\",\n picker: {\n title: \"Insérer une balise de fusion\",\n searchPlaceholder: \"Rechercher des balises de fusion\",\n searchAriaLabel: \"Rechercher des balises de fusion\",\n noResults: \"Aucune balise de fusion correspondante\",\n empty: \"Aucune balise de fusion configurée\",\n otherGroup: \"Autres\",\n cancel: \"Annuler\",\n close: \"Fermer\",\n groupCount: \"{count}\",\n sample: \"Aperçu : {sample}\",\n },\n },\n logicTag: {\n insert: \"Insérer une logique\",\n insertShort: \"Logique\",\n picker: {\n title: \"Insérer une logique\",\n searchPlaceholder: \"Rechercher des balises logiques\",\n searchAriaLabel: \"Rechercher des balises logiques\",\n noResults: \"Aucune balise logique correspondante\",\n empty: \"Aucune balise logique configurée\",\n otherGroup: \"Autres\",\n close: \"Fermer\",\n },\n },\n canvas: {\n noBlocks: \"Aucun bloc pour l'instant\",\n dragHint:\n \"Partez de zéro en faisant glisser des blocs depuis la barre latérale\",\n dropHere: \"Déposez ici\",\n aiHintChat: \"ou laissez\",\n aiHintChatSuffix:\n \"générer un modèle complet pour vous en quelques secondes\",\n aiHintDesign:\n \"Vous avez déjà un design ? Téléversez une capture d'écran, une image ou un PDF et\",\n aiHintDesignSuffix: \"le recréera instantanément\",\n },\n mediaLibrary: {\n title: \"Médiathèque\",\n searchPlaceholder: \"Rechercher des fichiers...\",\n allFiles: \"Tous les fichiers\",\n filterAll: \"Tous les types\",\n filterImages: \"Images\",\n filterDocuments: \"Documents\",\n filterVideos: \"Vidéos\",\n filterAudio: \"Audio\",\n newFolder: \"Nouveau dossier\",\n folderName: \"Nom du dossier\",\n noFiles: \"Aucun fichier trouvé\",\n dropOrClick: \"Déposez des fichiers ici ou cliquez pour téléverser\",\n acceptedFormats: \"Images, PDF, vidéo, audio, documents (max 10 Mo)\",\n uploading: \"Téléversement...\",\n uploadingProgress: \"Téléversement de {current} sur {total}...\",\n selectImage: \"Sélectionner l'image\",\n selectFile: \"Sélectionner le fichier\",\n deleteSelected: \"Supprimer\",\n copyUrl: \"Copier l'URL\",\n copied: \"Copié !\",\n browseMedia: \"Parcourir la médiathèque\",\n renameFolder: \"Renommer le dossier\",\n addSubfolder: \"Ajouter un sous-dossier\",\n subfolderName: \"Nom du sous-dossier\",\n sortNewest: \"Plus récents d'abord\",\n sortOldest: \"Plus anciens d'abord\",\n sortNameAsc: \"Nom A-Z\",\n sortNameDesc: \"Nom Z-A\",\n sortSizeAsc: \"Plus petits d'abord\",\n sortSizeDesc: \"Plus grands d'abord\",\n moveSelected: \"Déplacer\",\n moveToRoot: \"Tous les fichiers\",\n currentFolder: \"(actuel)\",\n confirmDelete: \"Supprimer ce fichier ?\",\n renameFile: \"Renommer\",\n editFile: \"Modifier le fichier\",\n fileName: \"Nom de fichier\",\n altText: \"Texte alternatif\",\n altTextPlaceholder: \"Décrivez cette image pour l'accessibilité\",\n saveChanges: \"Enregistrer\",\n cancel: \"Annuler\",\n frequentlyUsed: \"Fréquemment utilisés\",\n deleteWarningTitle: \"Supprimer le fichier\",\n deleteWarningMessage:\n \"Ce fichier sera définitivement supprimé et ne pourra pas être récupéré.\",\n deleteWarningUsageNote:\n \"Les fichiers suivants sont utilisés dans des modèles. Les supprimer peut casser ces modèles.\",\n deleteAnyway: \"Supprimer le fichier\",\n usedInTemplates: \"Utilisé dans {count} modèle(s)\",\n viewGrid: \"Vue en grille\",\n viewList: \"Vue en liste\",\n showFolders: \"Afficher les dossiers\",\n hideFolders: \"Masquer les dossiers\",\n importFromUrl: \"Importer depuis une URL\",\n importUrlPlaceholder: \"https://example.com/image.jpg\",\n import: \"Importer\",\n importing: \"Importation...\",\n importError: \"Échec de l'importation depuis l'URL\",\n conversionLabel: \"Taille\",\n conversionOriginal: \"Originale\",\n conversionSmall: \"Petite (150px)\",\n conversionMedium: \"Moyenne (600px)\",\n conversionLarge: \"Grande (1200px)\",\n replaceFile: \"Remplacer le fichier\",\n replaceWarningTitle: \"Remplacer le fichier\",\n replaceWarningMessage:\n \"Vous êtes sur le point de remplacer ce fichier. Le remplacement doit avoir la même extension ({extension}).\",\n replaceWarningUsageNote:\n \"Ce fichier est utilisé dans {count} modèle(s). Le remplacer mettra à jour toutes les références.\",\n replaceSelectFile: \"Sélectionner le fichier de remplacement\",\n replace: \"Remplacer\",\n replacing: \"Remplacement...\",\n replaceError: \"Échec du remplacement du fichier\",\n saving: \"Enregistrement...\",\n cropAspectRatio: \"Proportions\",\n cropFree: \"Libre\",\n cropSquare: \"1:1\",\n cropLandscape43: \"4:3\",\n cropLandscape169: \"16:9\",\n cropOriginal: \"Originales\",\n cropMaxWidth: \"Largeur max\",\n cropMaxHeight: \"Hauteur max\",\n cropOutputSize: \"Taille de sortie\",\n cropPixels: \"px\",\n cropOptional: \"(facultatif)\",\n storageTooltip: \"{used} sur {total} utilisés ({remaining} restants)\",\n },\n savedBlocks: {\n title: \"Blocs enregistrés\",\n saveAsBlock: \"Enregistrer comme bloc\",\n name: \"Nom\",\n namePlaceholder: \"p. ex. En-tête, Pied de page, CTA...\",\n save: \"Enregistrer le bloc\",\n saving: \"Enregistrement...\",\n cancel: \"Annuler\",\n empty: \"Aucun bloc enregistré pour l'instant\",\n emptyHint:\n \"Enregistrez des blocs depuis vos modèles pour les réutiliser plus tard.\",\n noResults: \"Aucun bloc enregistré ne correspond à votre recherche\",\n search: \"Rechercher des blocs enregistrés...\",\n loading: \"Chargement des blocs enregistrés…\",\n category: \"Catégorie\",\n categoryPlaceholder: \"p. ex. En-têtes, Promos... (facultatif)\",\n allCategories: \"Toutes les catégories\",\n filterByCategory: \"Filtrer par catégorie\",\n insert: \"Insérer\",\n rename: \"Renommer\",\n delete: \"Supprimer\",\n deleteConfirm: \"Supprimer ce bloc enregistré ?\",\n blockCount: \"{count} bloc(s)\",\n browse: \"Parcourir les blocs enregistrés\",\n selectToPreview: \"Sélectionnez un bloc enregistré pour l'afficher\",\n insertAtBeginning: \"Au début\",\n insertAfterBlock: \"Après {block}\",\n insertAtEnd: \"À la fin\",\n insertPosition: \"Position d'insertion\",\n close: \"Fermer\",\n pickToolbar: \"Sélection de blocs à enregistrer\",\n pickCount: \"{count} bloc(s) sélectionné(s)\",\n pickHint: \"Cliquez sur les blocs pour les ajouter ou les retirer\",\n savingCount: \"Enregistrement de {count} bloc(s) :\",\n reorderHint:\n \"Glissez pour réordonner — les blocs sont enregistrés dans cet ordre\",\n reorderHandle: \"Réordonner {block}, position {position} sur {total}\",\n reorderAnnouncement: \"{block} déplacé en position {position} sur {total}\",\n expand: \"Développer\",\n collapse: \"Réduire\",\n expandPreview: \"Développer l'aperçu de {block}\",\n collapsePreview: \"Réduire l'aperçu de {block}\",\n time: {\n justNow: \"À l'instant\",\n minutesAgo: \"il y a {minutes} min\",\n hoursAgo: \"il y a {hours} h\",\n daysAgo: \"il y a {days} j\",\n },\n },\n mergeTagPreview: {\n label: \"Affichage des balises de fusion\",\n sample: \"Exemple\",\n labelView: \"Libellé\",\n },\n testEmail: {\n title: \"Envoyer un e-mail de test\",\n recipientLabel: \"Destinataire\",\n recipientPlaceholder: \"vous@exemple.fr\",\n invalidAddress: \"Saisissez une adresse e-mail valide.\",\n preview: \"Aperçu\",\n previewHint:\n \"Les balises de fusion sont affichées non résolues — votre backend les remplace.\",\n previewHintSample:\n \"Les balises de fusion affichent des valeurs d’exemple — votre backend insère les données réelles.\",\n recipientNotAllowed:\n \"Cette adresse ne figure pas dans la liste des destinataires autorisés.\",\n send: \"Envoyer\",\n sending: \"Envoi en cours...\",\n cancel: \"Annuler\",\n success: \"E-mail de test envoyé avec succès\",\n button: \"Test\",\n },\n sidebarNav: {\n browseSavedBlocks: \"Parcourir les blocs enregistrés\",\n expandSidebar: \"Développer la barre latérale des blocs\",\n palette: \"Palette de blocs\",\n insertBlock: \"Insérer un bloc {block}\",\n },\n landmarks: {\n canvas: \"Canevas de l'e-mail\",\n blockToolbar: \"Propriétés du bloc\",\n rightSidebar: \"Propriétés du bloc et paramètres du modèle\",\n reorderAnnouncements: \"Annonces de réorganisation des blocs\",\n },\n errors: {\n editorLoading: \"Chargement de l'éditeur...\",\n editorLoadFailed: \"Échec du chargement de l'éditeur.\",\n retry: \"Réessayer\",\n },\n issues: {\n panelTitle: \"Problèmes\",\n panelTabLabel: \"Problèmes\",\n groupErrors: \"Erreurs\",\n groupWarnings: \"Avertissements\",\n groupInfo: \"Infos\",\n jump: \"Aller au bloc\",\n fix: \"Corriger\",\n emptyState: \"Aucun problème — tout va bien.\",\n badgeError: \"Contient des erreurs\",\n badgeWarning: \"Contient des avertissements\",\n issueCountTooltip: \"{count} problème(s)\",\n },\n smallScreen: {\n title: \"Écran plus grand requis\",\n message:\n \"L'éditeur a besoin de plus d'espace que cet écran n'en offre. Ouvrez-le sur une tablette ou un ordinateur pour commencer à modifier.\",\n },\n};\n\nexport default fr;\n"],"mappings":";AAEA,IAAM,IAAgB;CACpB,QAAQ;EACN,WAAW;EACX,YAAY;CACd;CACA,SAAS;EACP,MAAM;EACN,MAAM;EACN,eACE;CACJ;CACA,UAAU;EACR,OAAO;EACP,SAAS;EACT,QAAQ;CACV;CACA,UAAU;EACR,QAAQ;EACR,SAAS;CACX;CACA,aAAa;EACX,QAAQ;EACR,SAAS;CACX;CACA,QAAQ;EACN,SAAS;EACT,OAAO;EACP,OAAO;EACP,WAAW;EACX,QAAQ;EACR,SAAS;EACT,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,MAAM;EACN,MAAM;EACN,OAAO;EACP,WAAW;CACb;CACA,SAAS;EACP,SAAS;EACT,UAAU;EACV,aAAa;EACb,iBAAiB;CACnB;CACA,SAAS;EACP,WAAW;EACX,QAAQ;CACV;CACA,aAAa;EACX,SAAS;EACT,MAAM;EACN,QAAQ;EACR,SAAS;CACX;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;EACN,QAAQ;EACR,WAAW;EACX,eAAe;EACf,WAAW;EACX,aAAa;EACb,SAAS;EACT,YAAY;EACZ,cAAc;EACd,WAAW;EACX,aAAa;EACb,YAAY;EACZ,iBAAiB;EACjB,aAAa;EACb,YAAY;EACZ,aAAa;EACb,UAAU;EACV,aAAa;EACb,WAAW;EACX,gBAAgB;EAChB,YAAY;EACZ,eAAe;EACf,gBAAgB;EAChB,kBAAkB;CACpB;CACA,cAAc;EACZ,MAAM;EACN,YACE;EACF,WAAW;EACX,QAAQ;EACR,kBAAkB;EAClB,aAAa;EACb,iBAAiB;EACjB,UAAU;EACV,QAAQ;EACR,OAAO;EACP,SAAS;EACT,WAAW;CACb;CACA,SAAS;EACP,UAAU;EACV,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,cAAc;EACd,eAAe;EACf,eAAe;CACjB;CACA,YAAY;EACV,UAAU;EACV,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,QAAQ;EACR,gBAAgB;EAChB,UAAU;EACV,YAAY;CACd;CACA,OAAO;EACL,OAAO;EACP,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EACV,YAAY;EACZ,aAAa;EACb,OAAO;EACP,OAAO;EACP,WAAW;EACX,aAAa;EACb,YAAY;CACd;CACA,OAAO;EACL,SAAS;EACT,UAAU;EACV,SAAS;CACX;CACA,OAAO;EACL,UAAU;EACV,qBAAqB;EACrB,SAAS;EACT,oBAAoB;EACpB,OAAO;EACP,WAAW;EACX,aAAa;EACb,SAAS;EACT,cAAc;EACd,gBAAgB;EAChB,2BAA2B;EAC3B,uBACE;EACF,YAAY;EACZ,aAAa;EACb,cAAc;EACd,WAAW;EACX,YAAY;EACZ,gBACE;CACJ;CACA,OAAO;EACL,UAAU;EACV,qBAAqB;EACrB,SAAS;EACT,OAAO;EACP,UAAU;EACV,cAAc;EACd,iBAAiB;EACjB,UAAU;EACV,sBAAsB;EACtB,SAAS;EACT,oBAAoB;EACpB,OAAO;EACP,WAAW;EACX,gBAAgB;EAChB,2BAA2B;EAC3B,uBACE;EACF,UAAU;CACZ;CACA,QAAQ;EACN,YAAY;EACZ,aAAa;EACb,MAAM;EACN,KAAK;EACL,gBAAgB;EAChB,cAAc;EACd,YAAY;EACZ,WAAW;EACX,cAAc;EACd,UAAU;EACV,OAAO;EACP,WAAW;EACX,WAAW;EACX,aAAa;CACf;CACA,SAAS;EACP,OAAO;EACP,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,WAAW;CACb;CACA,QAAQ;EACN,OAAO;EACP,SAAS;EACT,UAAU;EACV,YAAY;EACZ,UAAU;EACV,KAAK;EACL,gBAAgB;EAChB,OAAO;EACP,YAAY;EACZ,eAAe;EACf,cAAc;EACd,aAAa;EACb,aAAa;EACb,MAAM;EACN,WAAW;EACX,YAAY;EACZ,WAAW;EACX,SAAS;EACT,OAAO;EACP,WAAW;GACT,UAAU;GACV,SAAS;GACT,WAAW;GACX,UAAU;GACV,SAAS;GACT,QAAQ;GACR,WAAW;GACX,OAAO;GACP,SAAS;GACT,UAAU;GACV,UAAU;GACV,SAAS;GACT,UAAU;GACV,QAAQ;GACR,QAAQ;GACR,UAAU;GACV,SAAS;EACX;CACF;CACA,MAAM;EACJ,OAAO;EACP,SAAS;EACT,YAAY;EACZ,MAAM;EACN,KAAK;EACL,gBAAgB;EAChB,cAAc;EACd,MAAM;EACN,WAAW;EACX,OAAO;EACP,WAAW;EACX,UAAU;EACV,YAAY;EACZ,WAAW;EACX,gBAAgB;EAChB,SAAS;EACT,WAAW;EACX,UAAU;CACZ;CACA,OAAO;EACL,YAAY;EACZ,MAAM;EACN,SAAS;EACT,QAAQ;EACR,WAAW;EACX,WAAW;EACX,cAAc;EACd,cAAc;EACd,uBAAuB;EACvB,YAAY;EACZ,aAAa;EACb,aAAa;EACb,aAAa;EACb,YAAY;EACZ,UAAU;EACV,OAAO;EACP,WAAW;EACX,iBAAiB;EACjB,OAAO;CACT;CACA,QAAQ,EACN,QAAQ,UACV;CACA,WAAW;EACT,YAAY;EACZ,UAAU;EACV,SAAS;EACT,MAAM;EACN,OAAO;EACP,SAAS;EACT,SAAS;EACT,WAAW;EACX,YAAY;EACZ,aAAa;EACb,eAAe;EACf,YAAY;EACZ,YAAY;EACZ,eAAe;EACf,YAAY;EACZ,QAAQ;EACR,QAAQ;EACR,2BAA2B;EAC3B,iBAAiB;EACjB,cAAc;EACd,SAAS;EACT,QAAQ;CACV;CACA,cAAc;EACZ,oBAAoB;EACpB,aACE;EACF,QAAQ;GACN,UAAU;GACV,SAAS;GACT,YAAY;GACZ,iBAAiB;GACjB,kBAAkB;EACpB;EACA,SAAS,EACP,cACE,wFACJ;EACA,YAAY;GACV,aAAa;GACb,cAAc;GACd,UAAU;GACV,iBAAiB;GACjB,YAAY;EACd;CACF;CACA,MAAM;EACJ,SAAS;EACT,SAAS;EACT,OAAO;EACP,kBACE;CACJ;CACA,eAAe;EACb,SAAS;EACT,SAAS;EACT,YAAY;EACZ,OAAO;EACP,SAAS;EACT,eAAe;EACf,cAAc;EACd,gBAAgB;EAChB,kBAAkB;EAClB,iBAAiB;EACjB,iBAAiB;EACjB,aAAa;EACb,kBAAkB;EAClB,iBAAiB;EACjB,sBAAsB;EACtB,uBAAuB;EACvB,sBAAsB;EACtB,gBAAgB;EAChB,iBAAiB;EACjB,aAAa;EACb,qBAAqB;CACvB;CACA,kBAAkB;EAChB,QAAQ;EACR,aAAa;EACb,aAAa;EACb,YAAY;EACZ,iBAAiB;EACjB,WAAW;EACX,WAAW;EACX,eAAe;EACf,YAAY;EACZ,eAAe;EACf,0BACE;EACF,mBACE;EACF,UAAU;EACV,eAAe;EACf,mBACE;EACF,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;CACR;CACA,gBAAgB;EACd,SAAS;EACT,QAAQ;EACR,KAAK;EACL,OAAO;EACP,QAAQ;EACR,MAAM;EACN,aAAa;EACb,aAAa;EACb,cAAc;EACd,cAAc;EACd,eAAe;EACf,eAAe;EACf,gBAAgB;EAChB,gBAAgB;CAClB;CACA,aAAa;EACX,WAAW;EACX,UAAU;EACV,QAAQ;EACR,OAAO;EACP,cAAc;CAChB;CACA,UAAU;EACR,aAAa;EACb,QAAQ;EACR,QAAQ;EACR,aAAa;EACb,WAAW;EACX,gBAAgB;EAChB,iBAAiB;EACjB,QAAQ;GACN,OAAO;GACP,mBAAmB;GACnB,iBAAiB;GACjB,WAAW;GACX,OAAO;GACP,YAAY;GACZ,QAAQ;GACR,OAAO;GACP,YAAY;GACZ,QAAQ;EACV;CACF;CACA,UAAU;EACR,QAAQ;EACR,aAAa;EACb,QAAQ;GACN,OAAO;GACP,mBAAmB;GACnB,iBAAiB;GACjB,WAAW;GACX,OAAO;GACP,YAAY;GACZ,OAAO;EACT;CACF;CACA,QAAQ;EACN,UAAU;EACV,UACE;EACF,UAAU;EACV,YAAY;EACZ,kBACE;EACF,cACE;EACF,oBAAoB;CACtB;CACA,cAAc;EACZ,OAAO;EACP,mBAAmB;EACnB,UAAU;EACV,WAAW;EACX,cAAc;EACd,iBAAiB;EACjB,cAAc;EACd,aAAa;EACb,WAAW;EACX,YAAY;EACZ,SAAS;EACT,aAAa;EACb,iBAAiB;EACjB,WAAW;EACX,mBAAmB;EACnB,aAAa;EACb,YAAY;EACZ,gBAAgB;EAChB,SAAS;EACT,QAAQ;EACR,aAAa;EACb,cAAc;EACd,cAAc;EACd,eAAe;EACf,YAAY;EACZ,YAAY;EACZ,aAAa;EACb,cAAc;EACd,aAAa;EACb,cAAc;EACd,cAAc;EACd,YAAY;EACZ,eAAe;EACf,eAAe;EACf,YAAY;EACZ,UAAU;EACV,UAAU;EACV,SAAS;EACT,oBAAoB;EACpB,aAAa;EACb,QAAQ;EACR,gBAAgB;EAChB,oBAAoB;EACpB,sBACE;EACF,wBACE;EACF,cAAc;EACd,iBAAiB;EACjB,UAAU;EACV,UAAU;EACV,aAAa;EACb,aAAa;EACb,eAAe;EACf,sBAAsB;EACtB,QAAQ;EACR,WAAW;EACX,aAAa;EACb,iBAAiB;EACjB,oBAAoB;EACpB,iBAAiB;EACjB,kBAAkB;EAClB,iBAAiB;EACjB,aAAa;EACb,qBAAqB;EACrB,uBACE;EACF,yBACE;EACF,mBAAmB;EACnB,SAAS;EACT,WAAW;EACX,cAAc;EACd,QAAQ;EACR,iBAAiB;EACjB,UAAU;EACV,YAAY;EACZ,iBAAiB;EACjB,kBAAkB;EAClB,cAAc;EACd,cAAc;EACd,eAAe;EACf,gBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,gBAAgB;CAClB;CACA,aAAa;EACX,OAAO;EACP,aAAa;EACb,MAAM;EACN,iBAAiB;EACjB,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,WACE;EACF,WAAW;EACX,QAAQ;EACR,SAAS;EACT,UAAU;EACV,qBAAqB;EACrB,eAAe;EACf,kBAAkB;EAClB,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,eAAe;EACf,YAAY;EACZ,QAAQ;EACR,iBAAiB;EACjB,mBAAmB;EACnB,kBAAkB;EAClB,aAAa;EACb,gBAAgB;EAChB,OAAO;EACP,aAAa;EACb,WAAW;EACX,UAAU;EACV,aAAa;EACb,aACE;EACF,eAAe;EACf,qBAAqB;EACrB,QAAQ;EACR,UAAU;EACV,eAAe;EACf,iBAAiB;EACjB,MAAM;GACJ,SAAS;GACT,YAAY;GACZ,UAAU;GACV,SAAS;EACX;CACF;CACA,iBAAiB;EACf,OAAO;EACP,QAAQ;EACR,WAAW;CACb;CACA,WAAW;EACT,OAAO;EACP,gBAAgB;EAChB,sBAAsB;EACtB,gBAAgB;EAChB,SAAS;EACT,aACE;EACF,mBACE;EACF,qBACE;EACF,MAAM;EACN,SAAS;EACT,QAAQ;EACR,SAAS;EACT,QAAQ;CACV;CACA,YAAY;EACV,mBAAmB;EACnB,eAAe;EACf,SAAS;EACT,aAAa;CACf;CACA,WAAW;EACT,QAAQ;EACR,cAAc;EACd,cAAc;EACd,sBAAsB;CACxB;CACA,QAAQ;EACN,eAAe;EACf,kBAAkB;EAClB,OAAO;CACT;CACA,QAAQ;EACN,YAAY;EACZ,eAAe;EACf,aAAa;EACb,eAAe;EACf,WAAW;EACX,MAAM;EACN,KAAK;EACL,YAAY;EACZ,YAAY;EACZ,cAAc;EACd,mBAAmB;CACrB;CACA,aAAa;EACX,OAAO;EACP,SACE;CACJ;AACF"}