@templatical/editor 0.38.0 → 0.39.1

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 (289) hide show
  1. package/README.md +2 -4
  2. package/dist/{AiChatSidebar-tu4eLcf_.js → AiChatSidebar-pOxCZWz9.js} +67 -67
  3. package/dist/{AiFeatureMenu-BF0i0vA4.js → AiFeatureMenu-Bljk6Qjv.js} +7 -7
  4. package/dist/{BlockIssueBadge-DT-FqKeC.js → BlockIssueBadge-D5oGxOQP.js} +5 -5
  5. package/dist/{BlockPreviewCanvas-DDCmMram.js → BlockPreviewCanvas-DXGjUECG.js} +27 -27
  6. package/dist/{CloudHeaderExtras-NPhudovT.js → CloudHeaderExtras-DaocwNmy.js} +5 -5
  7. package/dist/{CloudPanels-Iwnky0iA.js → CloudPanels-CyZAnSJY.js} +7 -7
  8. package/dist/{CollaboratorBar-DAITu0hz.js → CollaboratorBar-C7Zca3g1.js} +4 -4
  9. package/dist/{CommentsPanel-CDvgmWP1.js → CommentsPanel-CNOb7YCm.js} +2 -2
  10. package/dist/{CommentsSidebar-X_xqM3dR.js → CommentsSidebar-VmwjU9va.js} +14 -14
  11. package/dist/{CountdownBlock-ZFJIdbP6.js → CountdownBlock-DSvbf3qU.js} +3 -3
  12. package/dist/{CountdownToolbar-DBFoG3a6.js → CountdownToolbar-C2kfS6Oy.js} +31 -30
  13. package/dist/{DesignReferenceSidebar--QtXjLrw.js → DesignReferenceSidebar-QC4gEUWp.js} +11 -11
  14. package/dist/{IssuesPanel-BLbNFMSX.js → IssuesPanel-DL2Xr14_.js} +8 -8
  15. package/dist/{LoadingTrack-BlTL4zFv.js → LoadingTrack-C2jKCU2d.js} +1 -1
  16. package/dist/LogicTagInsertButton-D8IwH-9Z.js +1071 -0
  17. package/dist/{MediaPanels-CMTAhDXB.js → MediaPanels-Cc4UkfG1.js} +2 -2
  18. package/dist/MergeTagInput-QI-5KG2R.js +81 -0
  19. package/dist/{MergeTagModeToggle-DKN6ihI5.js → MergeTagModeToggle-D793Bj_E.js} +32 -73
  20. package/dist/{ParagraphEditor-1E9yzOfk.js → ParagraphEditor-DkkPSexG.js} +50 -51
  21. package/dist/{RestoreVersionDialog-BMGUkcd8.js → RestoreVersionDialog-BgueZnZr.js} +5 -5
  22. package/dist/{RichTextEditorContent-BnxbQUV9.js → RichTextEditorContent-BC5UTVnb.js} +12 -12
  23. package/dist/{SaveBlockDialog-WKASpCCT.js → SaveBlockDialog-BuTuVlLr.js} +12 -11
  24. package/dist/{SavedBlocksBrowserModal-AYEXTMtQ.js → SavedBlocksBrowserModal-Srhix8BB.js} +17 -16
  25. package/dist/{SavedBlocksPanels-D_CpacTl.js → SavedBlocksPanels-B2iScCS-.js} +2 -2
  26. package/dist/{SavedBlocksPickBar-BHMwg-1G.js → SavedBlocksPickBar-cI7bDQQi.js} +4 -4
  27. package/dist/{TemplateScoringPanel-CSin43YM.js → TemplateScoringPanel-C2Rdlyn6.js} +104 -104
  28. package/dist/TemplateSettings-C_5leDdF.js +245 -0
  29. package/dist/{TestEmailModal-BxizsRCd.js → TestEmailModal-DJ5q_u4N.js} +55 -55
  30. package/dist/{TestEmailPanel-vd2e5HzT.js → TestEmailPanel-CP24UGst.js} +2 -2
  31. package/dist/{TitleEditor-CLJ68Ty4.js → TitleEditor-QBBOXtxx.js} +18 -18
  32. package/dist/ToggleSwitch-JvQ_CmI1.js +102 -0
  33. package/dist/Toolbar-COD2TW20.js +2426 -0
  34. package/dist/{TplModal-Q9fDgS1M.js → TplModal-C8xGjC1l.js} +5 -5
  35. package/dist/{VersionHistoryMenu-eGYVhM4H.js → VersionHistoryMenu-BVQityes.js} +10 -10
  36. package/dist/{VersionHistoryPanels-C7Ntrrfq.js → VersionHistoryPanels-BrK6na4A.js} +2 -2
  37. package/dist/{VersionPreviewBanner-BbQXnR0M.js → VersionPreviewBanner-BaMSgA1O.js} +3 -3
  38. package/dist/{blockTypeIcons-5qD4bB76.js → blockTypeIcons-CdXugKyV.js} +16 -37
  39. package/dist/bundle-stats.json +8 -8
  40. package/dist/{cdn/chunks/ca-D9S-UCfZ.js → ca-YlPDhElv.js} +5 -3
  41. package/dist/cdn/chunks/{AiChatSidebar-dyqqHAcI.js → AiChatSidebar-CjSEoK4x.js} +54 -54
  42. package/dist/cdn/chunks/AiChatSidebar-CjSEoK4x.js.map +1 -0
  43. package/dist/cdn/chunks/{AiFeatureMenu-BjVMwhW8.js → AiFeatureMenu-l0K5TOSn.js} +6 -6
  44. package/dist/cdn/chunks/{AiFeatureMenu-BjVMwhW8.js.map → AiFeatureMenu-l0K5TOSn.js.map} +1 -1
  45. package/dist/cdn/chunks/{BlockIssueBadge-BJ__oEtm.js → BlockIssueBadge-9hHpaXb9.js} +5 -5
  46. package/dist/cdn/chunks/{BlockIssueBadge-BJ__oEtm.js.map → BlockIssueBadge-9hHpaXb9.js.map} +1 -1
  47. package/dist/cdn/chunks/{BlockPreviewCanvas-B5f26eLE.js → BlockPreviewCanvas-lQrAdgG3.js} +30 -30
  48. package/dist/cdn/chunks/{BlockPreviewCanvas-B5f26eLE.js.map → BlockPreviewCanvas-lQrAdgG3.js.map} +1 -1
  49. package/dist/cdn/chunks/{CloudHeaderExtras-D5P5IEKA.js → CloudHeaderExtras-CXNe7Q-4.js} +5 -5
  50. package/dist/cdn/chunks/{CloudHeaderExtras-D5P5IEKA.js.map → CloudHeaderExtras-CXNe7Q-4.js.map} +1 -1
  51. package/dist/cdn/chunks/{CloudPanels-DkmR05nB.js → CloudPanels-bHhh9AUA.js} +6 -6
  52. package/dist/cdn/chunks/{CloudPanels-DkmR05nB.js.map → CloudPanels-bHhh9AUA.js.map} +1 -1
  53. package/dist/cdn/chunks/{CollaboratorBar-Yn7KSpt4.js → CollaboratorBar-DgqcaGGI.js} +5 -5
  54. package/dist/cdn/chunks/{CollaboratorBar-Yn7KSpt4.js.map → CollaboratorBar-DgqcaGGI.js.map} +1 -1
  55. package/dist/cdn/chunks/{CommentsPanel-CntwwocI.js → CommentsPanel-Cy4TlTHC.js} +3 -3
  56. package/dist/cdn/chunks/{CommentsPanel-CntwwocI.js.map → CommentsPanel-Cy4TlTHC.js.map} +1 -1
  57. package/dist/cdn/chunks/{CommentsSidebar-BLDKnKy7.js → CommentsSidebar-C7oAP3Mx.js} +5 -5
  58. package/dist/cdn/chunks/{CommentsSidebar-BLDKnKy7.js.map → CommentsSidebar-C7oAP3Mx.js.map} +1 -1
  59. package/dist/cdn/chunks/{CountdownBlock-B4AfqJwb.js → CountdownBlock-DdC8Lg5F.js} +4 -4
  60. package/dist/cdn/chunks/{CountdownBlock-B4AfqJwb.js.map → CountdownBlock-DdC8Lg5F.js.map} +1 -1
  61. package/dist/cdn/chunks/{CountdownToolbar-CA1dpuOI.js → CountdownToolbar-CN9h4nlC.js} +22 -21
  62. package/dist/cdn/chunks/{CountdownToolbar-CA1dpuOI.js.map → CountdownToolbar-CN9h4nlC.js.map} +1 -1
  63. package/dist/cdn/chunks/{DesignReferenceSidebar-D1Y9Hswe.js → DesignReferenceSidebar-Bjo0M-AY.js} +7 -7
  64. package/dist/cdn/chunks/{DesignReferenceSidebar-D1Y9Hswe.js.map → DesignReferenceSidebar-Bjo0M-AY.js.map} +1 -1
  65. package/dist/cdn/chunks/{IssuesPanel-Q62LTqvd.js → IssuesPanel-DdFk-Blf.js} +6 -6
  66. package/dist/cdn/chunks/{IssuesPanel-Q62LTqvd.js.map → IssuesPanel-DdFk-Blf.js.map} +1 -1
  67. package/dist/cdn/chunks/{LoadingTrack-Cm3TDKb3.js → LoadingTrack-Ba5xh5HD.js} +2 -2
  68. package/dist/cdn/chunks/{LoadingTrack-Cm3TDKb3.js.map → LoadingTrack-Ba5xh5HD.js.map} +1 -1
  69. package/dist/cdn/chunks/LogicTagInsertButton-DpyPozop.js +1035 -0
  70. package/dist/cdn/chunks/LogicTagInsertButton-DpyPozop.js.map +1 -0
  71. package/dist/cdn/chunks/{MediaPanels-D21M6shx.js → MediaPanels-kX9AZQ7K.js} +3 -3
  72. package/dist/cdn/chunks/{MediaPanels-D21M6shx.js.map → MediaPanels-kX9AZQ7K.js.map} +1 -1
  73. package/dist/cdn/chunks/MergeTagInput-ERJr7bP_.js +83 -0
  74. package/dist/cdn/chunks/MergeTagInput-ERJr7bP_.js.map +1 -0
  75. package/dist/cdn/chunks/{MergeTagModeToggle-DYxkAGtA.js → MergeTagModeToggle-n3nvSNeQ.js} +33 -33
  76. package/dist/cdn/chunks/{MergeTagModeToggle-DYxkAGtA.js.map → MergeTagModeToggle-n3nvSNeQ.js.map} +1 -1
  77. package/dist/cdn/chunks/{ParagraphEditor-Bd-GQXee.js → ParagraphEditor-DO4RzP8l.js} +43 -43
  78. package/dist/cdn/chunks/{ParagraphEditor-Bd-GQXee.js.map → ParagraphEditor-DO4RzP8l.js.map} +1 -1
  79. package/dist/cdn/chunks/{RestoreVersionDialog-2X9RpM9A.js → RestoreVersionDialog-CzZ_sFnz.js} +5 -5
  80. package/dist/cdn/chunks/{RestoreVersionDialog-2X9RpM9A.js.map → RestoreVersionDialog-CzZ_sFnz.js.map} +1 -1
  81. package/dist/cdn/chunks/{RichTextEditorContent-D_rb0rmU.js → RichTextEditorContent-Ch5zeyZ7.js} +9 -9
  82. package/dist/cdn/chunks/{RichTextEditorContent-D_rb0rmU.js.map → RichTextEditorContent-Ch5zeyZ7.js.map} +1 -1
  83. package/dist/cdn/chunks/{SaveBlockDialog-CufdTomT.js → SaveBlockDialog-LgxYrXyx.js} +10 -9
  84. package/dist/cdn/chunks/{SaveBlockDialog-CufdTomT.js.map → SaveBlockDialog-LgxYrXyx.js.map} +1 -1
  85. package/dist/cdn/chunks/{SavedBlocksBrowserModal-CqpaNsk7.js → SavedBlocksBrowserModal-CdeSsTpb.js} +9 -9
  86. package/dist/cdn/chunks/{SavedBlocksBrowserModal-CqpaNsk7.js.map → SavedBlocksBrowserModal-CdeSsTpb.js.map} +1 -1
  87. package/dist/cdn/chunks/{SavedBlocksPanels-DpxYxddo.js → SavedBlocksPanels-B5hakNJj.js} +3 -3
  88. package/dist/cdn/chunks/{SavedBlocksPanels-DpxYxddo.js.map → SavedBlocksPanels-B5hakNJj.js.map} +1 -1
  89. package/dist/cdn/chunks/{SavedBlocksPickBar-Drpoav1B.js → SavedBlocksPickBar-Cl6PLwwV.js} +5 -5
  90. package/dist/cdn/chunks/{SavedBlocksPickBar-Drpoav1B.js.map → SavedBlocksPickBar-Cl6PLwwV.js.map} +1 -1
  91. package/dist/cdn/chunks/{TemplateScoringPanel-DBjUNULq.js → TemplateScoringPanel--JxR6CsQ.js} +86 -86
  92. package/dist/cdn/chunks/TemplateScoringPanel--JxR6CsQ.js.map +1 -0
  93. package/dist/cdn/chunks/TemplateSettings-DjXiiiNr.js +207 -0
  94. package/dist/cdn/chunks/TemplateSettings-DjXiiiNr.js.map +1 -0
  95. package/dist/cdn/chunks/{TestEmailModal-BTNlSW6f.js → TestEmailModal-BAuDxJtD.js} +53 -53
  96. package/dist/cdn/chunks/TestEmailModal-BAuDxJtD.js.map +1 -0
  97. package/dist/cdn/chunks/{TestEmailPanel-D0A9Zgxr.js → TestEmailPanel-GUGZisLp.js} +3 -3
  98. package/dist/cdn/chunks/{TestEmailPanel-D0A9Zgxr.js.map → TestEmailPanel-GUGZisLp.js.map} +1 -1
  99. package/dist/cdn/chunks/{TitleEditor-CrnuIq62.js → TitleEditor-uKu33Nwr.js} +16 -16
  100. package/dist/cdn/chunks/TitleEditor-uKu33Nwr.js.map +1 -0
  101. package/dist/cdn/chunks/ToggleSwitch-CDy8OfcB.js +104 -0
  102. package/dist/cdn/chunks/ToggleSwitch-CDy8OfcB.js.map +1 -0
  103. package/dist/cdn/chunks/Toolbar-dxDYwN5E.js +2385 -0
  104. package/dist/cdn/chunks/Toolbar-dxDYwN5E.js.map +1 -0
  105. package/dist/cdn/chunks/{TplModal-DYXrTz42.js → TplModal-DuwS2ifK.js} +5 -5
  106. package/dist/cdn/chunks/{TplModal-DYXrTz42.js.map → TplModal-DuwS2ifK.js.map} +1 -1
  107. package/dist/cdn/chunks/{VersionHistoryMenu-bDGnE4hb.js → VersionHistoryMenu-Dij1pTEb.js} +6 -6
  108. package/dist/cdn/chunks/{VersionHistoryMenu-bDGnE4hb.js.map → VersionHistoryMenu-Dij1pTEb.js.map} +1 -1
  109. package/dist/cdn/chunks/{VersionHistoryPanels-82P0Q0HM.js → VersionHistoryPanels-GeR6MStB.js} +3 -3
  110. package/dist/cdn/chunks/{VersionHistoryPanels-82P0Q0HM.js.map → VersionHistoryPanels-GeR6MStB.js.map} +1 -1
  111. package/dist/cdn/chunks/{VersionPreviewBanner-BJiwKkVC.js → VersionPreviewBanner-Df3FVlig.js} +4 -4
  112. package/dist/cdn/chunks/{VersionPreviewBanner-BJiwKkVC.js.map → VersionPreviewBanner-Df3FVlig.js.map} +1 -1
  113. package/dist/cdn/chunks/{blockTypeIcons-CNjJSFun.js → blockTypeIcons-raBjStuv.js} +2 -2
  114. package/dist/cdn/chunks/{blockTypeIcons-CNjJSFun.js.map → blockTypeIcons-raBjStuv.js.map} +1 -1
  115. package/dist/{ca-D9S-UCfZ.js → cdn/chunks/ca-YlPDhElv.js} +7 -1
  116. package/dist/cdn/chunks/{ca-D9S-UCfZ.js.map → ca-YlPDhElv.js.map} +1 -1
  117. package/dist/cdn/chunks/{cloud-BLgCKP7Z.js → cloud-eaXyxZ8l.js} +2 -2
  118. package/dist/cdn/chunks/{cloud-BLgCKP7Z.js.map → cloud-eaXyxZ8l.js.map} +1 -1
  119. package/dist/cdn/chunks/{createCloudRuntime-U-qCH-dq.js → createCloudRuntime-D5bXzcTe.js} +6 -6
  120. package/dist/cdn/chunks/{createCloudRuntime-U-qCH-dq.js.map → createCloudRuntime-D5bXzcTe.js.map} +1 -1
  121. package/dist/cdn/chunks/{de-BUPszLpi.js → de-CONjnzrF.js} +6 -2
  122. package/dist/cdn/chunks/{de-BUPszLpi.js.map → de-CONjnzrF.js.map} +1 -1
  123. package/dist/cdn/chunks/{dist-BW6Y49zE.js → dist-BRZhN8qJ.js} +4 -4
  124. package/dist/cdn/chunks/dist-BRZhN8qJ.js.map +1 -0
  125. package/dist/cdn/chunks/{dist-CAFTQ6Y2.js → dist-CXB2_kBa.js} +27 -22
  126. package/dist/cdn/chunks/dist-CXB2_kBa.js.map +1 -0
  127. package/dist/cdn/chunks/{draggable-kbOhCgnk.js → draggable-IB4x6w2O.js} +1477 -1470
  128. package/dist/cdn/chunks/draggable-IB4x6w2O.js.map +1 -0
  129. package/dist/cdn/chunks/{editor-modal-MXgtarMl.js → editor-modal-C_xYN_66.js} +7 -7
  130. package/dist/cdn/chunks/{editor-modal-MXgtarMl.js.map → editor-modal-C_xYN_66.js.map} +1 -1
  131. package/dist/cdn/chunks/{en-BbOC5x3w.js → en-BAMooiOF.js} +6 -2
  132. package/dist/cdn/chunks/{en-BbOC5x3w.js.map → en-BAMooiOF.js.map} +1 -1
  133. package/dist/cdn/chunks/en-BwfjKb4M.js +2 -0
  134. package/dist/{es-0bCDcT9p.js → cdn/chunks/es-I47lHs2m.js} +7 -1
  135. package/dist/cdn/chunks/{es-0bCDcT9p.js.map → es-I47lHs2m.js.map} +1 -1
  136. package/dist/cdn/chunks/{extensions-B8_jnIkD.js → extensions-Bhu8UEE5.js} +185 -100
  137. package/dist/cdn/chunks/extensions-Bhu8UEE5.js.map +1 -0
  138. package/dist/cdn/chunks/{fr-Brr8mJ9e.js → fr-B8MIKjT4.js} +6 -2
  139. package/dist/cdn/chunks/{fr-Brr8mJ9e.js.map → fr-B8MIKjT4.js.map} +1 -1
  140. package/dist/cdn/chunks/htmlparser-ClUZ6waR.js +1113 -0
  141. package/dist/cdn/chunks/htmlparser-ClUZ6waR.js.map +1 -0
  142. package/dist/cdn/chunks/{icons-BUlqGSgd.js → icons-BKkJ-5xF.js} +36 -36
  143. package/dist/cdn/chunks/{icons-BUlqGSgd.js.map → icons-BKkJ-5xF.js.map} +1 -1
  144. package/dist/cdn/chunks/keys-dJbD1QPs.js +12 -0
  145. package/dist/cdn/chunks/keys-dJbD1QPs.js.map +1 -0
  146. package/dist/{nl-Co3_RL0M.js → cdn/chunks/nl-CBLxcb-0.js} +7 -1
  147. package/dist/cdn/chunks/{nl-Co3_RL0M.js.map → nl-CBLxcb-0.js.map} +1 -1
  148. package/dist/{pt-BR-BECez5b0.js → cdn/chunks/pt-BR-CMSRfX7t.js} +7 -1
  149. package/dist/cdn/chunks/{pt-BR-BECez5b0.js.map → pt-BR-CMSRfX7t.js.map} +1 -1
  150. package/dist/cdn/chunks/socialIcons-9VrG8X3m.js +1054 -0
  151. package/dist/cdn/chunks/socialIcons-9VrG8X3m.js.map +1 -0
  152. package/dist/cdn/chunks/{src-IGLRmUar.js → src-CZ-W8YBa.js} +4 -4
  153. package/dist/cdn/chunks/{src-IGLRmUar.js.map → src-CZ-W8YBa.js.map} +1 -1
  154. package/dist/cdn/chunks/{src-CUvZWL6Y.js → src-CaNsA_WX.js} +2 -2
  155. package/dist/cdn/chunks/{src-CUvZWL6Y.js.map → src-CaNsA_WX.js.map} +1 -1
  156. package/dist/cdn/chunks/src-Dwgq7hf4.js.map +1 -1
  157. package/dist/cdn/chunks/templateSettingsFields-YCFVBVYh.js +36 -0
  158. package/dist/cdn/chunks/templateSettingsFields-YCFVBVYh.js.map +1 -0
  159. package/dist/cdn/chunks/{tiptap-Epe8m3Vo.js → tiptap-DhLuKyDc.js} +2776 -2773
  160. package/dist/cdn/chunks/tiptap-DhLuKyDc.js.map +1 -0
  161. package/dist/cdn/chunks/{useAliveFlag-CT9gjvO_.js → useAliveFlag-DAlQLbM2.js} +2 -2
  162. package/dist/cdn/chunks/{useAliveFlag-CT9gjvO_.js.map → useAliveFlag-DAlQLbM2.js.map} +1 -1
  163. package/dist/cdn/chunks/{useCloudI18n-DSWSGj-A.js → useCloudI18n-C09JcFS0.js} +3 -3
  164. package/dist/cdn/chunks/{useCloudI18n-DSWSGj-A.js.map → useCloudI18n-C09JcFS0.js.map} +1 -1
  165. package/dist/cdn/chunks/useEditorCore-BHmIp1hW.js +2592 -0
  166. package/dist/cdn/chunks/useEditorCore-BHmIp1hW.js.map +1 -0
  167. package/dist/cdn/chunks/useEditorRoot-DFx2fXJP.js +10 -0
  168. package/dist/cdn/chunks/{useEditorRoot-B0zW2nT4.js.map → useEditorRoot-DFx2fXJP.js.map} +1 -1
  169. package/dist/cdn/chunks/{useI18n-Dlo7R9RA.js → useI18n-DTZ9sIcv.js} +3 -3
  170. package/dist/cdn/chunks/{useI18n-Dlo7R9RA.js.map → useI18n-DTZ9sIcv.js.map} +1 -1
  171. package/dist/cdn/chunks/useLogicTag-E2V0Xdcb.js +38 -0
  172. package/dist/cdn/chunks/useLogicTag-E2V0Xdcb.js.map +1 -0
  173. package/dist/cdn/chunks/useMergeTag-BE8oDoha.js +60 -0
  174. package/dist/cdn/chunks/useMergeTag-BE8oDoha.js.map +1 -0
  175. package/dist/cdn/chunks/{usePopoverPosition-ElP3ABaV.js → usePopoverPosition-gB9q-ql7.js} +3 -3
  176. package/dist/cdn/chunks/{usePopoverPosition-ElP3ABaV.js.map → usePopoverPosition-gB9q-ql7.js.map} +1 -1
  177. package/dist/cdn/chunks/{useScrollToBlock-nTbWkgaU.js → useScrollToBlock-CtTXwmiU.js} +3 -3
  178. package/dist/cdn/chunks/{useScrollToBlock-nTbWkgaU.js.map → useScrollToBlock-CtTXwmiU.js.map} +1 -1
  179. package/dist/cdn/editor.css +1 -1
  180. package/dist/cdn/editor.js +856 -3347
  181. package/dist/cdn/editor.js.map +1 -1
  182. package/dist/{check-DWtkBzBU.js → check-eqb2JhqU.js} +1 -1
  183. package/dist/{chevron-down-C-Fjxcqj.js → chevron-down-Dkr-7Ywl.js} +1 -1
  184. package/dist/{chevron-right-SOkn2d4P.js → chevron-right-Bge4XF_B.js} +1 -1
  185. package/dist/{chevron-up-lntU1ypp.js → chevron-up-CQAyl0kC.js} +1 -1
  186. package/dist/{circle-alert-CjzUTwy3.js → circle-alert-CYgTHKWr.js} +1 -1
  187. package/dist/{clock-pB2QKPsJ.js → clock-BgSJZJP5.js} +1 -1
  188. package/dist/{cloud-DdidMW6f.js → cloud-C9xWZXhg.js} +1 -1
  189. package/dist/{copy-CId1E038.js → copy-mw6PVnOJ.js} +1 -1
  190. package/dist/{createCloudRuntime-x5WZm3p8.js → createCloudRuntime-BGd5--Bq.js} +5 -5
  191. package/dist/{createLucideIcon-Cwf_nTzE.js → createLucideIcon-BxY5yz5u.js} +6 -6
  192. package/dist/{de-BUPszLpi.js → de-CONjnzrF.js} +5 -1
  193. package/dist/{dist-D8i1ixHK.js → dist-8VFzbeu9.js} +3 -3
  194. package/dist/{dist-DBirAJIs.js → dist-BDuPwOyn.js} +26 -21
  195. package/dist/{dist-CtF9STPS.js → dist-BJM3eFyT.js} +1 -1
  196. package/dist/{dist-DkcA6epL.js → dist-BdHF7nyq.js} +3 -3
  197. package/dist/{dist-ByT5fgKq.js → dist-Bl4rxpX9.js} +1 -1
  198. package/dist/{dist-BVqAYoRB.js → dist-BmsLcnrO.js} +4 -4
  199. package/dist/{dist-CtMXAH7a.js → dist-BxVnMgXZ.js} +1 -1
  200. package/dist/{dist-DC-3T0ED.js → dist-CQSVro7b.js} +1 -1
  201. package/dist/{dist-f7HXo6j6.js → dist-DQbOebGW.js} +1 -1
  202. package/dist/{dist-DL9334yz.js → dist-DerFNpDY.js} +3 -3
  203. package/dist/{dist-D08oVYhr.js → dist-Djmzp6wi.js} +1 -1
  204. package/dist/{dist-D7WY8VPq.js → dist-DyrEOKEJ.js} +1 -1
  205. package/dist/{dist-DzdeVn-W.js → dist-EDkj3Ub1.js} +1 -1
  206. package/dist/{dist-C1tsW_99.js → dist-wyXxj3R1.js} +1 -1
  207. package/dist/{editor-modal-B_LaQf0s.js → editor-modal-OPhP71YO.js} +20 -20
  208. package/dist/{en-BbOC5x3w.js → en-BAMooiOF.js} +5 -1
  209. package/dist/en-CjNopehs.js +2 -0
  210. package/dist/{cdn/chunks/es-0bCDcT9p.js → es-I47lHs2m.js} +5 -3
  211. package/dist/extensions-DRN-elXT.js +1645 -0
  212. package/dist/{eye-BuGtFUoJ.js → eye-DphkRtAD.js} +1 -1
  213. package/dist/{fr-Brr8mJ9e.js → fr-B8MIKjT4.js} +5 -1
  214. package/dist/{image-up-gH4JEpU5.js → image-up-Qi2BXD7T.js} +1 -1
  215. package/dist/index.d.ts +15 -0
  216. package/dist/{info-BQ60P82u.js → info-VSyAs02q.js} +1 -1
  217. package/dist/keys-BdoSgsz9.js +10 -0
  218. package/dist/{link-3R8it3J7.js → link-CNuozGqD.js} +1 -1
  219. package/dist/{list-Ccdgj46T.js → list-BA0I5Wmu.js} +1 -1
  220. package/dist/{loader-circle-B_tAD4k6.js → loader-circle-z5eeqasv.js} +1 -1
  221. package/dist/{message-circle-P-KSc6V0.js → message-circle-BsQ9hEup.js} +1 -1
  222. package/dist/{cdn/chunks/nl-Co3_RL0M.js → nl-CBLxcb-0.js} +5 -3
  223. package/dist/package-OkXfuRoO.js +25 -0
  224. package/dist/{pencil-9ZiwqS4r.js → pencil-DFVFA7Dj.js} +1 -1
  225. package/dist/{plus-BwJEzCaO.js → plus-D8bkVjZ7.js} +1 -1
  226. package/dist/{cdn/chunks/pt-BR-BECez5b0.js → pt-BR-CMSRfX7t.js} +5 -3
  227. package/dist/{refresh-cw-DEgfb2FK.js → refresh-cw-DPB7YFuz.js} +1 -1
  228. package/dist/{runtime-dom.esm-bundler-PnoZU512.js → runtime-dom.esm-bundler-BGbPz4-g.js} +2 -2
  229. package/dist/{search-DqQ8Li5E.js → search-C-dCgqIa.js} +1 -1
  230. package/dist/{send-CE6uvqop.js → send-Cm2fy2zm.js} +1 -1
  231. package/dist/{shield-check-DhD1Z3rd.js → shield-check-COgBYFDF.js} +1 -1
  232. package/dist/smartphone-v0u_MOEV.js +46 -0
  233. package/dist/socialIcons-DkGcpEwC.js +1130 -0
  234. package/dist/{sparkles-R0ZQHa6F.js → sparkles-Ds0RF8Iu.js} +1 -1
  235. package/dist/style.css +1 -1
  236. package/dist/templateSettingsFields-YCFVBVYh.js +34 -0
  237. package/dist/templatical-editor.js +945 -3511
  238. package/dist/{text-align-start-DSux2UNn.js → text-align-start-DiavaIm6.js} +1 -1
  239. package/dist/{trash-Cf_SqsER.js → trash-DnOkfu2V.js} +1 -1
  240. package/dist/{triangle-alert-C6tGa6jw.js → triangle-alert-DGLAyXnh.js} +1 -1
  241. package/dist/{upload-DusKjpVr.js → upload-BBDme2cy.js} +1 -1
  242. package/dist/{useAliveFlag-oyByIcjy.js → useAliveFlag-BkKyhkwZ.js} +1 -1
  243. package/dist/{useCloudI18n-BLyh_e2T.js → useCloudI18n-D1iedlP3.js} +2 -2
  244. package/dist/useEditorCore-C5APBjjV.js +4097 -0
  245. package/dist/{useEditorRoot-ds57-l6F.js → useEditorRoot-BOxn5EfP.js} +2 -2
  246. package/dist/{useI18n-BbdxxpOE.js → useI18n-Ds_-druD.js} +2 -2
  247. package/dist/useLogicTag-DoHfc08B.js +36 -0
  248. package/dist/useMergeTag-DXyum3kG.js +58 -0
  249. package/dist/{usePopoverPosition-CprM5p-c.js → usePopoverPosition-Du-Ah8E9.js} +2 -2
  250. package/dist/{useScrollToBlock-BTFw0b9O.js → useScrollToBlock-DXQYPCnJ.js} +3 -3
  251. package/dist/{vue.runtime.esm-bundler-DShF3P6k.js → vue.runtime.esm-bundler-CyqhBwpY.js} +1133 -1126
  252. package/dist/{x-D_-42Ukq.js → x-3BHV3Q6K.js} +1 -1
  253. package/package.json +16 -16
  254. package/dist/ColorPicker-BqlZ_TqG.js +0 -501
  255. package/dist/FieldRow-C8nOknr_.js +0 -128
  256. package/dist/MergeTagInput-BEjzj4Iu.js +0 -457
  257. package/dist/MergeTagSuggestion-DKoLEeoj.js +0 -1329
  258. package/dist/cdn/chunks/AiChatSidebar-dyqqHAcI.js.map +0 -1
  259. package/dist/cdn/chunks/ColorPicker-LcrzgMoW.js +0 -502
  260. package/dist/cdn/chunks/ColorPicker-LcrzgMoW.js.map +0 -1
  261. package/dist/cdn/chunks/FieldRow-D9OJhYeb.js +0 -130
  262. package/dist/cdn/chunks/FieldRow-D9OJhYeb.js.map +0 -1
  263. package/dist/cdn/chunks/MergeTagInput-l7paaAml.js +0 -419
  264. package/dist/cdn/chunks/MergeTagInput-l7paaAml.js.map +0 -1
  265. package/dist/cdn/chunks/MergeTagSuggestion-t8Uj00Er.js +0 -215
  266. package/dist/cdn/chunks/MergeTagSuggestion-t8Uj00Er.js.map +0 -1
  267. package/dist/cdn/chunks/TemplateScoringPanel-DBjUNULq.js.map +0 -1
  268. package/dist/cdn/chunks/TestEmailModal-BTNlSW6f.js.map +0 -1
  269. package/dist/cdn/chunks/TitleEditor-CrnuIq62.js.map +0 -1
  270. package/dist/cdn/chunks/dist-BW6Y49zE.js.map +0 -1
  271. package/dist/cdn/chunks/dist-CAFTQ6Y2.js.map +0 -1
  272. package/dist/cdn/chunks/draggable-kbOhCgnk.js.map +0 -1
  273. package/dist/cdn/chunks/en-C9U7N77n.js +0 -2
  274. package/dist/cdn/chunks/extensions-B8_jnIkD.js.map +0 -1
  275. package/dist/cdn/chunks/htmlparser-DTML8Gvz.js +0 -1007
  276. package/dist/cdn/chunks/htmlparser-DTML8Gvz.js.map +0 -1
  277. package/dist/cdn/chunks/keys-DBFhDFng.js +0 -12
  278. package/dist/cdn/chunks/keys-DBFhDFng.js.map +0 -1
  279. package/dist/cdn/chunks/tiptap-Epe8m3Vo.js.map +0 -1
  280. package/dist/cdn/chunks/useEditorCore-Cs7rYVBo.js +0 -3689
  281. package/dist/cdn/chunks/useEditorCore-Cs7rYVBo.js.map +0 -1
  282. package/dist/cdn/chunks/useEditorRoot-B0zW2nT4.js +0 -10
  283. package/dist/cdn/chunks/useMergeTag-BYAifvh8.js +0 -46
  284. package/dist/cdn/chunks/useMergeTag-BYAifvh8.js.map +0 -1
  285. package/dist/en-DcmpWV53.js +0 -2
  286. package/dist/extensions-CHOBZRab.js +0 -445
  287. package/dist/keys-DQA2i1k1.js +0 -10
  288. package/dist/useEditorCore-DhlKOYwe.js +0 -5273
  289. package/dist/useMergeTag-DlvOBW_B.js +0 -44
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions-Bhu8UEE5.js","names":[],"sources":["../../../src/extensions/FontSize.ts","../../../src/extensions/LetterSpacing.ts","../../../src/extensions/LineBoundaryKeys.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","../../../src/extensions/MergeTagSuggestion.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\n/**\n * Routes plain End/Home through `Selection.modify` instead of the browser's\n * native caret movement.\n *\n * Chromium (verified 140–151, including stable Chrome) has a bug where a\n * native End or Home pressed while a triple-click selection is active puts\n * Blink's selection state into a mode where the next typed character\n * natively smooth-scrolls the nearest scrollable ancestor (the editor's\n * canvas, `.tpl-body`) to its very bottom (End) or top (Home), dragging the\n * caret out of view. The state cannot be repaired after the fact — clearing\n * or re-setting the DOM selection, blur/refocus, and preventDefault on the\n * clicks all fail — but a programmatic caret move never arms it.\n *\n * `Selection.modify(\"move\", direction, \"lineboundary\")` is the exact\n * equivalent of the native key (visual line boundary, bidi-aware via the\n * logical forward/backward directions), so behavior is unchanged for users.\n * Shift+End / Shift+Home extend selections natively and do not trigger the\n * bug, so only the plain keys are bound — a keymap entry without modifiers\n * never matches the shifted keys.\n */\nexport const LineBoundaryKeys = Extension.create({\n name: \"lineBoundaryKeys\",\n\n addKeyboardShortcuts() {\n const moveToLineBoundary =\n (direction: \"forward\" | \"backward\") =>\n ({ editor }: { editor: { view: unknown } }): boolean => {\n const view = editor.view as {\n composing: boolean;\n root: DocumentOrShadowRoot & {\n getSelection?: () => Selection | null;\n };\n dom: HTMLElement;\n };\n // During IME composition End/Home commit the composition; leave\n // that to the browser.\n if (!view || view.composing) return false;\n // `view.root` is the editable's Document or ShadowRoot, so the\n // selection resolves correctly in both mount modes. ShadowRoot's\n // getSelection is Chromium-only; elsewhere fall back to the owner\n // document (Chromium is also the only engine with the bug).\n const selection =\n typeof view.root?.getSelection === \"function\"\n ? view.root.getSelection()\n : (view.dom?.ownerDocument?.getSelection?.() ?? null);\n // `modify` is non-standard; without it, or with a selection that\n // is not ours, native handling is the safer default.\n if (!selection || typeof selection.modify !== \"function\") return false;\n if (!selection.anchorNode || !view.dom.contains(selection.anchorNode)) {\n return false;\n }\n selection.modify(\"move\", direction, \"lineboundary\");\n return true;\n };\n\n return {\n End: moveToLineBoundary(\"forward\"),\n Home: moveToLineBoundary(\"backward\"),\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 tpl:hover: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 tpl:hover: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 // Both attributes are state, not markup, same as `MergeTagNode`:\n // `renderHTML()` emits the canonical `data-logic-merge-tag` /\n // `data-keyword` pair and `parseHTML` reads only those. `rendered: false`\n // keeps TipTap from also serializing each attribute under its own name,\n // which would put a write-only duplicate of the same data on every tag.\n value: {\n default: \"\",\n rendered: false,\n parseHTML: (element) =>\n element.getAttribute(\"data-logic-merge-tag\") || \"\",\n },\n keyword: {\n default: \"\",\n rendered: false,\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, onScopeDispose, 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 {\n getMergeTagLabel,\n getMergeTagDisplayLabel,\n findMergeTag,\n canRepickMergeTag,\n showRawValue,\n isMergeTagValue,\n requestMergeTag,\n} = useMergeTag();\nconst { t, format } = useI18n();\n\n// `node.attrs.label` is the label captured when the tag was inserted. It is\n// only ever a fallback — the configured tags win, which is what keeps a\n// relabelled tag from rendering its stale stored copy.\nconst displayLabel = computed(() =>\n getMergeTagDisplayLabel(props.node.attrs.value, props.node.attrs.label),\n);\nconst canRepick = computed(() => canRepickMergeTag(props.node.attrs.value));\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\n\n// The chooser mounts in the popover root, outside this node view, so the node\n// can be torn down while it is open — a collaborator edit, a block change, the\n// editor unmounting. Writing attributes onto a destroyed node view throws.\nlet disposed = false;\nonScopeDispose(() => {\n disposed = true;\n});\n\n/** Whether the text currently in the raw input is a usable merge tag. */\nconst isEditValueValid = computed(\n () =>\n editValue.value.trim() === \"\" || isMergeTagValue(editValue.value.trim()),\n);\n\n/**\n * Swap this tag for another one, chosen through the same chooser insertion\n * uses. `requestMergeTag` sets the editor-wide requesting flag for the whole\n * await, which is what stops `useRichTextEditor`'s click-outside handler\n * finishing the block when the user clicks a row in the chooser — that would\n * dispose this node view and silently drop the update.\n */\nasync function repick(): Promise<void> {\n const replacement = await requestMergeTag({\n reason: \"edit\",\n current: findMergeTag(props.node.attrs.value),\n });\n if (disposed || !replacement) return;\n props.updateAttributes({\n value: replacement.value,\n label: replacement.label,\n });\n}\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\n/**\n * Activating the chip opens the chooser when one can resolve this token, and\n * the raw input only when none can. Editing a token as free text is how a\n * chip ends up holding something that is not a merge tag at all, which the\n * renderer then emits verbatim into the sent email.\n */\nfunction activate(): void {\n if (canRepick.value) {\n void repick();\n return;\n }\n startEditing();\n}\n\nfunction finishEditing(): void {\n const newValue = editValue.value.trim();\n // Never commit something that isn't a merge tag: `renderHTML` writes the\n // value straight into `data-merge-tag`, and the renderer drops that into the\n // MJML unchanged, so a typo would ship as literal text in the email.\n if (\n newValue &&\n newValue !== props.node.attrs.value &&\n isMergeTagValue(newValue)\n ) {\n props.updateAttributes({\n // The honest resolution, not the display chain: this is written into the\n // document as `data-label`, so a placeholder would be persisted as if it\n // were the tag's name.\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 // Enter on an invalid value keeps the input open rather than discarding\n // what was typed — the border and `aria-invalid` already say why.\n if (!isEditValueValid.value) return;\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 :aria-invalid=\"isEditValueValid ? undefined : 'true'\"\n class=\"tpl:w-32 tpl:rounded 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 :class=\"\n isEditValueValid\n ? 'tpl:border-none'\n : 'tpl:border tpl:border-[var(--tpl-danger)]'\n \"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"\n canRepick\n ? format(t.mergeTag.changeTag, { label: displayLabel })\n : t.mergeTag.editValue\n \"\n class=\"tpl:cursor-pointer\"\n :class=\"showRawValue ? 'tpl-tooltip' : ''\"\n :data-tooltip=\"showRawValue ? node.attrs.value : undefined\"\n @click.stop=\"activate\"\n @keydown.enter.stop=\"activate\"\n @keydown.space.prevent.stop=\"activate\"\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 tpl:hover: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, onScopeDispose, 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 {\n getMergeTagLabel,\n getMergeTagDisplayLabel,\n findMergeTag,\n canRepickMergeTag,\n showRawValue,\n isMergeTagValue,\n requestMergeTag,\n} = useMergeTag();\nconst { t, format } = useI18n();\n\n// `node.attrs.label` is the label captured when the tag was inserted. It is\n// only ever a fallback — the configured tags win, which is what keeps a\n// relabelled tag from rendering its stale stored copy.\nconst displayLabel = computed(() =>\n getMergeTagDisplayLabel(props.node.attrs.value, props.node.attrs.label),\n);\nconst canRepick = computed(() => canRepickMergeTag(props.node.attrs.value));\n\nconst isEditing = ref(false);\nconst editValue = ref(\"\");\nconst inputRef = ref<HTMLInputElement | null>(null);\n\n// The chooser mounts in the popover root, outside this node view, so the node\n// can be torn down while it is open — a collaborator edit, a block change, the\n// editor unmounting. Writing attributes onto a destroyed node view throws.\nlet disposed = false;\nonScopeDispose(() => {\n disposed = true;\n});\n\n/** Whether the text currently in the raw input is a usable merge tag. */\nconst isEditValueValid = computed(\n () =>\n editValue.value.trim() === \"\" || isMergeTagValue(editValue.value.trim()),\n);\n\n/**\n * Swap this tag for another one, chosen through the same chooser insertion\n * uses. `requestMergeTag` sets the editor-wide requesting flag for the whole\n * await, which is what stops `useRichTextEditor`'s click-outside handler\n * finishing the block when the user clicks a row in the chooser — that would\n * dispose this node view and silently drop the update.\n */\nasync function repick(): Promise<void> {\n const replacement = await requestMergeTag({\n reason: \"edit\",\n current: findMergeTag(props.node.attrs.value),\n });\n if (disposed || !replacement) return;\n props.updateAttributes({\n value: replacement.value,\n label: replacement.label,\n });\n}\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\n/**\n * Activating the chip opens the chooser when one can resolve this token, and\n * the raw input only when none can. Editing a token as free text is how a\n * chip ends up holding something that is not a merge tag at all, which the\n * renderer then emits verbatim into the sent email.\n */\nfunction activate(): void {\n if (canRepick.value) {\n void repick();\n return;\n }\n startEditing();\n}\n\nfunction finishEditing(): void {\n const newValue = editValue.value.trim();\n // Never commit something that isn't a merge tag: `renderHTML` writes the\n // value straight into `data-merge-tag`, and the renderer drops that into the\n // MJML unchanged, so a typo would ship as literal text in the email.\n if (\n newValue &&\n newValue !== props.node.attrs.value &&\n isMergeTagValue(newValue)\n ) {\n props.updateAttributes({\n // The honest resolution, not the display chain: this is written into the\n // document as `data-label`, so a placeholder would be persisted as if it\n // were the tag's name.\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 // Enter on an invalid value keeps the input open rather than discarding\n // what was typed — the border and `aria-invalid` already say why.\n if (!isEditValueValid.value) return;\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 :aria-invalid=\"isEditValueValid ? undefined : 'true'\"\n class=\"tpl:w-32 tpl:rounded 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 :class=\"\n isEditValueValid\n ? 'tpl:border-none'\n : 'tpl:border tpl:border-[var(--tpl-danger)]'\n \"\n @blur=\"finishEditing\"\n @keydown=\"handleKeydown\"\n />\n <!-- Display mode -->\n <span\n v-else\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"\n canRepick\n ? format(t.mergeTag.changeTag, { label: displayLabel })\n : t.mergeTag.editValue\n \"\n class=\"tpl:cursor-pointer\"\n :class=\"showRawValue ? 'tpl-tooltip' : ''\"\n :data-tooltip=\"showRawValue ? node.attrs.value : undefined\"\n @click.stop=\"activate\"\n @keydown.enter.stop=\"activate\"\n @keydown.space.prevent.stop=\"activate\"\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 tpl:hover: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 /**\n * Read live, not captured. `renderHTML` and the input/paste rules resolve a\n * label every time they run, and `editor.setMergeTags` can replace the list\n * while a block is open for editing.\n */\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 // Both attributes are state, not markup: `renderHTML()` below emits the\n // canonical `data-merge-tag` / `data-label` pair and `parseHTML` reads\n // only those. `rendered: false` keeps TipTap from also serializing each\n // attribute under its own name, which would put a write-only duplicate\n // of the same data on every tag — invalid on a `<span>`, and paid again\n // through storage, autosave, snapshots and version history.\n label: {\n default: \"\",\n rendered: false,\n parseHTML: (element) =>\n element.getAttribute(\"data-label\") || element.textContent || \"\",\n },\n value: {\n default: \"\",\n rendered: false,\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","import type { MergeTag } from \"@templatical/types\";\nimport { Extension } from \"@tiptap/core\";\nimport Suggestion, {\n type SuggestionOptions,\n type SuggestionProps,\n type SuggestionKeyDownProps,\n} from \"@tiptap/suggestion\";\nimport type { Ref } from \"vue\";\nimport { createMergeTagPopup, filterMergeTags } from \"../utils/mergeTagPopup\";\n\nexport interface MergeTagSuggestionOptions {\n /** Available merge tags */\n /**\n * Read live, not captured: the list can be replaced while a block is being\n * edited (`editor.setMergeTags`), and a snapshot taken when the extension\n * was configured would keep suggesting the old tags.\n */\n mergeTags: () => MergeTag[];\n /** Trigger string (e.g. \"{{\", \"*|\", \"%%=\") */\n char: string;\n /** Localized empty-state label */\n emptyText: string;\n /**\n * Mount target for the suggestion popup. When provided with a non-null\n * `.value`, the popup attaches into that element instead of\n * `document.body` — keeping it inside the editor's effective DOM root\n * (shadow-aware). Pass the ref returned by `usePopoverRoot()`.\n *\n * Falls back to `document.body` when omitted or when the ref's value is\n * null at popup-open time (e.g. headless/test editors without an editor\n * shell). Preserves pre-Phase-3 behavior for callers that don't migrate.\n */\n popoverRoot?: Ref<HTMLElement | null> | null;\n}\n\n/**\n * Builds the `@tiptap/suggestion` `render` factory for the merge-tag popup.\n * A thin adapter over {@link createMergeTagPopup}: it maps ProseMirror's\n * `SuggestionProps` (items, `clientRect`, `view.dom`, `command`) onto the\n * controller. Exported as a standalone function so that mapping can be\n * unit-tested with mocked `SuggestionProps` instead of a full editor.\n */\nexport function createMergeTagSuggestionRenderer(\n emptyText: string,\n popoverRootRef?: Ref<HTMLElement | null> | null,\n): NonNullable<SuggestionOptions<MergeTag>[\"render\"]> {\n return () => {\n const popup = createMergeTagPopup(emptyText, popoverRootRef);\n\n return {\n onStart: (props: SuggestionProps<MergeTag>) => {\n // Use view.dom (ProseMirror contenteditable, actually\n // attached to the DOM) rather than options.element, which may\n // be a detached div when no `element` is passed to the editor\n // constructor (as is the case with @tiptap/vue-3 EditorContent).\n const viewDom = props.editor.view?.dom as HTMLElement | undefined;\n popup.open({\n items: props.items,\n getRect: props.clientRect ?? null,\n anchorEl: viewDom ?? null,\n onCommand: (item) => props.command(item),\n });\n },\n onUpdate: (props: SuggestionProps<MergeTag>) => {\n popup.update({\n items: props.items,\n getRect: props.clientRect ?? null,\n onCommand: (item) => props.command(item),\n });\n },\n onKeyDown: (props: SuggestionKeyDownProps): boolean => {\n // Escape closes via TipTap's suggestion plugin (→ onExit); report it\n // handled without selecting.\n if (props.event.key === \"Escape\") {\n return true;\n }\n return popup.handleKeyDown(props.event);\n },\n onExit: () => popup.close(),\n };\n };\n}\n\nexport const MergeTagSuggestion = Extension.create<MergeTagSuggestionOptions>({\n name: \"mergeTagSuggestion\",\n\n addOptions() {\n return {\n mergeTags: () => [],\n char: \"{{\",\n emptyText: \"No matching merge tags\",\n popoverRoot: null,\n };\n },\n\n addProseMirrorPlugins() {\n const tags = this.options.mergeTags();\n const emptyText = this.options.emptyText;\n const popoverRootRef = this.options.popoverRoot;\n\n const config: Omit<SuggestionOptions<MergeTag>, \"editor\"> = {\n char: this.options.char,\n allowSpaces: false,\n startOfLine: false,\n // Default is [\" \"] which requires whitespace/line-start before the\n // trigger char — so `.{{` would not fire. Allow any preceding char.\n allowedPrefixes: null,\n items: ({ query }: { query: string }) => filterMergeTags(tags, query),\n command: ({\n editor,\n range,\n props,\n }: {\n editor: SuggestionProps<MergeTag>[\"editor\"];\n range: { from: number; to: number };\n props: MergeTag;\n }) => {\n // Use insertContentAt for atomic replace (matches the canonical\n // @tiptap/suggestion + Mention pattern). Avoids edge cases where\n // chained deleteRange + insertMergeTag fails to insert when the\n // selection state shifts mid-chain.\n editor\n .chain()\n .focus()\n .insertContentAt(range, {\n type: \"mergeTagNode\",\n attrs: { label: props.label, value: props.value },\n })\n .run();\n },\n render: createMergeTagSuggestionRenderer(emptyText, popoverRootRef),\n };\n\n return [\n Suggestion({\n editor: this.editor,\n ...config,\n }),\n ];\n },\n});\n"],"mappings":"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"}
@@ -424,15 +424,19 @@ var e = {
424
424
  presetColors: "Couleurs prédéfinies"
425
425
  },
426
426
  mergeTag: {
427
- clickToEdit: "Cliquez pour modifier",
427
+ editAsText: "Modifier comme texte",
428
+ fieldGroup: "Valeur avec balises de fusion",
428
429
  remove: "Supprimer la balise de fusion",
429
430
  insert: "Insérer une balise de fusion",
430
431
  insertShort: "Balise de fusion",
431
432
  editValue: "Modifier la valeur de la balise de fusion",
433
+ changeTag: "Remplacer la balise de fusion : {label}",
434
+ unknownLabel: "Balise de fusion",
432
435
  deleteMergeTag: "Supprimer la balise de fusion",
433
436
  suggestionEmpty: "Aucune balise de fusion correspondante",
434
437
  picker: {
435
438
  title: "Insérer une balise de fusion",
439
+ changeTitle: "Remplacer la balise de fusion",
436
440
  searchPlaceholder: "Rechercher des balises de fusion",
437
441
  searchAriaLabel: "Rechercher des balises de fusion",
438
442
  noResults: "Aucune balise de fusion correspondante",
@@ -616,4 +620,4 @@ var e = {
616
620
  //#endregion
617
621
  export { e as default };
618
622
 
619
- //# sourceMappingURL=fr-Brr8mJ9e.js.map
623
+ //# sourceMappingURL=fr-B8MIKjT4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fr-Brr8mJ9e.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\n header: {\n save: \"Enregistrer\",\n saving: \"Enregistrement...\",\n saved: \"Enregistré\",\n unsaved: \"Non enregistré\",\n saveFailed: \"Échec de l'enregistrement\",\n saveNoTemplate: \"Chargez ou créez d'abord un modèle\",\n templateName: \"Nom du modèle\",\n rename: \"Renommer le modèle\",\n untitled: \"Sans titre\",\n updatedAt: \"Modifié {time}\",\n createdAt: \"Créé {time}\",\n updatedJustNow: \"Modifié à l'instant\",\n createdJustNow: \"Créé à l'instant\",\n },\n\n // Relative timestamps, shared by every surface that shows one: the header's\n // updated line, saved blocks, comments and version history.\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 // Toolbar - Paragraph\n paragraph: {\n paragraphSpacing: \"Espacement des paragraphes\",\n },\n\n history: {\n collabWarning:\n \"Annuler peut affecter les modifications récentes de vos collaborateurs\",\n undo: \"Annuler\",\n redo: \"Rétablir\",\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\n // Placeholder text a newly inserted block starts with. Author-facing\n // prompts, meant to be overwritten — so they follow the editor UI locale.\n // Recipient-facing defaults live in `i18n/contentDefaults.ts` and follow\n // the template's own `settings.locale` instead.\n blockDefaults: {\n title: \"Saisissez votre titre\",\n paragraph: \"Saisissez votre texte ici\",\n button: \"Cliquez ici\",\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 alignJustify: \"Justifier\",\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 },\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 height: \"Hauteur\",\n heightAuto: \"Automatique\",\n heightCustom: \"Personnalisée\",\n borderRadius: \"Rayon de bordure\",\n linkUrl: \"URL du lien\",\n openInNewTab: \"Ouvrir dans un nouvel onglet\",\n placeholderUrl: \"Image de substitution\",\n optional: \"(facultatif)\",\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 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 height: \"Hauteur\",\n heightAuto: \"Automatique\",\n heightCustom: \"Personnalisée\",\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 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 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 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 contentDirection: \"De droite à gauche\",\n contentDirectionHint:\n \"Sens d'écriture de l'e-mail, indépendant de la langue de l'éditeur. S'il n'est pas défini, il suit la langue du contenu (arabe, hébreu, …).\",\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 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 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 },\n comments: {\n button: \"Commentaires\",\n title: \"Commentaires\",\n placeholder: \"Écrire un commentaire...\",\n replyPlaceholder: \"Écrire une réponse...\",\n reply: \"Répondre\",\n resolve: \"Résoudre\",\n unresolve: \"Réouvrir\",\n delete: \"Supprimer\",\n edit: \"Modifier\",\n cancel: \"Annuler\",\n save: \"Enregistrer\",\n noComments: \"Aucun commentaire\",\n noCommentsHint:\n \"Démarrez une conversation en ajoutant un commentaire au modèle ou à un bloc précis.\",\n deleteConfirm: \"Supprimer ce commentaire ?\",\n filterAll: \"Tous\",\n filterUnresolved: \"Non résolus\",\n filterBlock: \"Ce bloc\",\n jumpToBlock: \"Bloc\",\n ownedByYou: \"Vous\",\n edited: \"modifié\",\n resolvedBy: \"Résolu par {name}\",\n replyOne: \"{count} réponse\",\n replyMany: \"{count} réponses\",\n missingBlock: \"Bloc introuvable\",\n saveTemplateFirst: \"Enregistrez le modèle avant de commenter ce bloc.\",\n },\n versionHistory: {\n tooltip: \"Historique des versions\",\n dropdownTitle: \"Historique des versions\",\n empty: \"Aucune version pour l’instant\",\n auto: \"auto\",\n olderVersion: \"Version précédente\",\n newerVersion: \"Version plus récente\",\n },\n versionPreview: {\n message: \"Vous consultez une version antérieure de ce modèle.\",\n cancel: \"Annuler\",\n restore: \"Restaurer cette version\",\n restoreConfirm: {\n title: \"Restaurer cette version ?\",\n unsavedWithSave:\n \"Vous avez des modifications non enregistrées. Enregistrez-les d’abord et elles resteront dans l’historique ; restaurez sans enregistrer et elles seront perdues.\",\n unsavedNoSave:\n \"Vous avez des modifications non enregistrées et aucun endroit où les enregistrer. Restaurer cette version les fera disparaître.\",\n saveAndRestore: \"Enregistrer, puis restaurer\",\n restoreAnyway: \"Restaurer quand même\",\n cancel: \"Annuler\",\n },\n },\n previewResolution: {\n resolving: \"Résolution de l’aperçu…\",\n failed:\n \"L’aperçu n’a pas pu être résolu — le modèle non résolu est affiché.\",\n hint: \"L’aperçu utilise des données résolues par votre backend.\",\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 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":"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"}
1
+ {"version":3,"file":"fr-B8MIKjT4.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\n header: {\n save: \"Enregistrer\",\n saving: \"Enregistrement...\",\n saved: \"Enregistré\",\n unsaved: \"Non enregistré\",\n saveFailed: \"Échec de l'enregistrement\",\n saveNoTemplate: \"Chargez ou créez d'abord un modèle\",\n templateName: \"Nom du modèle\",\n rename: \"Renommer le modèle\",\n untitled: \"Sans titre\",\n updatedAt: \"Modifié {time}\",\n createdAt: \"Créé {time}\",\n updatedJustNow: \"Modifié à l'instant\",\n createdJustNow: \"Créé à l'instant\",\n },\n\n // Relative timestamps, shared by every surface that shows one: the header's\n // updated line, saved blocks, comments and version history.\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 // Toolbar - Paragraph\n paragraph: {\n paragraphSpacing: \"Espacement des paragraphes\",\n },\n\n history: {\n collabWarning:\n \"Annuler peut affecter les modifications récentes de vos collaborateurs\",\n undo: \"Annuler\",\n redo: \"Rétablir\",\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\n // Placeholder text a newly inserted block starts with. Author-facing\n // prompts, meant to be overwritten — so they follow the editor UI locale.\n // Recipient-facing defaults live in `i18n/contentDefaults.ts` and follow\n // the template's own `settings.locale` instead.\n blockDefaults: {\n title: \"Saisissez votre titre\",\n paragraph: \"Saisissez votre texte ici\",\n button: \"Cliquez ici\",\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 alignJustify: \"Justifier\",\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 },\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 height: \"Hauteur\",\n heightAuto: \"Automatique\",\n heightCustom: \"Personnalisée\",\n borderRadius: \"Rayon de bordure\",\n linkUrl: \"URL du lien\",\n openInNewTab: \"Ouvrir dans un nouvel onglet\",\n placeholderUrl: \"Image de substitution\",\n optional: \"(facultatif)\",\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 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 height: \"Hauteur\",\n heightAuto: \"Automatique\",\n heightCustom: \"Personnalisée\",\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 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 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 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 contentDirection: \"De droite à gauche\",\n contentDirectionHint:\n \"Sens d'écriture de l'e-mail, indépendant de la langue de l'éditeur. S'il n'est pas défini, il suit la langue du contenu (arabe, hébreu, …).\",\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 editAsText: \"Modifier comme texte\",\n fieldGroup: \"Valeur avec balises de fusion\",\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 changeTag: \"Remplacer la balise de fusion : {label}\",\n unknownLabel: \"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 changeTitle: \"Remplacer la 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 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 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 },\n comments: {\n button: \"Commentaires\",\n title: \"Commentaires\",\n placeholder: \"Écrire un commentaire...\",\n replyPlaceholder: \"Écrire une réponse...\",\n reply: \"Répondre\",\n resolve: \"Résoudre\",\n unresolve: \"Réouvrir\",\n delete: \"Supprimer\",\n edit: \"Modifier\",\n cancel: \"Annuler\",\n save: \"Enregistrer\",\n noComments: \"Aucun commentaire\",\n noCommentsHint:\n \"Démarrez une conversation en ajoutant un commentaire au modèle ou à un bloc précis.\",\n deleteConfirm: \"Supprimer ce commentaire ?\",\n filterAll: \"Tous\",\n filterUnresolved: \"Non résolus\",\n filterBlock: \"Ce bloc\",\n jumpToBlock: \"Bloc\",\n ownedByYou: \"Vous\",\n edited: \"modifié\",\n resolvedBy: \"Résolu par {name}\",\n replyOne: \"{count} réponse\",\n replyMany: \"{count} réponses\",\n missingBlock: \"Bloc introuvable\",\n saveTemplateFirst: \"Enregistrez le modèle avant de commenter ce bloc.\",\n },\n versionHistory: {\n tooltip: \"Historique des versions\",\n dropdownTitle: \"Historique des versions\",\n empty: \"Aucune version pour l’instant\",\n auto: \"auto\",\n olderVersion: \"Version précédente\",\n newerVersion: \"Version plus récente\",\n },\n versionPreview: {\n message: \"Vous consultez une version antérieure de ce modèle.\",\n cancel: \"Annuler\",\n restore: \"Restaurer cette version\",\n restoreConfirm: {\n title: \"Restaurer cette version ?\",\n unsavedWithSave:\n \"Vous avez des modifications non enregistrées. Enregistrez-les d’abord et elles resteront dans l’historique ; restaurez sans enregistrer et elles seront perdues.\",\n unsavedNoSave:\n \"Vous avez des modifications non enregistrées et aucun endroit où les enregistrer. Restaurer cette version les fera disparaître.\",\n saveAndRestore: \"Enregistrer, puis restaurer\",\n restoreAnyway: \"Restaurer quand même\",\n cancel: \"Annuler\",\n },\n },\n previewResolution: {\n resolving: \"Résolution de l’aperçu…\",\n failed:\n \"L’aperçu n’a pas pu être résolu — le modèle non résolu est affiché.\",\n hint: \"L’aperçu utilise des données résolues par votre backend.\",\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 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":"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"}