@templatical/editor 0.29.1 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/dist/{AiChatSidebar-DsYJwCLT.js → AiChatSidebar-DYDtzTDd.js} +8 -8
  2. package/dist/{AiFeatureMenu-CehKC-dh.js → AiFeatureMenu-BJ882XCi.js} +4 -4
  3. package/dist/{BlockIssueBadge-Dhk7Hv4m.js → BlockIssueBadge-D6y8vQpL.js} +2 -2
  4. package/dist/{BlockPreviewCanvas-BQZ7aTPr.js → BlockPreviewCanvas-DQNxLy7u.js} +1 -1
  5. package/dist/{CloudHeaderExtras-CaRdlYpY.js → CloudHeaderExtras-CqG3RaKw.js} +2 -2
  6. package/dist/{CloudPanels-CYqHk1Az.js → CloudPanels-B6xrk7kN.js} +3 -3
  7. package/dist/{CollaboratorBar-BZi12Mut.js → CollaboratorBar-by16gXQH.js} +2 -2
  8. package/dist/{ColorPicker-CXPSbnRD.js → ColorPicker-E5gqlCZE.js} +1 -1
  9. package/dist/{CommentsPanel-DnWdgQHg.js → CommentsPanel-B_kzvTHR.js} +1 -1
  10. package/dist/{CommentsSidebar-ZOqmuo4D.js → CommentsSidebar-gfzUX7cd.js} +10 -10
  11. package/dist/{CountdownToolbar-ByQVLqFF.js → CountdownToolbar-DU8UHx9A.js} +17 -17
  12. package/dist/{DesignReferenceSidebar-B9anB-Q0.js → DesignReferenceSidebar-DgndMB4H.js} +6 -6
  13. package/dist/{NumberWithSuffix-C-k0BP1m.js → FieldRow-0-UbQR4a.js} +23 -16
  14. package/dist/{IssuesPanel-CDk7lUna.js → IssuesPanel-DmJTb_SZ.js} +5 -5
  15. package/dist/{MergeTagModeToggle-sBEGugix.js → MergeTagModeToggle-CZnJ2Gz_.js} +3 -3
  16. package/dist/{MergeTagSuggestion-DPfXtDzP.js → MergeTagSuggestion-DyUcY_9e.js} +2 -2
  17. package/dist/{ParagraphEditor-gbp5gbFv.js → ParagraphEditor-CnB4kXle.js} +19 -19
  18. package/dist/{RestoreVersionDialog-DIHpGfFr.js → RestoreVersionDialog-BpOphPiE.js} +3 -3
  19. package/dist/{RichTextEditorContent-DZ6GiAUi.js → RichTextEditorContent-ChPNgHQ_.js} +3 -3
  20. package/dist/{SaveBlockDialog-QSj7tf1p.js → SaveBlockDialog-CKw4Va6j.js} +6 -6
  21. package/dist/{SavedBlocksBrowserModal-Bz2xaBzJ.js → SavedBlocksBrowserModal-SST-7EMK.js} +7 -7
  22. package/dist/{SavedBlocksPanels-RNgOnK9j.js → SavedBlocksPanels-ChV8bOgM.js} +1 -1
  23. package/dist/{SavedBlocksPickBar-CRmd3sD9.js → SavedBlocksPickBar-BbEeD5RB.js} +2 -2
  24. package/dist/{TemplateScoringPanel-CDwlSFEe.js → TemplateScoringPanel-De8BZpRU.js} +10 -10
  25. package/dist/{TestEmailModal-DclmELUc.js → TestEmailModal-4d2pXeHU.js} +7 -7
  26. package/dist/{TestEmailPanel-4i4n9Kup.js → TestEmailPanel-DEgCesNP.js} +1 -1
  27. package/dist/{TitleEditor-DMAeSWx3.js → TitleEditor-89pmKLVY.js} +8 -8
  28. package/dist/{TplModal-CjuKT36J.js → TplModal-DswccJRJ.js} +1 -1
  29. package/dist/{VersionHistoryMenu-B6zAcmAC.js → VersionHistoryMenu-DBxSJR1k.js} +4 -4
  30. package/dist/{VersionHistoryPanels-MqgexkhW.js → VersionHistoryPanels-CFLHDH9P.js} +1 -1
  31. package/dist/{VersionPreviewBanner-CQlSzQ2B.js → VersionPreviewBanner-DhG5RcRt.js} +1 -1
  32. package/dist/{blockTypeIcons-ejNais7n.js → blockTypeIcons-dpKs5GQc.js} +2 -2
  33. package/dist/bundle-stats.json +6 -6
  34. package/dist/{ca-DY0AYOLG.js → ca-DZSrLNXK.js} +2 -0
  35. package/dist/cdn/chunks/{AiChatSidebar-BE97qqqb.js → AiChatSidebar-DmYDRmvX.js} +6 -6
  36. package/dist/cdn/chunks/{AiChatSidebar-BE97qqqb.js.map → AiChatSidebar-DmYDRmvX.js.map} +1 -1
  37. package/dist/cdn/chunks/{AiFeatureMenu-CNP54HPc.js → AiFeatureMenu-C0Rt08qb.js} +3 -3
  38. package/dist/cdn/chunks/{AiFeatureMenu-CNP54HPc.js.map → AiFeatureMenu-C0Rt08qb.js.map} +1 -1
  39. package/dist/cdn/chunks/{BlockIssueBadge-Bry71Wjz.js → BlockIssueBadge-BBog2CMy.js} +2 -2
  40. package/dist/cdn/chunks/{BlockIssueBadge-Bry71Wjz.js.map → BlockIssueBadge-BBog2CMy.js.map} +1 -1
  41. package/dist/cdn/chunks/{BlockPreviewCanvas-CUEZIwJ4.js → BlockPreviewCanvas-DNBjBKBI.js} +2 -2
  42. package/dist/cdn/chunks/{BlockPreviewCanvas-CUEZIwJ4.js.map → BlockPreviewCanvas-DNBjBKBI.js.map} +1 -1
  43. package/dist/cdn/chunks/{CloudHeaderExtras-Bz--_dKu.js → CloudHeaderExtras-Ditfv7y9.js} +3 -3
  44. package/dist/cdn/chunks/{CloudHeaderExtras-Bz--_dKu.js.map → CloudHeaderExtras-Ditfv7y9.js.map} +1 -1
  45. package/dist/cdn/chunks/{CloudPanels-BXcdYgy0.js → CloudPanels-C4U5bJO6.js} +4 -4
  46. package/dist/cdn/chunks/{CloudPanels-BXcdYgy0.js.map → CloudPanels-C4U5bJO6.js.map} +1 -1
  47. package/dist/cdn/chunks/{CollaboratorBar-CvvoIrKS.js → CollaboratorBar-B79JR9NH.js} +3 -3
  48. package/dist/cdn/chunks/{CollaboratorBar-CvvoIrKS.js.map → CollaboratorBar-B79JR9NH.js.map} +1 -1
  49. package/dist/cdn/chunks/{ColorPicker-Ww4xHHMI.js → ColorPicker-C-ZiwUV3.js} +2 -2
  50. package/dist/cdn/chunks/{ColorPicker-Ww4xHHMI.js.map → ColorPicker-C-ZiwUV3.js.map} +1 -1
  51. package/dist/cdn/chunks/{CommentsPanel-DjId-XH-.js → CommentsPanel-D1Ke8PbO.js} +2 -2
  52. package/dist/cdn/chunks/{CommentsPanel-DjId-XH-.js.map → CommentsPanel-D1Ke8PbO.js.map} +1 -1
  53. package/dist/cdn/chunks/{CommentsSidebar-DXXGWSr4.js → CommentsSidebar-B-UyhIZN.js} +2 -2
  54. package/dist/cdn/chunks/{CommentsSidebar-DXXGWSr4.js.map → CommentsSidebar-B-UyhIZN.js.map} +1 -1
  55. package/dist/cdn/chunks/{CountdownToolbar-BD90NpY1.js → CountdownToolbar-DyOHOu44.js} +18 -18
  56. package/dist/cdn/chunks/{CountdownToolbar-BD90NpY1.js.map → CountdownToolbar-DyOHOu44.js.map} +1 -1
  57. package/dist/cdn/chunks/{DesignReferenceSidebar-DY-laxO5.js → DesignReferenceSidebar-BCCX1FtP.js} +3 -3
  58. package/dist/cdn/chunks/{DesignReferenceSidebar-DY-laxO5.js.map → DesignReferenceSidebar-BCCX1FtP.js.map} +1 -1
  59. package/dist/cdn/chunks/{NumberWithSuffix-DOG0zHvY.js → FieldRow-CbcpsxZ4.js} +24 -17
  60. package/dist/cdn/chunks/FieldRow-CbcpsxZ4.js.map +1 -0
  61. package/dist/cdn/chunks/{IssuesPanel-iC2hgrXx.js → IssuesPanel-3vD3ImHF.js} +2 -2
  62. package/dist/cdn/chunks/{IssuesPanel-iC2hgrXx.js.map → IssuesPanel-3vD3ImHF.js.map} +1 -1
  63. package/dist/cdn/chunks/{MergeTagModeToggle-BRW3qErZ.js → MergeTagModeToggle-BU0SDRow.js} +3 -3
  64. package/dist/cdn/chunks/{MergeTagModeToggle-BRW3qErZ.js.map → MergeTagModeToggle-BU0SDRow.js.map} +1 -1
  65. package/dist/cdn/chunks/{MergeTagSuggestion-VP_nC-8W.js → MergeTagSuggestion-B9vL0VaG.js} +2 -2
  66. package/dist/cdn/chunks/{MergeTagSuggestion-VP_nC-8W.js.map → MergeTagSuggestion-B9vL0VaG.js.map} +1 -1
  67. package/dist/cdn/chunks/{ParagraphEditor-CPVnO48U.js → ParagraphEditor-CSwIuvoF.js} +22 -22
  68. package/dist/cdn/chunks/{ParagraphEditor-CPVnO48U.js.map → ParagraphEditor-CSwIuvoF.js.map} +1 -1
  69. package/dist/cdn/chunks/{RestoreVersionDialog--Blx-VKu.js → RestoreVersionDialog-Bvg2WvJN.js} +3 -3
  70. package/dist/cdn/chunks/{RestoreVersionDialog--Blx-VKu.js.map → RestoreVersionDialog-Bvg2WvJN.js.map} +1 -1
  71. package/dist/cdn/chunks/{RichTextEditorContent-DpvOKKH-.js → RichTextEditorContent-DdkmEEpK.js} +3 -3
  72. package/dist/cdn/chunks/{RichTextEditorContent-DpvOKKH-.js.map → RichTextEditorContent-DdkmEEpK.js.map} +1 -1
  73. package/dist/cdn/chunks/{SaveBlockDialog-DXQ2g_38.js → SaveBlockDialog-D-QO3LuR.js} +5 -5
  74. package/dist/cdn/chunks/{SaveBlockDialog-DXQ2g_38.js.map → SaveBlockDialog-D-QO3LuR.js.map} +1 -1
  75. package/dist/cdn/chunks/{SavedBlocksBrowserModal-DWBvVkuk.js → SavedBlocksBrowserModal-BRdN56r7.js} +6 -6
  76. package/dist/cdn/chunks/{SavedBlocksBrowserModal-DWBvVkuk.js.map → SavedBlocksBrowserModal-BRdN56r7.js.map} +1 -1
  77. package/dist/cdn/chunks/{SavedBlocksPanels-GgdpiPUq.js → SavedBlocksPanels-D9GTlLgb.js} +2 -2
  78. package/dist/cdn/chunks/{SavedBlocksPanels-GgdpiPUq.js.map → SavedBlocksPanels-D9GTlLgb.js.map} +1 -1
  79. package/dist/cdn/chunks/{SavedBlocksPickBar-Dyb5xi1B.js → SavedBlocksPickBar-DSRcUeIo.js} +3 -3
  80. package/dist/cdn/chunks/{SavedBlocksPickBar-Dyb5xi1B.js.map → SavedBlocksPickBar-DSRcUeIo.js.map} +1 -1
  81. package/dist/cdn/chunks/{TemplateScoringPanel-B0YcaJsR.js → TemplateScoringPanel-Dy5oOVhB.js} +2 -2
  82. package/dist/cdn/chunks/{TemplateScoringPanel-B0YcaJsR.js.map → TemplateScoringPanel-Dy5oOVhB.js.map} +1 -1
  83. package/dist/cdn/chunks/{TestEmailModal-B9SmAIKZ.js → TestEmailModal-B4L2lmIV.js} +7 -7
  84. package/dist/cdn/chunks/{TestEmailModal-B9SmAIKZ.js.map → TestEmailModal-B4L2lmIV.js.map} +1 -1
  85. package/dist/cdn/chunks/{TestEmailPanel-Q6alElB1.js → TestEmailPanel-cTPgEf-D.js} +2 -2
  86. package/dist/cdn/chunks/{TestEmailPanel-Q6alElB1.js.map → TestEmailPanel-cTPgEf-D.js.map} +1 -1
  87. package/dist/cdn/chunks/{TitleEditor-Tudoac5f.js → TitleEditor-BKjL2Zs1.js} +8 -8
  88. package/dist/cdn/chunks/{TitleEditor-Tudoac5f.js.map → TitleEditor-BKjL2Zs1.js.map} +1 -1
  89. package/dist/cdn/chunks/{TplModal-BNJIFnyj.js → TplModal-DxrgNmt9.js} +2 -2
  90. package/dist/cdn/chunks/{TplModal-BNJIFnyj.js.map → TplModal-DxrgNmt9.js.map} +1 -1
  91. package/dist/cdn/chunks/{VersionHistoryMenu-DJGcA_RX.js → VersionHistoryMenu-CMqZFUHE.js} +2 -2
  92. package/dist/cdn/chunks/{VersionHistoryMenu-DJGcA_RX.js.map → VersionHistoryMenu-CMqZFUHE.js.map} +1 -1
  93. package/dist/cdn/chunks/{VersionHistoryPanels-Crw5JA89.js → VersionHistoryPanels-CxIFBJsz.js} +2 -2
  94. package/dist/cdn/chunks/{VersionHistoryPanels-Crw5JA89.js.map → VersionHistoryPanels-CxIFBJsz.js.map} +1 -1
  95. package/dist/cdn/chunks/{VersionPreviewBanner-C8pfES5A.js → VersionPreviewBanner-CdsZvVYF.js} +2 -2
  96. package/dist/cdn/chunks/{VersionPreviewBanner-C8pfES5A.js.map → VersionPreviewBanner-CdsZvVYF.js.map} +1 -1
  97. package/dist/cdn/chunks/{blockTypeIcons-JUwZtKaq.js → blockTypeIcons-DXPd_hd1.js} +2 -2
  98. package/dist/cdn/chunks/{blockTypeIcons-JUwZtKaq.js.map → blockTypeIcons-DXPd_hd1.js.map} +1 -1
  99. package/dist/cdn/chunks/{ca-DY0AYOLG.js → ca-DZSrLNXK.js} +3 -1
  100. package/dist/cdn/chunks/ca-DZSrLNXK.js.map +1 -0
  101. package/dist/cdn/chunks/{cloud-C29LPXYn.js → cloud-CITqEHEc.js} +2 -2
  102. package/dist/cdn/chunks/{cloud-C29LPXYn.js.map → cloud-CITqEHEc.js.map} +1 -1
  103. package/dist/cdn/chunks/{createCloudRuntime-C6MJN7M6.js → createCloudRuntime-DwIXvrb0.js} +4 -4
  104. package/dist/cdn/chunks/{createCloudRuntime-C6MJN7M6.js.map → createCloudRuntime-DwIXvrb0.js.map} +1 -1
  105. package/dist/{de-CYLWugqb.js → cdn/chunks/de-DbayqpK-.js} +4 -0
  106. package/dist/cdn/chunks/{de-CYLWugqb.js.map → de-DbayqpK-.js.map} +1 -1
  107. package/dist/cdn/chunks/en-BzFt4b80.js +2 -0
  108. package/dist/cdn/chunks/{en-C3TM249M.js → en-l0ib5X0f.js} +3 -1
  109. package/dist/cdn/chunks/en-l0ib5X0f.js.map +1 -0
  110. package/dist/cdn/chunks/{es-D1SF4nCR.js → es-CMQ-5PJP.js} +3 -1
  111. package/dist/cdn/chunks/es-CMQ-5PJP.js.map +1 -0
  112. package/dist/cdn/chunks/{extensions-BQefRevf.js → extensions-C87Z6_23.js} +5 -5
  113. package/dist/cdn/chunks/{extensions-BQefRevf.js.map → extensions-C87Z6_23.js.map} +1 -1
  114. package/dist/{fr-CdLhJ7kw.js → cdn/chunks/fr-DNXmZWAq.js} +4 -0
  115. package/dist/cdn/chunks/fr-DNXmZWAq.js.map +1 -0
  116. package/dist/cdn/chunks/{icons-BTdLXRXn.js → icons-ciivb5BS.js} +10 -10
  117. package/dist/cdn/chunks/{icons-BTdLXRXn.js.map → icons-ciivb5BS.js.map} +1 -1
  118. package/dist/{nl-BvsLoyKp.js → cdn/chunks/nl-BylRRHYJ.js} +4 -0
  119. package/dist/cdn/chunks/nl-BylRRHYJ.js.map +1 -0
  120. package/dist/cdn/chunks/{preRenderCustomBlocks-CbA3RcAy.js → preRenderCustomBlocks-DyCIgmqJ.js} +2 -2
  121. package/dist/cdn/chunks/{preRenderCustomBlocks-CbA3RcAy.js.map → preRenderCustomBlocks-DyCIgmqJ.js.map} +1 -1
  122. package/dist/cdn/chunks/{pt-BR-CAGS5YXp.js → pt-BR-BVoJhpie.js} +3 -1
  123. package/dist/cdn/chunks/pt-BR-BVoJhpie.js.map +1 -0
  124. package/dist/cdn/chunks/{src-Cx70q30o.js → src-6J-yyZoD.js} +2 -2
  125. package/dist/cdn/chunks/{src-Cx70q30o.js.map → src-6J-yyZoD.js.map} +1 -1
  126. package/dist/cdn/chunks/{src-B_QJduQD.js → src-BD60gqPW.js} +72 -67
  127. package/dist/cdn/chunks/src-BD60gqPW.js.map +1 -0
  128. package/dist/cdn/chunks/{src-fxaI2EQc.js → src-Bid3cmHa.js} +4 -4
  129. package/dist/cdn/chunks/{src-fxaI2EQc.js.map → src-Bid3cmHa.js.map} +1 -1
  130. package/dist/cdn/chunks/{src-CjSrA_o4.js → src-Cf0ohOog.js} +166 -136
  131. package/dist/cdn/chunks/src-Cf0ohOog.js.map +1 -0
  132. package/dist/cdn/chunks/{tiptap-Bqy-H6CT.js → tiptap-Ey0FpaX7.js} +1710 -1700
  133. package/dist/cdn/chunks/tiptap-Ey0FpaX7.js.map +1 -0
  134. package/dist/cdn/chunks/{useEditorCore-o2emEjgF.js → useEditorCore-CTNB2Mkl.js} +351 -356
  135. package/dist/cdn/chunks/{useEditorCore-o2emEjgF.js.map → useEditorCore-CTNB2Mkl.js.map} +1 -1
  136. package/dist/cdn/chunks/{useMergeTag-BWt1DQS1.js → useMergeTag-lWo7So18.js} +2 -2
  137. package/dist/cdn/chunks/{useMergeTag-BWt1DQS1.js.map → useMergeTag-lWo7So18.js.map} +1 -1
  138. package/dist/cdn/editor.css +1 -1
  139. package/dist/cdn/editor.js +943 -911
  140. package/dist/cdn/editor.js.map +1 -1
  141. package/dist/{check-CTe6VejT.js → check-80E6ZGin.js} +1 -1
  142. package/dist/{chevron-down-BBThVMu-.js → chevron-down-BmkLsn2c.js} +1 -1
  143. package/dist/{chevron-up-iECwf-Bc.js → chevron-up-DJSAzlUU.js} +1 -1
  144. package/dist/{circle-alert-Z_eeykrO.js → circle-alert-BsCfZryY.js} +1 -1
  145. package/dist/{clock-CEj1c29j.js → clock-BcLIngSK.js} +1 -1
  146. package/dist/{cloud-CHHQWdaR.js → cloud-DwJ8ebNl.js} +1 -1
  147. package/dist/{createCloudRuntime-WwKt9mgb.js → createCloudRuntime-CdXQdl34.js} +2 -2
  148. package/dist/{createLucideIcon-DphAT3tw.js → createLucideIcon-eeetEgBb.js} +2 -2
  149. package/dist/{cdn/chunks/de-CYLWugqb.js → de-DbayqpK-.js} +2 -2
  150. package/dist/{dist-nmzPlqlz.js → dist-BC1y_U2m.js} +151 -141
  151. package/dist/{dist-gWM8H2hz.js → dist-BFcAowKZ.js} +2 -2
  152. package/dist/dist-BQqIUwvB.js +5 -0
  153. package/dist/{dist-DLaIQ5H5.js → dist-BkAVGSRr.js} +6 -6
  154. package/dist/{dist-BfcqryVg.js → dist-CQ9T1yi-.js} +2 -2
  155. package/dist/{dist-CaR5TLiM.js → dist-CWC5t5J3.js} +2 -2
  156. package/dist/{dist-D2P8U3p6.js → dist-Cd0LvUlh.js} +2 -2
  157. package/dist/{dist-DSgmnQ-f.js → dist-CvW1nNzy.js} +2 -2
  158. package/dist/{dist-B1kLn1rs.js → dist-CzVIVbSa.js} +90 -85
  159. package/dist/{dist-9fjN9cuD.js → dist-D8MekYFl.js} +2 -2
  160. package/dist/{dist-DifptC-U.js → dist-Do83S47T.js} +2 -2
  161. package/dist/{dist-BdIwIlKz.js → dist-prgdllHG.js} +2 -2
  162. package/dist/dist-waDcdb1l.js +5 -0
  163. package/dist/{en-C3TM249M.js → en-l0ib5X0f.js} +2 -0
  164. package/dist/{es-D1SF4nCR.js → es-CMQ-5PJP.js} +2 -0
  165. package/dist/{extensions-B4gwZ36u.js → extensions-BYImwYeO.js} +15 -15
  166. package/dist/{cdn/chunks/fr-CdLhJ7kw.js → fr-DNXmZWAq.js} +2 -2
  167. package/dist/{image-up-W1INxCu8.js → image-up-BfxY85ar.js} +1 -1
  168. package/dist/{info-5t4WYKfh.js → info-LX4QFBr6.js} +1 -1
  169. package/dist/{loader-circle-DJCZ_JMY.js → loader-circle-Bwima0v8.js} +1 -1
  170. package/dist/{message-circle-Biu6lHh_.js → message-circle-Box-mf2k.js} +1 -1
  171. package/dist/{cdn/chunks/nl-BvsLoyKp.js → nl-BylRRHYJ.js} +2 -2
  172. package/dist/{pencil-DkPlMca7.js → pencil-BM9gSq_J.js} +1 -1
  173. package/dist/{preRenderCustomBlocks-BebjKtmw.js → preRenderCustomBlocks-2KyBJocY.js} +1 -1
  174. package/dist/{pt-BR-CAGS5YXp.js → pt-BR-BVoJhpie.js} +2 -0
  175. package/dist/{refresh-cw-DHbpkkol.js → refresh-cw-BuzFX0wH.js} +1 -1
  176. package/dist/{scan-line-DojwGzjU.js → scan-line-Duq1WXoG.js} +1 -1
  177. package/dist/{send-c6ppcE9I.js → send-DZ4nOnIA.js} +1 -1
  178. package/dist/{shield-check-F9T4ylNK.js → shield-check-Cz4BRYdv.js} +1 -1
  179. package/dist/{sparkles-D-0OiTZD.js → sparkles-DP8RqOeL.js} +1 -1
  180. package/dist/style.css +1 -1
  181. package/dist/templatical-editor.js +986 -954
  182. package/dist/{text-align-start-kEEtoRrD.js → text-align-start-D7tXhjUP.js} +1 -1
  183. package/dist/{trash-2-DRQzhY9R.js → trash-2-BS7lZeyb.js} +1 -1
  184. package/dist/{triangle-alert-Bt4-GU3t.js → triangle-alert-Cx4mQGjx.js} +1 -1
  185. package/dist/{upload-D2wtjvH8.js → upload-L8tLVM10.js} +1 -1
  186. package/dist/{useEditorCore-CJp84vJY.js → useEditorCore-CtR46sbJ.js} +868 -873
  187. package/dist/{useMergeTag-D1Rsn4BO.js → useMergeTag-Cx36rtrt.js} +3 -3
  188. package/dist/{useScrollToBlock-B0Qpjfa4.js → useScrollToBlock-tndC8vKo.js} +1 -1
  189. package/dist/{x-YiG-TUGN.js → x-ChIQ7HwK.js} +1 -1
  190. package/package.json +22 -22
  191. package/dist/cdn/chunks/NumberWithSuffix-DOG0zHvY.js.map +0 -1
  192. package/dist/cdn/chunks/ca-DY0AYOLG.js.map +0 -1
  193. package/dist/cdn/chunks/en-C3TM249M.js.map +0 -1
  194. package/dist/cdn/chunks/en-DIwntrh3.js +0 -2
  195. package/dist/cdn/chunks/es-D1SF4nCR.js.map +0 -1
  196. package/dist/cdn/chunks/fr-CdLhJ7kw.js.map +0 -1
  197. package/dist/cdn/chunks/nl-BvsLoyKp.js.map +0 -1
  198. package/dist/cdn/chunks/pt-BR-CAGS5YXp.js.map +0 -1
  199. package/dist/cdn/chunks/src-B_QJduQD.js.map +0 -1
  200. package/dist/cdn/chunks/src-CjSrA_o4.js.map +0 -1
  201. package/dist/cdn/chunks/tiptap-Bqy-H6CT.js.map +0 -1
  202. package/dist/dist-CzMzshfS.js +0 -5
  203. package/dist/dist-DTVuNn8M.js +0 -5
@@ -1 +0,0 @@
1
- {"version":3,"file":"pt-BR-CAGS5YXp.js","names":[],"sources":["../../../src/i18n/locales/pt-BR.ts"],"sourcesContent":["import type en from \"./en\";\n\nconst ptBR: typeof en = {\n // Footer (OSS only)\n footer: {\n poweredBy: \"Desenvolvido por\",\n openSource: \"Código Aberto\",\n },\n\n // Header — nome do template + estado de salvamento. Exibido apenas quando um\n // provedor de templates está configurado.\n header: {\n save: \"Salvar\",\n saving: \"Salvando...\",\n saved: \"Salvo\",\n unsaved: \"Não salvo\",\n saveFailed: \"Falha ao salvar\",\n saveNoTemplate: \"Carregue ou crie um template primeiro\",\n templateName: \"Nome do template\",\n rename: \"Renomear template\",\n untitled: \"Sem título\",\n updatedAt: \"Atualizado {time}\",\n createdAt: \"Criado {time}\",\n updatedJustNow: \"Atualizado agora mesmo\",\n createdJustNow: \"Criado agora mesmo\",\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: \"Agora mesmo\",\n minutesAgo: \"há {minutes}min\",\n hoursAgo: \"há {hours}h\",\n daysAgo: \"há {days}d\",\n },\n\n // History (undo/redo)\n history: {\n collabWarning: \"Desfazer pode afetar alterações recentes de colaboradores\",\n undo: \"Desfazer\",\n redo: \"Refazer\",\n },\n\n // Viewport toggle\n viewport: {\n label: \"Viewport\",\n desktop: \"Desktop\",\n mobile: \"Mobile\",\n },\n\n // Dark mode preview\n darkMode: {\n enable: \"Visualizar Modo Escuro\",\n disable: \"Visualizar Modo Claro\",\n },\n\n // Preview mode\n previewMode: {\n enable: \"Modo de Visualização\",\n disable: \"Sair da Visualização\",\n },\n\n // Sidebar - Block types\n blocks: {\n section: \"Seção\",\n image: \"Imagem\",\n title: \"Título\",\n paragraph: \"Parágrafo\",\n button: \"Botão\",\n divider: \"Divisor\",\n video: \"Vídeo\",\n social: \"Redes Sociais\",\n spacer: \"Espaçador\",\n html: \"HTML\",\n menu: \"Menu\",\n table: \"Tabela\",\n countdown: \"Contagem Regressiva\",\n },\n\n // Right sidebar\n sidebar: {\n content: \"Conteúdo\",\n settings: \"Configurações\",\n noSelection: \"Nenhum elemento selecionado\",\n noSelectionHint: \"Selecione um bloco na tela para editá-lo\",\n },\n\n // Toolbar - Common\n toolbar: {\n duplicate: \"Duplicar\",\n delete: \"Excluir\",\n },\n\n // Title editor toolbar\n titleEditor: {\n toolbar: \"Formatação de título\",\n bold: \"Negrito (Ctrl+B)\",\n italic: \"Itálico (Ctrl+I)\",\n addLink: \"Adicionar Link\",\n },\n\n // Paragraph editor toolbar\n paragraphEditor: {\n toolbar: \"Formatação de texto\",\n bold: \"Negrito (Ctrl+B)\",\n italic: \"Itálico (Ctrl+I)\",\n underline: \"Sublinhado (Ctrl+U)\",\n strikethrough: \"Tachado\",\n subscript: \"Subscrito\",\n superscript: \"Sobrescrito\",\n addLink: \"Adicionar Link\",\n bulletList: \"Lista com Marcadores\",\n numberedList: \"Lista Numerada\",\n alignLeft: \"Alinhar à Esquerda\",\n alignCenter: \"Centralizar\",\n alignRight: \"Alinhar à Direita\",\n alignJustify: \"Justificar\",\n clearFormatting: \"Limpar Formatação\",\n insertEmoji: \"Inserir Emoji\",\n fontFamily: \"Família da Fonte\",\n defaultFont: \"Padrão\",\n fontSize: \"Tamanho da Fonte\",\n defaultSize: \"Padrão\",\n textColor: \"Cor do Texto\",\n highlightColor: \"Cor de Destaque\",\n lineHeight: \"Altura da Linha\",\n letterSpacing: \"Espaçamento entre Letras\",\n emojiItemLabel: \"Inserir emoji {emoji}\",\n },\n\n // Block actions (BlockWrapper)\n blockActions: {\n drag: \"Arraste para reordenar, ou pressione Espaço para mover com o teclado\",\n dragLifted:\n \"Movendo {block}. Use as setas para cima e para baixo para reposicionar, Espaço ou Enter para soltar, Escape para cancelar.\",\n duplicate: \"Duplicar bloco\",\n delete: \"Excluir bloco\",\n hiddenOnViewport: \"Oculto em {viewport}\",\n saveAsBlock: \"Salvar como Bloco\",\n conditionToggle: \"Alternar condição de exibição\",\n comments: \"Comentários ({count})\",\n lifted: \"{block} levantado. Posição {position} de {total}.\",\n moved: \"{block} movido para a posição {position} de {total}.\",\n dropped: \"{block} solto na posição {position} de {total}.\",\n cancelled: \"Movimento cancelado. {block} retornou à posição {position}.\",\n },\n\n // Toolbar - Section\n section: {\n dropHere: \"Solte blocos aqui\",\n columns: \"Colunas\",\n column1: \"1 Coluna\",\n column2: \"2 Colunas\",\n column3: \"3 Colunas\",\n ratio12: \"Proporção 1:2\",\n ratio21: \"Proporção 2:1\",\n borderRadius: \"Arredondamento das Bordas\",\n wrapperEnable: \"Adicionar wrapper\",\n stackOnMobile: \"Empilhar no celular\",\n },\n\n // Text editor link dialog\n linkDialog: {\n editLink: \"Editar Link\",\n insertLink: \"Inserir Link\",\n updateLink: \"Atualizar Link\",\n removeLink: \"Remover Link\",\n cancel: \"Cancelar\",\n urlPlaceholder: \"https://exemplo.com\",\n urlLabel: \"URL\",\n colorLabel: \"Cor do Link\",\n },\n\n // Toolbar - Title\n title: {\n level: \"Nível do Cabeçalho\",\n heading1: \"Cabeçalho 1 (36px)\",\n heading2: \"Cabeçalho 2 (28px)\",\n heading3: \"Cabeçalho 3 (22px)\",\n heading4: \"Cabeçalho 4 (18px)\",\n fontFamily: \"Família da Fonte\",\n inheritFont: \"Usar fonte do template\",\n color: \"Cor\",\n align: \"Alinhamento\",\n alignLeft: \"Esquerda\",\n alignCenter: \"Centro\",\n alignRight: \"Direita\",\n },\n\n // Emoji picker\n emoji: {\n smileys: \"Sorrisos\",\n gestures: \"Gestos\",\n objects: \"Objetos\",\n },\n\n // Toolbar - Image\n image: {\n imageUrl: \"URL da Imagem\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Texto Alternativo\",\n altTextPlaceholder: \"Descrição da imagem\",\n width: \"Largura\",\n fullWidth: \"Largura Total\",\n widthCustom: \"Personalizada\",\n height: \"Altura\",\n heightAuto: \"Automática\",\n heightCustom: \"Personalizada\",\n linkUrl: \"URL do Link\",\n openInNewTab: \"Abrir em nova aba\",\n placeholderUrl: \"Imagem de Espaço Reservado\",\n optional: \"(opcional)\",\n placeholderUrlPlaceholder: \"https://... (somente em design)\",\n placeholderUrlTooltip:\n \"Como a URL da imagem usa uma merge tag, você pode fornecer uma imagem real aqui para visualizar o layout durante o design. Isso não é incluído na saída final.\",\n clickToAdd: \"Clique para adicionar a URL da imagem\",\n browseMedia: \"Explorar Mídia\",\n dropToUpload: \"Solte a imagem para enviar\",\n uploading: \"Enviando…\",\n decorative: \"Imagem decorativa\",\n decorativeHint:\n \"Oculta para leitores de tela. Use apenas para espaçadores e elementos visuais.\",\n },\n\n // Toolbar - Video\n video: {\n videoUrl: \"URL do Vídeo\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n openInNewTab: \"Abrir em nova aba\",\n customThumbnail: \"Miniatura Personalizada\",\n optional: \"(opcional)\",\n thumbnailPlaceholder: \"Gerada automaticamente a partir da URL do vídeo\",\n altText: \"Texto Alternativo\",\n altTextPlaceholder: \"Descrição do vídeo\",\n width: \"Largura\",\n fullWidth: \"Largura Total\",\n height: \"Altura\",\n heightAuto: \"Automática\",\n heightCustom: \"Personalizada\",\n placeholderUrl: \"Miniatura de Espaço Reservado\",\n placeholderUrlPlaceholder: \"https://... (somente em design)\",\n placeholderUrlTooltip:\n \"Como a URL do vídeo usa uma merge tag, você pode fornecer uma miniatura real aqui para visualizar o layout durante o design. Isso não é incluído na saída final.\",\n addVideo: \"Adicionar URL de vídeo\",\n },\n\n // Toolbar - Button\n button: {\n fontFamily: \"Família da Fonte\",\n inheritFont: \"Usar fonte do template\",\n text: \"Texto\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"Abrir em nova aba\",\n background: \"Plano de Fundo\",\n textColor: \"Cor do Texto\",\n borderRadius: \"Arredondamento das Bordas\",\n fontSize: \"Tamanho da Fonte\",\n width: \"Largura\",\n widthAuto: \"Ajustar ao conteúdo\",\n fullWidth: \"Largura Total\",\n widthCustom: \"Personalizada\",\n },\n\n // Toolbar - Divider\n divider: {\n style: \"Estilo\",\n solid: \"Sólido\",\n dashed: \"Tracejado\",\n dotted: \"Pontilhado\",\n color: \"Cor\",\n thickness: \"Espessura\",\n },\n\n // Toolbar - Social Icons\n social: {\n icons: \"Ícones\",\n addIcon: \"Adicionar Ícone\",\n addIcons: \"Adicionar ícones de redes sociais\",\n removeIcon: \"Remover\",\n urlPlaceholder: \"https://...\",\n style: \"Estilo\",\n styleSolid: \"Sólido\",\n styleOutlined: \"Contornado\",\n styleRounded: \"Arredondado\",\n styleSquare: \"Quadrado\",\n styleCircle: \"Circular\",\n size: \"Tamanho\",\n sizeSmall: \"P\",\n sizeMedium: \"M\",\n sizeLarge: \"G\",\n spacing: \"Espaçamento\",\n align: \"Alinhamento\",\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\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n\n // Toolbar - Menu\n menu: {\n items: \"Itens do Menu\",\n addItem: \"Adicionar Item\",\n removeItem: \"Remover\",\n text: \"Texto\",\n urlPlaceholder: \"https://exemplo.com\",\n openInNewTab: \"Abrir em nova aba\",\n bold: \"Negrito\",\n underline: \"Sublinhado\",\n color: \"Cor\",\n linkColor: \"Cor do Link\",\n fontSize: \"Tamanho da Fonte\",\n fontFamily: \"Família da Fonte\",\n separator: \"Separador\",\n separatorColor: \"Cor do Separador\",\n spacing: \"Espaçamento\",\n textAlign: \"Alinhamento\",\n addLinks: \"Adicionar links ao menu\",\n },\n\n // Toolbar - Table\n table: {\n dimensions: \"Dimensões\",\n rows: \"Linhas\",\n columns: \"Colunas\",\n hasHeaderRow: \"Linha de cabeçalho\",\n headerBackgroundColor: \"Plano de Fundo do Cabeçalho\",\n noHeaderBg: \"Sem plano de fundo\",\n borderColor: \"Cor da Borda\",\n borderWidth: \"Espessura da Borda\",\n cellPadding: \"Preenchimento da Célula\",\n fontFamily: \"Família da Fonte\",\n fontSize: \"Tamanho da Fonte\",\n color: \"Cor do Texto\",\n textAlign: \"Alinhamento\",\n cellPlaceholder: \"Digite o texto...\",\n empty: \"Adicionar uma tabela\",\n },\n\n // Toolbar - Spacer\n spacer: {\n height: \"Altura\",\n },\n\n // Toolbar - Countdown\n countdown: {\n targetDate: \"Data Alvo\",\n timezone: \"Fuso Horário\",\n display: \"Exibição\",\n days: \"Dias\",\n hours: \"Horas\",\n minutes: \"Minutos\",\n seconds: \"Segundos\",\n separator: \"Separador\",\n fontFamily: \"Família da Fonte\",\n inheritFont: \"Padrão\",\n digitFontSize: \"Tamanho dos Dígitos\",\n digitColor: \"Cor dos Dígitos\",\n labelColor: \"Cor dos Rótulos\",\n labelFontSize: \"Tamanho dos Rótulos\",\n background: \"Plano de Fundo\",\n labels: \"Rótulos\",\n expiry: \"Mensagem de Expiração\",\n expiredMessagePlaceholder: \"Esta oferta expirou\",\n expiredImageUrl: \"URL da Imagem de Expiração\",\n hideOnExpiry: \"Ocultar ao expirar\",\n setDate: \"Defina uma data alvo no painel de configurações\",\n hidden: \"Oculto (expirado)\",\n },\n\n // Custom Blocks\n customBlocks: {\n definitionNotFound:\n \"Tipo de bloco desconhecido — este bloco não está registrado\",\n renderError:\n \"Este bloco não pôde ser renderizado. Verifique se há erros no template do bloco.\",\n fields: {\n required: \"Obrigatório\",\n addItem: \"Adicionar item\",\n removeItem: \"Remover\",\n maxItemsReached: \"Número máximo de itens atingido\",\n minItemsRequired: \"Mínimo de {count} itens obrigatório\",\n },\n toolbar: {\n noDefinition:\n \"Registre este tipo de bloco na sua configuração do SDK para editar suas propriedades\",\n },\n dataSource: {\n fetchButton: \"Carregar conteúdo\",\n changeButton: \"Alterar\",\n fetching: \"Carregando...\",\n readOnlyTooltip: \"Este valor é carregado da sua fonte de dados\",\n fetchError: \"Falha ao carregar conteúdo\",\n },\n },\n\n // Toolbar - HTML\n html: {\n content: \"Conteúdo HTML\",\n preview: \"Bloco HTML personalizado\",\n empty: \"Adicione conteúdo HTML no painel\",\n sanitizationHint:\n \"O HTML é exportado como está e não é sanitizado — garanta que o conteúdo seja seguro.\",\n },\n\n // Toolbar - Common block settings\n blockSettings: {\n spacing: \"Espaçamento\",\n padding: \"Preenchimento\",\n background: \"Plano de Fundo\",\n color: \"Cor\",\n display: \"Exibição\",\n showOnDesktop: \"Mostrar no desktop\",\n showOnMobile: \"Mostrar no mobile\",\n hiddenOnDevice: \"Oculto em {device}\",\n displayCondition: \"Condição de Exibição\",\n selectCondition: \"Selecionar condição\",\n removeCondition: \"Remover condição\",\n noCondition: \"Sempre visível\",\n conditionApplied: \"Condição aplicada\",\n customCondition: \"Condição personalizada\",\n customConditionLabel: \"Nome da condição\",\n customConditionBefore: \"Antes (lógica de abertura)\",\n customConditionAfter: \"Depois (lógica de fechamento)\",\n applyCondition: \"Aplicar\",\n cancelCondition: \"Cancelar\",\n customBadge: \"Personalizado\",\n restoreHiddenBlocks: \"Mostrar todos os blocos ocultos\",\n },\n\n // Template settings\n templateSettings: {\n layout: \"Layout\",\n widthPreset: \"Largura Predefinida\",\n customWidth: \"Largura Personalizada\",\n appearance: \"Aparência\",\n backgroundColor: \"Cor de Fundo\",\n textColor: \"Cor do Texto\",\n linkColor: \"Cor do Link\",\n linkUnderline: \"Sublinhar Links\",\n fontFamily: \"Família da Fonte\",\n preheaderText: \"Texto de Pré-cabeçalho\",\n preheaderTextPlaceholder:\n \"Texto de prévia exibido após o assunto na caixa de entrada...\",\n preheaderTextHint:\n \"Este texto aparece após o assunto nas pré-visualizações dos clientes de e-mail. Suporta merge tags.\",\n language: \"Idioma\",\n contentLocale: \"Idioma do conteúdo\",\n contentLocaleHint:\n \"Código BCP 47 (ex.: en, de, pt-BR). Define o atributo lang do e-mail renderizado para que leitores de tela pronunciem o conteúdo corretamente.\",\n tips: \"Dicas\",\n tip1: \"600px é a largura padrão para templates de e-mail\",\n tip2: \"Use fontes seguras para web para melhor compatibilidade\",\n tip3: \"Fundos claros funcionam melhor para legibilidade\",\n },\n\n // Spacing control\n spacingControl: {\n lockAll: \"Travar todos os lados\",\n unlock: \"Destravar lados\",\n top: \"Superior\",\n right: \"Direito\",\n bottom: \"Inferior\",\n left: \"Esquerdo\",\n decreaseTop: \"Diminuir superior\",\n increaseTop: \"Aumentar superior\",\n decreaseLeft: \"Diminuir esquerdo\",\n increaseLeft: \"Aumentar esquerdo\",\n decreaseRight: \"Diminuir direito\",\n increaseRight: \"Aumentar direito\",\n decreaseBottom: \"Diminuir inferior\",\n increaseBottom: \"Aumentar inferior\",\n },\n\n // Color Picker\n colorPicker: {\n pickColor: \"Escolher uma cor\",\n hexValue: \"Valor hexadecimal da cor\",\n notSet: \"Não definido\",\n clear: \"Limpar cor\",\n presetColors: \"Cores predefinidas\",\n },\n\n // Merge Tag\n mergeTag: {\n clickToEdit: \"Clique para editar\",\n remove: \"Remover merge tag\",\n insert: \"Inserir merge tag\",\n insertShort: \"Merge tag\",\n editValue: \"Editar valor da merge tag\",\n deleteMergeTag: \"Excluir merge tag\",\n suggestionEmpty: \"Nenhuma merge tag correspondente\",\n picker: {\n title: \"Inserir merge tag\",\n searchPlaceholder: \"Pesquisar merge tags\",\n searchAriaLabel: \"Pesquisar merge tags\",\n noResults: \"Nenhuma merge tag correspondente\",\n empty: \"Nenhuma merge tag configurada\",\n otherGroup: \"Outros\",\n close: \"Fechar\",\n groupCount: \"{count}\",\n sample: \"Pré-visualização: {sample}\",\n },\n },\n\n // Logic tags (standalone, separate from merge tags)\n logicTag: {\n insert: \"Inserir lógica\",\n insertShort: \"Lógica\",\n picker: {\n title: \"Inserir lógica\",\n searchPlaceholder: \"Buscar tags de lógica\",\n searchAriaLabel: \"Buscar tags de lógica\",\n noResults: \"Nenhuma tag de lógica correspondente\",\n empty: \"Nenhuma tag de lógica configurada\",\n otherGroup: \"Outros\",\n close: \"Fechar\",\n },\n },\n\n // Canvas\n canvas: {\n noBlocks: \"Nenhum bloco ainda\",\n dragHint: \"Comece do zero arrastando blocos da barra lateral\",\n dropHere: \"Solte aqui\",\n aiHintChat: \"ou deixe a\",\n aiHintChatSuffix: \"gerar um template completo para você em segundos\",\n aiHintDesign:\n \"Tem um design existente? Envie uma captura de tela, imagem ou PDF e a\",\n aiHintDesignSuffix: \"recriará instantaneamente\",\n },\n\n // Sidebar\n savedBlocks: {\n title: \"Blocos Salvos\",\n saveAsBlock: \"Salvar como Bloco\",\n name: \"Nome\",\n namePlaceholder: \"ex.: Cabeçalho, Rodapé, CTA...\",\n save: \"Salvar Bloco\",\n saving: \"Salvando...\",\n cancel: \"Cancelar\",\n empty: \"Nenhum bloco salvo ainda\",\n emptyHint: \"Salve blocos dos seus templates para reutilizá-los depois.\",\n noResults: \"Nenhum bloco salvo corresponde à sua busca\",\n search: \"Buscar blocos salvos...\",\n loading: \"Carregando blocos salvos…\",\n category: \"Categoria\",\n categoryPlaceholder: \"ex.: Cabeçalhos, Promoções... (opcional)\",\n allCategories: \"Todas as categorias\",\n filterByCategory: \"Filtrar por categoria\",\n insert: \"Inserir\",\n rename: \"Renomear\",\n delete: \"Excluir\",\n deleteConfirm: \"Excluir este bloco salvo?\",\n blockCount: \"{count} bloco(s)\",\n browse: \"Explorar Blocos Salvos\",\n selectToPreview: \"Selecione um bloco salvo para visualizar\",\n insertAtBeginning: \"No início\",\n insertAfterBlock: \"Após {block}\",\n insertAtEnd: \"No final\",\n insertPosition: \"Posição de inserção\",\n close: \"Fechar\",\n pickToolbar: \"Seleção de bloco salvo\",\n pickCount: \"{count} bloco(s) selecionado(s)\",\n pickHint: \"Clique nos blocos para adicionar ou remover\",\n savingCount: \"Salvando {count} bloco(s):\",\n reorderHint: \"Arraste para reordenar — os blocos são salvos nesta ordem\",\n reorderHandle: \"Reordenar {block}, posição {position} de {total}\",\n reorderAnnouncement: \"{block} movido para a posição {position} de {total}\",\n expand: \"Expandir\",\n collapse: \"Recolher\",\n expandPreview: \"Expandir a prévia de {block}\",\n collapsePreview: \"Recolher a prévia de {block}\",\n },\n comments: {\n button: \"Comentários\",\n title: \"Comentários\",\n placeholder: \"Escreva um comentário...\",\n replyPlaceholder: \"Escreva uma resposta...\",\n reply: \"Responder\",\n resolve: \"Resolver\",\n unresolve: \"Reabrir\",\n delete: \"Excluir\",\n edit: \"Editar\",\n cancel: \"Cancelar\",\n save: \"Salvar\",\n noComments: \"Nenhum comentário ainda\",\n noCommentsHint:\n \"Inicie uma conversa adicionando um comentário ao template ou a um bloco específico.\",\n deleteConfirm: \"Excluir este comentário?\",\n filterAll: \"Todos\",\n filterUnresolved: \"Não resolvidos\",\n filterBlock: \"Este bloco\",\n jumpToBlock: \"Bloco\",\n ownedByYou: \"Você\",\n edited: \"editado\",\n resolvedBy: \"Resolvido por {name}\",\n replyOne: \"{count} Resposta\",\n replyMany: \"{count} Respostas\",\n missingBlock: \"Bloco ausente\",\n saveTemplateFirst: \"Salve o template antes de comentar neste bloco.\",\n },\n versionHistory: {\n tooltip: \"Histórico de versões\",\n dropdownTitle: \"Histórico de versões\",\n empty: \"Nenhuma versão ainda\",\n auto: \"auto\",\n olderVersion: \"Versão anterior\",\n newerVersion: \"Versão mais recente\",\n },\n versionPreview: {\n message: \"Você está visualizando uma versão anterior deste modelo.\",\n cancel: \"Cancelar\",\n restore: \"Restaurar esta versão\",\n restoreConfirm: {\n title: \"Restaurar esta versão?\",\n unsavedWithSave:\n \"Você tem alterações não salvas. Salve-as primeiro e elas ficarão no seu histórico — restaure sem salvar e elas serão perdidas.\",\n unsavedNoSave:\n \"Você tem alterações não salvas e nenhum lugar para salvá-las. Restaurar esta versão vai descartá-las.\",\n saveAndRestore: \"Salvar e restaurar\",\n restoreAnyway: \"Restaurar mesmo assim\",\n cancel: \"Cancelar\",\n },\n },\n previewResolution: {\n resolving: \"Resolvendo a pré-visualização…\",\n failed:\n \"Não foi possível resolver a pré-visualização — exibindo o modelo não resolvido.\",\n hint: \"A pré-visualização usa dados resolvidos pelo seu backend.\",\n },\n mergeTagPreview: {\n label: \"Exibição de merge tags\",\n sample: \"Exemplo\",\n labelView: \"Rótulo\",\n },\n testEmail: {\n title: \"Enviar E-mail de Teste\",\n recipientLabel: \"Destinatário\",\n recipientPlaceholder: \"voce@exemplo.com\",\n invalidAddress: \"Informe um endereço de e-mail válido.\",\n preview: \"Pré-visualização\",\n previewHint:\n \"As merge tags aparecem sem resolução — seu backend as preenche.\",\n previewHintSample:\n \"As merge tags mostram valores de exemplo — seu backend insere os dados reais.\",\n recipientNotAllowed:\n \"Esse endereço não está na lista de destinatários permitidos.\",\n send: \"Enviar\",\n sending: \"Enviando...\",\n cancel: \"Cancelar\",\n success: \"E-mail de teste enviado com sucesso\",\n button: \"Testar\",\n },\n sidebarNav: {\n browseSavedBlocks: \"Explorar blocos salvos\",\n palette: \"Paleta de blocos\",\n insertBlock: \"Inserir bloco {block}\",\n },\n\n // Landmark region labels for assistive technology\n landmarks: {\n canvas: \"Tela do e-mail\",\n blockToolbar: \"Propriedades do bloco\",\n rightSidebar: \"Propriedades do bloco e configurações do template\",\n reorderAnnouncements: \"Anúncios de reordenação de blocos\",\n },\n\n // Design Reference (cloud)\n errors: {\n editorLoading: \"Carregando editor...\",\n editorLoadFailed: \"Falha ao carregar o editor.\",\n retry: \"Tentar novamente\",\n },\n\n issues: {\n panelTitle: \"Problemas\",\n panelTabLabel: \"Problemas\",\n groupErrors: \"Erros\",\n groupWarnings: \"Avisos\",\n groupInfo: \"Informações\",\n jump: \"Ir para o bloco\",\n fix: \"Corrigir\",\n emptyState: \"Nenhum problema — tudo certo.\",\n badgeError: \"Possui erros\",\n badgeWarning: \"Possui avisos\",\n issueCountTooltip: \"{count} problema(s)\",\n },\n\n smallScreen: {\n title: \"Tela maior necessária\",\n message:\n \"O editor precisa de mais espaço do que esta tela oferece. Abra-o em um tablet ou desktop para começar a editar.\",\n },\n};\n\nexport default ptBR;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"src-B_QJduQD.js","names":[],"sources":["../../../../types/src/blocks.ts","../../../../types/src/social.ts","../../../../types/src/guards.ts","../../../../types/src/defaults.ts","../../../../types/src/template.ts","../../../../types/src/factory.ts","../../../../types/src/clone.ts","../../../../types/src/html-scan.ts","../../../../types/src/merge-tags.ts","../../../../types/src/preview-resolution.ts","../../../../types/src/config.ts"],"sourcesContent":["export interface SpacingValue {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\nexport interface BlockStyles {\n padding: SpacingValue;\n backgroundColor?: string;\n}\n\nexport interface BlockVisibility {\n desktop: boolean;\n mobile: boolean;\n}\n\nexport interface BaseBlock {\n id: string;\n type: string;\n styles: BlockStyles;\n visibility?: BlockVisibility;\n displayCondition?: {\n label: string;\n before: string;\n after: string;\n group?: string;\n description?: string;\n };\n}\n\nexport type ColumnLayout = \"1\" | \"2\" | \"3\" | \"2-1\" | \"1-2\";\n\n/**\n * Optional outer frame for a section. When present, the section is rendered\n * inside an `mj-wrapper` — a full-width band (its own background + padding)\n * that frames the section, e.g. a white card sitting on a colored band.\n */\nexport interface SectionWrapper {\n backgroundColor?: string;\n padding?: SpacingValue;\n /** Corner radius in px for the outer frame. Omitted/0 = square corners. */\n borderRadius?: number;\n}\n\nexport interface SectionBlock extends BaseBlock {\n type: \"section\";\n columns: ColumnLayout;\n children: Block[][];\n /**\n * Whether columns stack vertically on mobile. Absent or `true` keeps MJML's\n * default responsive behavior (columns stack below 480px). `false` renders\n * the columns inside an `<mj-group>` so they stay side-by-side on mobile,\n * proportionally shrunk to fit.\n */\n stackOnMobile?: boolean;\n /** Corner radius in px. Omitted/0 = square corners. */\n borderRadius?: number;\n /** Optional outer frame (rendered as an `mj-wrapper` around the section). */\n wrapper?: SectionWrapper;\n}\n\nexport type HeadingLevel = 1 | 2 | 3 | 4;\n\nexport const HEADING_LEVEL_FONT_SIZE: Record<HeadingLevel, number> = {\n 1: 36,\n 2: 28,\n 3: 22,\n 4: 18,\n};\n\nexport interface TitleBlock extends BaseBlock {\n type: \"title\";\n content: string;\n level: HeadingLevel;\n /** Text color. Unset = inherit the document-level `textColor`. */\n color?: string;\n textAlign: \"left\" | \"center\" | \"right\";\n fontFamily?: string;\n}\n\nexport interface ParagraphBlock extends BaseBlock {\n type: \"paragraph\";\n content: string;\n}\n\nexport interface ImageBlock extends BaseBlock {\n type: \"image\";\n src: string;\n alt: string;\n width: number | \"full\";\n /**\n * Height in pixels. Absent means the height is derived from the width, so the\n * image keeps its aspect ratio — setting both stretches it, since email\n * clients don't support `object-fit`.\n */\n height?: number;\n align: \"left\" | \"center\" | \"right\";\n linkUrl?: string;\n linkOpenInNewTab?: boolean;\n placeholderUrl?: string;\n decorative?: boolean;\n}\n\nexport interface ButtonBlock extends BaseBlock {\n type: \"button\";\n text: string;\n url: string;\n openInNewTab?: boolean;\n backgroundColor: string;\n textColor: string;\n borderRadius: number;\n fontSize: number;\n buttonPadding: SpacingValue;\n fontFamily?: string;\n width?: number | \"full\";\n /**\n * Placement of the button within its column. No visible effect when `width`\n * is `\"full\"`, since the button then spans the column.\n */\n align: \"left\" | \"center\" | \"right\";\n}\n\nexport interface DividerBlock extends BaseBlock {\n type: \"divider\";\n lineStyle: \"solid\" | \"dashed\" | \"dotted\";\n color: string;\n thickness: number;\n width: number | \"full\";\n}\n\nexport interface VideoBlock extends BaseBlock {\n type: \"video\";\n url: string;\n openInNewTab?: boolean;\n thumbnailUrl: string;\n alt: string;\n width: number | \"full\";\n /**\n * Height in pixels for the thumbnail. Absent means the height is derived from\n * the width, so the thumbnail keeps its aspect ratio — setting both stretches\n * it, since email clients don't support `object-fit`.\n */\n height?: number;\n align: \"left\" | \"center\" | \"right\";\n placeholderUrl?: string;\n}\n\nexport type SocialPlatform =\n | \"facebook\"\n | \"twitter\"\n | \"instagram\"\n | \"linkedin\"\n | \"youtube\"\n | \"tiktok\"\n | \"pinterest\"\n | \"email\"\n | \"whatsapp\"\n | \"telegram\"\n | \"discord\"\n | \"snapchat\"\n | \"reddit\"\n | \"github\"\n | \"dribbble\"\n | \"behance\"\n | \"website\";\n\nexport type SocialIconStyle =\n \"solid\" | \"outlined\" | \"rounded\" | \"square\" | \"circle\";\n\nexport type SocialIconSize = \"small\" | \"medium\" | \"large\";\n\nexport interface SocialIcon {\n id: string;\n platform: SocialPlatform;\n url: string;\n}\n\nexport interface SocialIconsBlock extends BaseBlock {\n type: \"social\";\n icons: SocialIcon[];\n iconStyle: SocialIconStyle;\n iconSize: SocialIconSize;\n spacing: number;\n align: \"left\" | \"center\" | \"right\";\n}\n\nexport interface SpacerBlock extends BaseBlock {\n type: \"spacer\";\n height: number;\n}\n\nexport interface HtmlBlock extends BaseBlock {\n type: \"html\";\n content: string;\n}\n\nexport interface MenuItemData {\n id: string;\n text: string;\n url: string;\n openInNewTab: boolean;\n bold: boolean;\n underline: boolean;\n color?: string;\n}\n\nexport interface MenuBlock extends BaseBlock {\n type: \"menu\";\n items: MenuItemData[];\n fontSize: number;\n fontFamily?: string;\n /** Base text/link color. Unset = inherit the document-level `textColor`. */\n color?: string;\n linkColor?: string;\n textAlign: \"left\" | \"center\" | \"right\";\n separator: string;\n separatorColor: string;\n spacing: number;\n}\n\nexport interface TableCellData {\n id: string;\n content: string;\n}\n\nexport interface TableRowData {\n id: string;\n cells: TableCellData[];\n}\n\nexport interface TableBlock extends BaseBlock {\n type: \"table\";\n rows: TableRowData[];\n hasHeaderRow: boolean;\n headerBackgroundColor?: string;\n borderColor: string;\n borderWidth: number;\n cellPadding: number;\n fontSize: number;\n fontFamily?: string;\n /** Text color. Unset = inherit the document-level `textColor`. */\n color?: string;\n textAlign: \"left\" | \"center\" | \"right\";\n}\n\nexport interface CountdownBlock extends BaseBlock {\n type: \"countdown\";\n targetDate: string;\n timezone: string;\n showDays: boolean;\n showHours: boolean;\n showMinutes: boolean;\n showSeconds: boolean;\n separator: \":\" | \"-\" | \" \";\n digitFontSize: number;\n digitColor: string;\n labelColor: string;\n labelFontSize: number;\n backgroundColor: string;\n fontFamily?: string;\n labelDays: string;\n labelHours: string;\n labelMinutes: string;\n labelSeconds: string;\n expiredMessage: string;\n expiredImageUrl: string;\n hideOnExpiry: boolean;\n}\n\nexport interface CustomBlock extends BaseBlock {\n type: \"custom\";\n customType: string;\n fieldValues: Record<string, unknown>;\n renderedHtml?: string;\n dataSourceFetched?: boolean;\n}\n\nexport type Block =\n | SectionBlock\n | TitleBlock\n | ParagraphBlock\n | ImageBlock\n | ButtonBlock\n | DividerBlock\n | VideoBlock\n | SocialIconsBlock\n | SpacerBlock\n | HtmlBlock\n | MenuBlock\n | TableBlock\n | CountdownBlock\n | CustomBlock;\n\nexport type BlockType = Block[\"type\"];\n","import type { SocialPlatform } from \"./blocks\";\n\n/**\n * SVG glyph (24×24 path) + brand color for each social platform.\n *\n * Single source of truth shared by two consumers that render icons in\n * different formats: the editor draws them as inline SVG (`SocialIconSvg.vue`)\n * and `@templatical/renderer` rasterizes them to PNGs\n * (`scripts/rasterize-social.mjs`) because Outlook's Word engine has no SVG\n * support. Typing as `Record<SocialPlatform, ...>` makes adding a platform to\n * the union a compile error until its glyph is supplied here, keeping both\n * consumers in lockstep.\n */\nexport interface SocialIconGlyph {\n /** SVG path data on a 24×24 viewBox. */\n path: string;\n /** Brand color as a 6-digit hex string. */\n color: string;\n}\n\nexport const SOCIAL_ICON_GLYPHS: Record<SocialPlatform, SocialIconGlyph> = {\n facebook: {\n color: \"#1877F2\",\n path: \"M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z\",\n },\n twitter: {\n color: \"#000000\",\n path: \"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\",\n },\n instagram: {\n color: \"#E4405F\",\n path: \"M12 0C8.74 0 8.333.015 7.053.072 5.775.132 4.905.333 4.14.63c-.789.306-1.459.717-2.126 1.384S.935 3.35.63 4.14C.333 4.905.131 5.775.072 7.053.012 8.333 0 8.74 0 12s.015 3.667.072 4.947c.06 1.277.261 2.148.558 2.913.306.788.717 1.459 1.384 2.126.667.666 1.336 1.079 2.126 1.384.766.296 1.636.499 2.913.558C8.333 23.988 8.74 24 12 24s3.667-.015 4.947-.072c1.277-.06 2.148-.262 2.913-.558.788-.306 1.459-.718 2.126-1.384.666-.667 1.079-1.335 1.384-2.126.296-.765.499-1.636.558-2.913.06-1.28.072-1.687.072-4.947s-.015-3.667-.072-4.947c-.06-1.277-.262-2.149-.558-2.913-.306-.789-.718-1.459-1.384-2.126C21.319 1.347 20.651.935 19.86.63c-.765-.297-1.636-.499-2.913-.558C15.667.012 15.26 0 12 0zm0 2.16c3.203 0 3.585.016 4.85.071 1.17.055 1.805.249 2.227.415.562.217.96.477 1.382.896.419.42.679.819.896 1.381.164.422.36 1.057.413 2.227.057 1.266.07 1.646.07 4.85s-.015 3.585-.074 4.85c-.061 1.17-.256 1.805-.421 2.227-.224.562-.479.96-.899 1.382-.419.419-.824.679-1.38.896-.42.164-1.065.36-2.235.413-1.274.057-1.649.07-4.859.07-3.211 0-3.586-.015-4.859-.074-1.171-.061-1.816-.256-2.236-.421-.569-.224-.96-.479-1.379-.899-.421-.419-.69-.824-.9-1.38-.165-.42-.359-1.065-.42-2.235-.045-1.26-.061-1.649-.061-4.844 0-3.196.016-3.586.061-4.861.061-1.17.255-1.814.42-2.234.21-.57.479-.96.9-1.381.419-.419.81-.689 1.379-.898.42-.166 1.051-.361 2.221-.421 1.275-.045 1.65-.06 4.859-.06l.045.03zm0 3.678c-3.405 0-6.162 2.76-6.162 6.162 0 3.405 2.76 6.162 6.162 6.162 3.405 0 6.162-2.76 6.162-6.162 0-3.405-2.76-6.162-6.162-6.162zM12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4zm7.846-10.405c0 .795-.646 1.44-1.44 1.44-.795 0-1.44-.646-1.44-1.44 0-.794.646-1.439 1.44-1.439.793-.001 1.44.645 1.44 1.439z\",\n },\n linkedin: {\n color: \"#0A66C2\",\n path: \"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\",\n },\n youtube: {\n color: \"#FF0000\",\n path: \"M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z\",\n },\n tiktok: {\n color: \"#000000\",\n path: \"M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z\",\n },\n pinterest: {\n color: \"#BD081C\",\n path: \"M12 0C5.373 0 0 5.372 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738.098.119.112.224.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z\",\n },\n email: {\n color: \"#6B7280\",\n path: \"M1.5 8.67v8.58a3 3 0 003 3h15a3 3 0 003-3V8.67l-8.928 5.493a3 3 0 01-3.144 0L1.5 8.67z M22.5 6.908V6.75a3 3 0 00-3-3h-15a3 3 0 00-3 3v.158l9.714 5.978a1.5 1.5 0 001.572 0L22.5 6.908z\",\n },\n website: {\n color: \"#6B7280\",\n path: \"M21.721 12.752a9.711 9.711 0 0 0-.945-5.003 12.754 12.754 0 0 1-4.339 2.708 18.991 18.991 0 0 1-.214 4.772 17.165 17.165 0 0 0 5.498-2.477ZM14.634 15.55a17.324 17.324 0 0 0 .332-4.647c-.952.227-1.945.347-2.966.347-1.021 0-2.014-.12-2.966-.347a17.515 17.515 0 0 0 .332 4.647 17.385 17.385 0 0 0 5.268 0ZM9.772 17.119a18.963 18.963 0 0 0 4.456 0A17.182 17.182 0 0 1 12 21.724a17.18 17.18 0 0 1-2.228-4.605ZM7.777 15.23a18.87 18.87 0 0 1-.214-4.774 12.753 12.753 0 0 1-4.34-2.708 9.711 9.711 0 0 0-.944 5.004 17.165 17.165 0 0 0 5.498 2.477ZM21.356 14.752a9.765 9.765 0 0 1-7.478 6.817 18.64 18.64 0 0 0 1.988-4.718 18.627 18.627 0 0 0 5.49-2.098ZM2.644 14.752c1.682.971 3.53 1.688 5.49 2.099a18.64 18.64 0 0 0 1.988 4.718 9.765 9.765 0 0 1-7.478-6.816ZM13.878 2.43a9.755 9.755 0 0 1 6.116 3.986 11.267 11.267 0 0 1-3.746 2.504 18.63 18.63 0 0 0-2.37-6.49ZM12 2.276a17.152 17.152 0 0 1 2.805 7.121c-.897.23-1.837.353-2.805.353-.968 0-1.908-.122-2.805-.353A17.151 17.151 0 0 1 12 2.276ZM10.122 2.43a18.629 18.629 0 0 0-2.37 6.49 11.266 11.266 0 0 1-3.746-2.504 9.754 9.754 0 0 1 6.116-3.985Z\",\n },\n whatsapp: {\n color: \"#25D366\",\n path: \"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z\",\n },\n telegram: {\n color: \"#26A5E4\",\n path: \"M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z\",\n },\n discord: {\n color: \"#5865F2\",\n path: \"M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189z\",\n },\n snapchat: {\n color: \"#FFFC00\",\n path: \"M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.162-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738a.36.36 0 01.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146 1.124.347 2.317.535 3.554.535 6.627 0 12.017-5.373 12.017-12.001C24.034 5.367 18.644 0 12.017 0z\",\n },\n reddit: {\n color: \"#FF4500\",\n path: \"M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.701zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73-.828 0-1.979-.196-2.512-.73a.326.326 0 0 0-.232-.095z\",\n },\n github: {\n color: \"#181717\",\n path: \"M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\",\n },\n dribbble: {\n color: \"#EA4C89\",\n path: \"M12 24C5.385 24 0 18.615 0 12S5.385 0 12 0s12 5.385 12 12-5.385 12-12 12zm10.12-10.358c-.35-.11-3.17-.953-6.384-.438 1.34 3.684 1.887 6.684 1.992 7.308 2.3-1.555 3.936-4.02 4.392-6.87zm-6.115 7.808c-.153-.9-.75-4.032-2.19-7.77l-.066.02c-5.79 2.015-7.86 6.025-8.04 6.4 1.73 1.358 3.92 2.166 6.29 2.166 1.42 0 2.77-.29 4-.814zm-11.62-2.58c.232-.4 3.045-5.055 8.332-6.765.135-.045.27-.084.405-.12-.26-.585-.54-1.167-.832-1.74C7.17 11.775 2.206 11.71 1.756 11.7l-.004.312c0 2.633.998 5.037 2.634 6.855zm-2.42-8.955c.46.008 4.683.026 9.477-1.248-1.698-3.018-3.53-5.558-3.8-5.928-2.868 1.35-5.01 3.99-5.676 7.17zM9.6 2.052c.282.38 2.145 2.914 3.822 6 3.645-1.365 5.19-3.44 5.373-3.702-1.81-1.61-4.19-2.586-6.795-2.586-.825 0-1.63.1-2.4.285zm10.335 3.483c-.218.29-1.935 2.493-5.724 4.04.24.49.47.985.68 1.486.08.18.15.36.22.53 3.41-.43 6.8.26 7.14.33-.02-2.42-.88-4.64-2.31-6.38z\",\n },\n behance: {\n color: \"#1769FF\",\n path: \"M22 7h-7V5h7v2zm1.726 10c-.442 1.297-2.029 3-5.101 3-3.074 0-5.564-1.729-5.564-5.675 0-3.91 2.325-5.92 5.466-5.92 3.082 0 4.964 1.782 5.375 4.426.078.506.109 1.188.095 2.14H15.97c.13 3.211 3.483 3.312 4.588 2.029h3.168zm-7.686-4h4.965c-.105-1.547-1.136-2.219-2.477-2.219-1.466 0-2.277.768-2.488 2.219zm-9.574 6.988H0V5.021h6.953c5.476.081 5.58 5.444 2.72 6.906 3.461 1.26 3.577 8.061-3.207 8.061zM3 11h3.584c2.508 0 2.906-3-.312-3H3v3zm3.391 3H3v3.016h3.341c3.055 0 2.868-3.016.05-3.016z\",\n },\n};\n","import type {\n Block,\n ButtonBlock,\n CountdownBlock,\n CustomBlock,\n DividerBlock,\n HtmlBlock,\n ImageBlock,\n MenuBlock,\n ParagraphBlock,\n SectionBlock,\n SocialIconsBlock,\n SpacerBlock,\n TableBlock,\n TitleBlock,\n VideoBlock,\n} from \"./blocks\";\n\nexport function isSection(block: Block): block is SectionBlock {\n return block.type === \"section\";\n}\n\nexport function isTitle(block: Block): block is TitleBlock {\n return block.type === \"title\";\n}\n\nexport function isParagraph(block: Block): block is ParagraphBlock {\n return block.type === \"paragraph\";\n}\n\nexport function isImage(block: Block): block is ImageBlock {\n return block.type === \"image\";\n}\n\nexport function isButton(block: Block): block is ButtonBlock {\n return block.type === \"button\";\n}\n\nexport function isDivider(block: Block): block is DividerBlock {\n return block.type === \"divider\";\n}\n\nexport function isVideo(block: Block): block is VideoBlock {\n return block.type === \"video\";\n}\n\nexport function isSocialIcons(block: Block): block is SocialIconsBlock {\n return block.type === \"social\";\n}\n\nexport function isSpacer(block: Block): block is SpacerBlock {\n return block.type === \"spacer\";\n}\n\nexport function isHtml(block: Block): block is HtmlBlock {\n return block.type === \"html\";\n}\n\nexport function isMenu(block: Block): block is MenuBlock {\n return block.type === \"menu\";\n}\n\nexport function isTable(block: Block): block is TableBlock {\n return block.type === \"table\";\n}\n\nexport function isCountdown(block: Block): block is CountdownBlock {\n return block.type === \"countdown\";\n}\n\nexport function isCustomBlock(block: Block): block is CustomBlock {\n return block.type === \"custom\";\n}\n","import type {\n ButtonBlock,\n CountdownBlock,\n DividerBlock,\n HtmlBlock,\n ImageBlock,\n MenuBlock,\n ParagraphBlock,\n SectionBlock,\n SocialIconsBlock,\n SpacerBlock,\n TableBlock,\n TitleBlock,\n VideoBlock,\n} from \"./blocks\";\nimport type { TemplateSettings } from \"./template\";\n\ntype BlockDefaultsFor<T> = Partial<Omit<T, \"id\" | \"type\">>;\n\nexport interface BlockDefaults {\n title?: BlockDefaultsFor<TitleBlock>;\n paragraph?: BlockDefaultsFor<ParagraphBlock>;\n image?: BlockDefaultsFor<ImageBlock>;\n button?: BlockDefaultsFor<ButtonBlock>;\n divider?: BlockDefaultsFor<DividerBlock>;\n section?: BlockDefaultsFor<SectionBlock>;\n video?: BlockDefaultsFor<VideoBlock>;\n social?: BlockDefaultsFor<SocialIconsBlock>;\n spacer?: BlockDefaultsFor<SpacerBlock>;\n html?: BlockDefaultsFor<HtmlBlock>;\n menu?: BlockDefaultsFor<MenuBlock>;\n table?: BlockDefaultsFor<TableBlock>;\n countdown?: BlockDefaultsFor<CountdownBlock>;\n}\n\nexport type TemplateDefaults = Partial<TemplateSettings>;\n\n// ---------------------------------------------------------------------------\n// Built-in default values — single source of truth for factories & consumers\n// ---------------------------------------------------------------------------\n\n// `color` is intentionally omitted: a new Title inherits the document\n// `textColor` (see `TemplateSettings`) unless the user sets a per-block color.\nexport const TITLE_BLOCK_DEFAULTS: BlockDefaultsFor<TitleBlock> = {\n content: \"<p>Enter your title</p>\",\n level: 2,\n textAlign: \"left\",\n};\n\nexport const PARAGRAPH_BLOCK_DEFAULTS: BlockDefaultsFor<ParagraphBlock> = {\n content: \"<p>Enter your text here</p>\",\n};\n\nexport const IMAGE_BLOCK_DEFAULTS: BlockDefaultsFor<ImageBlock> = {\n src: \"\",\n alt: \"\",\n width: \"full\",\n align: \"center\",\n};\n\nexport const BUTTON_BLOCK_DEFAULTS: BlockDefaultsFor<ButtonBlock> = {\n text: \"Click Here\",\n url: \"\",\n backgroundColor: \"#333333\",\n textColor: \"#ffffff\",\n borderRadius: 6,\n fontSize: 15,\n buttonPadding: { top: 12, right: 24, bottom: 12, left: 24 },\n align: \"center\",\n};\n\nexport const DIVIDER_BLOCK_DEFAULTS: BlockDefaultsFor<DividerBlock> = {\n lineStyle: \"solid\",\n color: \"#e0e0e0\",\n thickness: 1,\n width: \"full\",\n};\n\nexport const SECTION_BLOCK_DEFAULTS: BlockDefaultsFor<SectionBlock> = {\n columns: \"1\",\n};\n\nexport const VIDEO_BLOCK_DEFAULTS: BlockDefaultsFor<VideoBlock> = {\n url: \"\",\n thumbnailUrl: \"\",\n alt: \"Video\",\n width: \"full\",\n align: \"center\",\n};\n\nexport const SOCIAL_ICONS_BLOCK_DEFAULTS: BlockDefaultsFor<SocialIconsBlock> = {\n iconStyle: \"solid\",\n iconSize: \"medium\",\n spacing: 10,\n align: \"center\",\n};\n\nexport const SPACER_BLOCK_DEFAULTS: BlockDefaultsFor<SpacerBlock> = {\n height: 24,\n};\n\nexport const HTML_BLOCK_DEFAULTS: BlockDefaultsFor<HtmlBlock> = {\n content: \"\",\n};\n\n// `color` is intentionally omitted: a new Menu inherits the document\n// `textColor` unless the user sets a per-block color (or per-item `linkColor`).\nexport const MENU_BLOCK_DEFAULTS: BlockDefaultsFor<MenuBlock> = {\n fontSize: 15,\n textAlign: \"center\",\n separator: \"|\",\n separatorColor: \"#e0e0e0\",\n spacing: 10,\n};\n\n// `color` is intentionally omitted: a new Table inherits the document\n// `textColor` unless the user sets a per-block color.\nexport const TABLE_BLOCK_DEFAULTS: BlockDefaultsFor<TableBlock> = {\n hasHeaderRow: true,\n borderColor: \"#e0e0e0\",\n borderWidth: 1,\n cellPadding: 8,\n fontSize: 15,\n textAlign: \"left\",\n};\n\nexport const COUNTDOWN_BLOCK_DEFAULTS: BlockDefaultsFor<CountdownBlock> = {\n targetDate: \"\",\n timezone: \"UTC\",\n showDays: true,\n showHours: true,\n showMinutes: true,\n showSeconds: true,\n separator: \":\",\n digitFontSize: 32,\n digitColor: \"#1a1a1a\",\n labelColor: \"#6b7280\",\n labelFontSize: 12,\n backgroundColor: \"#ffffff\",\n labelDays: \"Days\",\n labelHours: \"Hours\",\n labelMinutes: \"Minutes\",\n labelSeconds: \"Seconds\",\n expiredMessage: \"This offer has expired\",\n expiredImageUrl: \"\",\n hideOnExpiry: false,\n};\n\nexport const DEFAULT_BLOCK_DEFAULTS: Required<BlockDefaults> = {\n title: TITLE_BLOCK_DEFAULTS,\n paragraph: PARAGRAPH_BLOCK_DEFAULTS,\n image: IMAGE_BLOCK_DEFAULTS,\n button: BUTTON_BLOCK_DEFAULTS,\n divider: DIVIDER_BLOCK_DEFAULTS,\n section: SECTION_BLOCK_DEFAULTS,\n video: VIDEO_BLOCK_DEFAULTS,\n social: SOCIAL_ICONS_BLOCK_DEFAULTS,\n spacer: SPACER_BLOCK_DEFAULTS,\n html: HTML_BLOCK_DEFAULTS,\n menu: MENU_BLOCK_DEFAULTS,\n table: TABLE_BLOCK_DEFAULTS,\n countdown: COUNTDOWN_BLOCK_DEFAULTS,\n};\n\nexport const DEFAULT_TEMPLATE_DEFAULTS: TemplateDefaults = {\n width: 600,\n backgroundColor: \"#ffffff\",\n textColor: \"#1a1a1a\",\n linkUnderline: true,\n fontFamily: \"Arial\",\n locale: \"en\",\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.getPrototypeOf(value) === Object.prototype\n );\n}\n\nexport function deepMergeDefaults<T extends object>(\n base: T,\n overrides: Partial<T>,\n): T {\n const result = { ...base };\n\n for (const key of Object.keys(overrides) as Array<keyof T>) {\n const baseVal = base[key];\n const overrideVal = overrides[key];\n\n if (overrideVal === undefined) {\n continue;\n }\n\n if (isPlainObject(baseVal) && isPlainObject(overrideVal)) {\n result[key] = deepMergeDefaults(\n baseVal,\n overrideVal as Partial<typeof baseVal>,\n ) as T[keyof T];\n } else {\n result[key] = overrideVal as T[keyof T];\n }\n }\n\n return result;\n}\n","import type { Block } from \"./blocks\";\nimport { DEFAULT_TEMPLATE_DEFAULTS } from \"./defaults\";\nimport type { TemplateDefaults } from \"./defaults\";\n\nexport interface TemplateSettings {\n width: number;\n backgroundColor: string;\n /**\n * Document-level default text color: the `<mj-text>` default in the rendered\n * MJML, inherited by every text block (Title, Paragraph, Menu, Table) that\n * doesn't set its own `color`. Required, defaulting to `#1a1a1a` (see\n * `DEFAULT_TEMPLATE_DEFAULTS`); customize the default per-consumer via\n * `templateDefaults`. A block's explicit `color` or an inline text-color\n * mark overrides it.\n */\n textColor: string;\n /**\n * Document-level link color: emitted as the global `a { color }` rule in the\n * rendered MJML, so it cascades to every link — rich-text and menu alike.\n * Optional: when unset, links inherit the surrounding text color\n * (`color: inherit`), preserving the pre-#352 default. A per-block or\n * per-item color (a Menu item's `color`, `MenuBlock.linkColor`) still\n * overrides it.\n */\n linkColor?: string;\n /**\n * Whether links are underlined document-wide: drives the global\n * `a { text-decoration }` rule (`underline` when true, `none` when false).\n * Required, defaulting to `true` (see `DEFAULT_TEMPLATE_DEFAULTS`) — the\n * common, more accessible email default. Applies to body (rich-text) links;\n * buttons and menu items carry their own inline `text-decoration` and are\n * unaffected. Set `false` to render links without an underline.\n */\n linkUnderline: boolean;\n fontFamily: string;\n preheaderText?: string;\n /**\n * BCP-47 language code for the rendered email's `<html lang>`. Drives\n * screen-reader pronunciation. Default `'en'` via `DEFAULT_TEMPLATE_DEFAULTS`.\n */\n locale: string;\n}\n\nexport interface TemplateContent {\n blocks: Block[];\n settings: TemplateSettings;\n}\n\nexport function createDefaultTemplateContent(\n defaultFontFamily = \"Arial\",\n templateDefaults?: TemplateDefaults,\n): TemplateContent {\n return {\n blocks: [],\n settings: {\n ...DEFAULT_TEMPLATE_DEFAULTS,\n fontFamily: defaultFontFamily,\n ...templateDefaults,\n } as TemplateSettings,\n };\n}\n","import type {\n Block,\n BlockStyles,\n BlockType,\n ButtonBlock,\n CountdownBlock,\n CustomBlock,\n DividerBlock,\n HtmlBlock,\n ImageBlock,\n MenuBlock,\n ParagraphBlock,\n SectionBlock,\n SocialIconsBlock,\n SpacerBlock,\n SpacingValue,\n TableBlock,\n TableCellData,\n TableRowData,\n TitleBlock,\n VideoBlock,\n} from \"./blocks\";\nimport type { CustomBlockDefinition, CustomBlockField } from \"./custom-blocks\";\nimport type { BlockDefaults } from \"./defaults\";\nimport {\n BUTTON_BLOCK_DEFAULTS,\n COUNTDOWN_BLOCK_DEFAULTS,\n deepMergeDefaults,\n DIVIDER_BLOCK_DEFAULTS,\n HTML_BLOCK_DEFAULTS,\n IMAGE_BLOCK_DEFAULTS,\n MENU_BLOCK_DEFAULTS,\n PARAGRAPH_BLOCK_DEFAULTS,\n SECTION_BLOCK_DEFAULTS,\n SOCIAL_ICONS_BLOCK_DEFAULTS,\n SPACER_BLOCK_DEFAULTS,\n TABLE_BLOCK_DEFAULTS,\n TITLE_BLOCK_DEFAULTS,\n VIDEO_BLOCK_DEFAULTS,\n} from \"./defaults\";\n\nfunction applyDefaults<T extends object>(\n base: T,\n partial: Partial<T> | undefined,\n): T {\n if (!partial || Object.keys(partial).length === 0) return base;\n return deepMergeDefaults(base, partial);\n}\n\nexport function generateId(): string {\n return crypto.randomUUID();\n}\n\nfunction createDefaultSpacing(value = 0): SpacingValue {\n return { top: value, right: value, bottom: value, left: value };\n}\n\nfunction createDefaultStyles(padding = 10): BlockStyles {\n return {\n padding: createDefaultSpacing(padding),\n };\n}\n\nexport function createTitleBlock(\n partial: Partial<TitleBlock> = {},\n): TitleBlock {\n const base: TitleBlock = {\n id: generateId(),\n type: \"title\",\n ...TITLE_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as TitleBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createParagraphBlock(\n partial: Partial<ParagraphBlock> = {},\n): ParagraphBlock {\n const base: ParagraphBlock = {\n id: generateId(),\n type: \"paragraph\",\n ...PARAGRAPH_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as ParagraphBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createImageBlock(\n partial: Partial<ImageBlock> = {},\n): ImageBlock {\n const base: ImageBlock = {\n id: generateId(),\n type: \"image\",\n ...IMAGE_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as ImageBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createButtonBlock(\n partial: Partial<ButtonBlock> = {},\n): ButtonBlock {\n const base: ButtonBlock = {\n id: generateId(),\n type: \"button\",\n ...BUTTON_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as ButtonBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createDividerBlock(\n partial: Partial<DividerBlock> = {},\n): DividerBlock {\n const base: DividerBlock = {\n id: generateId(),\n type: \"divider\",\n ...DIVIDER_BLOCK_DEFAULTS,\n styles: createDefaultStyles(20),\n } as DividerBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createSectionBlock(\n partial: Partial<SectionBlock> = {},\n): SectionBlock {\n const base: SectionBlock = {\n id: generateId(),\n type: \"section\",\n ...SECTION_BLOCK_DEFAULTS,\n children: [[]],\n styles: createDefaultStyles(20),\n } as SectionBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createVideoBlock(\n partial: Partial<VideoBlock> = {},\n): VideoBlock {\n const base: VideoBlock = {\n id: generateId(),\n type: \"video\",\n ...VIDEO_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as VideoBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createSocialIconsBlock(\n partial: Partial<SocialIconsBlock> = {},\n): SocialIconsBlock {\n const base: SocialIconsBlock = {\n id: generateId(),\n type: \"social\",\n icons: [],\n ...SOCIAL_ICONS_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as SocialIconsBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createSpacerBlock(\n partial: Partial<SpacerBlock> = {},\n): SpacerBlock {\n const base: SpacerBlock = {\n id: generateId(),\n type: \"spacer\",\n ...SPACER_BLOCK_DEFAULTS,\n styles: createDefaultStyles(0),\n } as SpacerBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createHtmlBlock(partial: Partial<HtmlBlock> = {}): HtmlBlock {\n const base: HtmlBlock = {\n id: generateId(),\n type: \"html\",\n ...HTML_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as HtmlBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createMenuBlock(partial: Partial<MenuBlock> = {}): MenuBlock {\n const base: MenuBlock = {\n id: generateId(),\n type: \"menu\",\n items: [],\n ...MENU_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as MenuBlock;\n return applyDefaults(base, partial);\n}\n\nfunction createDefaultTableRows(columns: number, rows: number): TableRowData[] {\n return Array.from({ length: rows }, () => ({\n id: generateId(),\n cells: Array.from({ length: columns }, (): TableCellData => ({\n id: generateId(),\n content: \"\",\n })),\n }));\n}\n\nexport function createTableBlock(\n partial: Partial<TableBlock> = {},\n): TableBlock {\n const base: TableBlock = {\n id: generateId(),\n type: \"table\",\n rows: createDefaultTableRows(3, 3),\n ...TABLE_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as TableBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createCountdownBlock(\n partial: Partial<CountdownBlock> = {},\n): CountdownBlock {\n const base: CountdownBlock = {\n id: generateId(),\n type: \"countdown\",\n ...COUNTDOWN_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as CountdownBlock;\n return applyDefaults(base, partial);\n}\n\nfunction getFieldDefault(field: CustomBlockField): unknown {\n if (field.type === \"repeatable\") {\n return field.default ?? [];\n }\n if (field.type === \"boolean\") {\n return field.default ?? false;\n }\n if (field.type === \"number\") {\n return field.default ?? 0;\n }\n\n return field.default ?? \"\";\n}\n\nexport function createCustomBlock(\n definition: CustomBlockDefinition,\n): CustomBlock {\n const fieldValues: Record<string, unknown> = {};\n\n for (const field of definition.fields) {\n fieldValues[field.key] = getFieldDefault(field);\n }\n\n const styles = applyDefaults(createDefaultStyles(), definition.defaultStyles);\n\n return {\n id: generateId(),\n type: \"custom\",\n customType: definition.type,\n fieldValues,\n styles,\n ...(definition.dataSource ? { dataSourceFetched: false } : {}),\n };\n}\n\nexport function createBlock(\n type: BlockType,\n blockDefaults?: BlockDefaults,\n): Block {\n switch (type) {\n case \"section\":\n return createSectionBlock(blockDefaults?.section);\n case \"title\":\n return createTitleBlock(blockDefaults?.title);\n case \"paragraph\":\n return createParagraphBlock(blockDefaults?.paragraph);\n case \"image\":\n return createImageBlock(blockDefaults?.image);\n case \"button\":\n return createButtonBlock(blockDefaults?.button);\n case \"divider\":\n return createDividerBlock(blockDefaults?.divider);\n case \"video\":\n return createVideoBlock(blockDefaults?.video);\n case \"social\":\n return createSocialIconsBlock(blockDefaults?.social);\n case \"spacer\":\n return createSpacerBlock(blockDefaults?.spacer);\n case \"html\":\n return createHtmlBlock(blockDefaults?.html);\n case \"menu\":\n return createMenuBlock(blockDefaults?.menu);\n case \"table\":\n return createTableBlock(blockDefaults?.table);\n case \"countdown\":\n return createCountdownBlock(blockDefaults?.countdown);\n default:\n throw new Error(`Unknown block type: ${type}`);\n }\n}\n\nexport function cloneBlock(block: Block): Block {\n const cloned = JSON.parse(JSON.stringify(block)) as Block;\n cloned.id = generateId();\n\n if (cloned.type === \"section\") {\n cloned.children = cloned.children.map((column) =>\n column.map((child) => cloneBlock(child)),\n );\n }\n\n return cloned;\n}\n","/**\n * Cycle-safe deep clone via a JSON round-trip.\n *\n * A naked `JSON.stringify` throws `Converting circular structure to JSON`\n * if the tree is self-referencing — e.g. a DOM element carrying a Sortable\n * expando back-ref (`HTMLDivElement.SortableXXX -> instance -> el -> div`)\n * leaks into block data through a drag handler inside a section. Both the\n * editor's public `getContent()` export path and the history snapshot path\n * must tolerate that: we drop the offending back-ref from the clone rather\n * than throw. Losing a transient DOM expando is harmless; the block data is\n * intact.\n *\n * The `WeakSet` replacer omits any object already seen on the current path,\n * which covers every cyclic shape. Template content is tree-shaped (and is\n * serialized to JSON for storage anyway), so dropping repeated references\n * never costs real data.\n */\nexport function safeClone<T>(value: T): T {\n const seen = new WeakSet<object>();\n return JSON.parse(\n JSON.stringify(value, (_key, val) => {\n if (typeof val === \"object\" && val !== null) {\n if (seen.has(val)) return undefined;\n seen.add(val);\n }\n return val;\n }),\n ) as T;\n}\n","/**\n * Minimal, allocation-free primitives for reading an HTML open tag out of a\n * markup string. They exist because merge-tag markup is rewritten from a raw\n * string in two packages — `@templatical/types` (label / sample resolution for\n * the previews) and `@templatical/renderer` (converting spans back to tokens on\n * export) — and both need the same two answers: where does this open tag end,\n * and what is the value of one of its attributes.\n *\n * Both are hand-written character scans rather than regexes. A regex over an\n * attribute string with no closing quote backtracks across the whole input,\n * which is the ReDoS class the span scanners were rewritten to avoid; a scan\n * that only moves forward cannot.\n */\n\nconst QUOTES = new Set(['\"', \"'\"]);\n\n/**\n * Index of the `>` that closes the open tag whose name ends at `from`, or `-1`\n * when the tag never closes.\n *\n * Quote-aware: a `>` inside a quoted attribute value does not end the tag.\n * That matters because a consumer may configure a merge-tag syntax whose tag\n * values contain `<` / `>` — Smarty-style `<% $email %>` — and HTML attribute\n * serialization escapes only `&`, `\"` and U+00A0, so those characters reach the\n * markup literally. A plain `indexOf(\">\")` stops mid-attribute there and every\n * caller downstream sees a truncated attribute string.\n *\n * An unterminated quote yields `-1` rather than a guessed tag end: callers\n * treat that as \"not markup I can rewrite\" and emit the input untouched, which\n * is the safe answer for malformed HTML.\n */\nexport function findOpenTagEnd(html: string, from: number): number {\n let quote: string | null = null;\n for (let i = from; i < html.length; i++) {\n const char = html[i];\n if (quote !== null) {\n if (char === quote) quote = null;\n continue;\n }\n if (QUOTES.has(char)) {\n quote = char;\n continue;\n }\n if (char === \">\") return i;\n }\n return -1;\n}\n\nfunction isAttrNameChar(char: string): boolean {\n return (\n char !== \" \" &&\n char !== \"\\t\" &&\n char !== \"\\n\" &&\n char !== \"\\r\" &&\n char !== \"\\f\" &&\n char !== \"=\" &&\n char !== \">\" &&\n char !== \"/\"\n );\n}\n\nfunction isWhitespace(char: string): boolean {\n return (\n char === \" \" ||\n char === \"\\t\" ||\n char === \"\\n\" ||\n char === \"\\r\" ||\n char === \"\\f\"\n );\n}\n\nconst NAMED_ENTITIES: Record<string, string> = {\n amp: \"&\",\n lt: \"<\",\n gt: \">\",\n quot: '\"',\n apos: \"'\",\n nbsp: \" \",\n};\n\n/**\n * Decode the character references an HTML serializer writes into an attribute\n * value, so callers get the characters the author wrote.\n *\n * Deliberately small: the named set a serializer actually emits, plus numeric\n * references. An unknown or malformed reference is left as literal text, which\n * is what a browser does. Single-pass — `&amp;lt;` decodes to the text `&lt;`\n * and stops, never to `<`, so an escaped entity inside a consumer's tag value\n * survives as itself.\n */\nfunction decodeAttrEntities(value: string): string {\n if (!value.includes(\"&\")) return value;\n return value.replace(\n /&(#[0-9]+|#[xX][0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g,\n (match, ref: string) => {\n if (ref[0] === \"#\") {\n const code =\n ref[1] === \"x\" || ref[1] === \"X\"\n ? Number.parseInt(ref.slice(2), 16)\n : Number.parseInt(ref.slice(1), 10);\n // Surrogates and out-of-range code points would throw; leave them be.\n if (!Number.isFinite(code) || code < 1 || code > 0x10ffff) return match;\n if (code >= 0xd800 && code <= 0xdfff) return match;\n return String.fromCodePoint(code);\n }\n return NAMED_ENTITIES[ref.toLowerCase()] ?? match;\n },\n );\n}\n\n/**\n * The value of the `name` attribute within an open tag's attribute string (the\n * text between the tag name and its closing `>`), or `null` when the attribute\n * is absent or its quoted value is never closed.\n *\n * Handles double-quoted, single-quoted and unquoted values, and matches the\n * attribute name case-insensitively, as HTML does. The value is\n * entity-decoded, because that is what the attribute means: the editor\n * serializes a tag value of `<% $email %>` as\n * `data-merge-tag=\"&lt;% $email %&gt;\"`, and every caller compares the result\n * against a configured merge-tag token written in raw characters.\n */\nexport function getTagAttrValue(attrs: string, name: string): string | null {\n const target = name.toLowerCase();\n let i = 0;\n\n while (i < attrs.length) {\n while (i < attrs.length && (isWhitespace(attrs[i]) || attrs[i] === \"/\")) {\n i++;\n }\n if (i >= attrs.length) break;\n\n const nameStart = i;\n while (i < attrs.length && isAttrNameChar(attrs[i])) i++;\n const attrName = attrs.substring(nameStart, i).toLowerCase();\n if (attrName === \"\") {\n // Not a name character and not whitespace — e.g. a stray `=`. Step over\n // it so the scan always advances.\n i++;\n continue;\n }\n\n while (i < attrs.length && isWhitespace(attrs[i])) i++;\n if (attrs[i] !== \"=\") {\n // A boolean attribute (`hidden`); the cursor already sits on the next\n // attribute name, so don't consume anything here.\n continue;\n }\n i++; // past `=`\n while (i < attrs.length && isWhitespace(attrs[i])) i++;\n\n const quote = attrs[i];\n if (QUOTES.has(quote)) {\n const valueStart = i + 1;\n const valueEnd = attrs.indexOf(quote, valueStart);\n if (valueEnd === -1) return null; // unterminated value — nothing readable follows\n if (attrName === target)\n return decodeAttrEntities(attrs.substring(valueStart, valueEnd));\n i = valueEnd + 1;\n continue;\n }\n\n const valueStart = i;\n while (i < attrs.length && !isWhitespace(attrs[i]) && attrs[i] !== \">\") i++;\n if (attrName === target)\n return decodeAttrEntities(attrs.substring(valueStart, i));\n }\n\n return null;\n}\n","import type { MergeTag } from \"./config\";\nimport { findOpenTagEnd, getTagAttrValue } from \"./html-scan\";\n\n// --- Syntax Presets ---\n\nexport interface SyntaxPreset {\n value: RegExp;\n logic: RegExp;\n}\n\nexport type SyntaxPresetName =\n \"liquid\" | \"handlebars\" | \"mailchimp\" | \"ampscript\";\n\nexport const SYNTAX_PRESETS: Record<SyntaxPresetName, SyntaxPreset> = {\n liquid: { value: /\\{\\{.+?\\}\\}/g, logic: /\\{%-?\\s*(\\w+).*?-?%\\}/g },\n handlebars: {\n value: /\\{\\{\\{?.+?\\}?\\}\\}/g,\n logic: /\\{\\{[#/](\\w+).*?\\}\\}/g,\n },\n mailchimp: { value: /\\*\\|\\w+\\|\\*/g, logic: /\\*\\|(\\w+)[:|].*?\\|\\*/g },\n ampscript: { value: /%%=.+?=%%/g, logic: /%%\\[\\s*(\\w+).*?\\]%%/g },\n};\n\nconst SYNTAX_TRIGGER_CHARS: Record<SyntaxPresetName, string> = {\n liquid: \"{{\",\n handlebars: \"{{\",\n mailchimp: \"*|\",\n ampscript: \"%%=\",\n};\n\nconst SYNTAX_CLOSING_CHARS: Record<SyntaxPresetName, string> = {\n liquid: \"}}\",\n handlebars: \"}}\",\n mailchimp: \"|*\",\n ampscript: \"=%%\",\n};\n\n/**\n * Resolves the autocomplete trigger string for a syntax preset.\n * Returns null when the syntax doesn't match any built-in preset\n * (custom regex syntax — autocomplete cannot be enabled safely).\n */\nexport function getSyntaxTriggerChar(syntax: SyntaxPreset): string | null {\n for (const name of Object.keys(SYNTAX_PRESETS) as SyntaxPresetName[]) {\n if (SYNTAX_PRESETS[name].value.source === syntax.value.source) {\n return SYNTAX_TRIGGER_CHARS[name];\n }\n }\n return null;\n}\n\n/**\n * Resolves the closing delimiter for a syntax preset (e.g. `}}` for liquid,\n * `|*` for mailchimp). The autocomplete trigger detector uses it to tell an\n * open tag (`{{first`) from a completed one (`{{first_name}}`) so the popup\n * doesn't reappear over a finished tag. Returns null for custom syntaxes —\n * the same set for which `getSyntaxTriggerChar` returns null.\n */\nexport function getSyntaxClosingChar(syntax: SyntaxPreset): string | null {\n for (const name of Object.keys(SYNTAX_PRESETS) as SyntaxPresetName[]) {\n if (SYNTAX_PRESETS[name].value.source === syntax.value.source) {\n return SYNTAX_CLOSING_CHARS[name];\n }\n }\n return null;\n}\n\nexport function resolveSyntax(\n syntax?: SyntaxPresetName | SyntaxPreset,\n): SyntaxPreset {\n if (!syntax) {\n return SYNTAX_PRESETS.liquid;\n }\n\n if (typeof syntax === \"string\") {\n return SYNTAX_PRESETS[syntax] ?? SYNTAX_PRESETS.liquid;\n }\n\n return syntax;\n}\n\n// --- Merge Tag Utilities ---\n\nfunction anchoredRegex(pattern: RegExp): RegExp {\n const source = pattern.source;\n const flags = pattern.flags.replace(\"g\", \"\");\n return new RegExp(`^${source}$`, flags);\n}\n\nexport function isMergeTagValue(value: string, syntax: SyntaxPreset): boolean {\n const trimmed = value?.trim() || \"\";\n // Handlebars (and similar) value regex is liberal enough to also match\n // logic tags like `{{#each items}}`. Exclude logic-shaped tags so callers\n // that rely on this discriminator (UI segmentation, label rendering)\n // don't misclassify them.\n if (anchoredRegex(syntax.logic).test(trimmed)) {\n return false;\n }\n return anchoredRegex(syntax.value).test(trimmed);\n}\n\nexport function getMergeTagLabel(value: string, mergeTags: MergeTag[]): string {\n const found = mergeTags.find((p) => p.value === value);\n if (found) {\n return found.label;\n }\n return value;\n}\n\nexport function resolveHtmlMergeTagLabels(\n html: string,\n mergeTags: MergeTag[],\n): string {\n return rewriteSpanByAttr(html, \"data-merge-tag\", (value) =>\n getMergeTagLabel(value, mergeTags),\n );\n}\n\n/**\n * The example value configured for `value`, or `undefined` when the tag is\n * unknown or declares none. Unlike `getMergeTagLabel`, which falls back to the\n * raw token, absence is reported as `undefined` so callers can choose their own\n * fallback — Sample mode falls back to the label, never to a raw token.\n */\nexport function getMergeTagSample(\n value: string,\n mergeTags: MergeTag[],\n): string | undefined {\n return mergeTags.find((p) => p.value === value)?.sample;\n}\n\n/**\n * Rewrite rich-text HTML for the previews' Sample mode.\n *\n * A tag **with** a sample is replaced by that value as bare text, wrapper and\n * all — dropping the `<span>` is what removes the merge-tag highlight, so the\n * value reads as ordinary content. A tag **without** one keeps its span and\n * shows its label, so it stays visibly dynamic; that difference is deliberate,\n * and it doubles as a signal that a sample is still unset.\n *\n * The unwrapped output is inert — `data-merge-tag` is gone from it — so this\n * result must only ever reach a preview surface, never `getContent()`, an\n * export or a send.\n */\nexport function substituteHtmlMergeTagSamples(\n html: string,\n mergeTags: MergeTag[],\n): string {\n return rewriteSpanByAttr(\n html,\n \"data-merge-tag\",\n (value) =>\n escapeTagText(\n getMergeTagSample(value, mergeTags) ??\n getMergeTagLabel(value, mergeTags),\n ),\n { unwrap: (value) => getMergeTagSample(value, mergeTags) !== undefined },\n );\n}\n\n/**\n * Whether any configured tag declares a `sample`.\n *\n * Gates the whole feature: with no samples anywhere the previews' Sample view\n * would be identical to the Label view, so the editor defaults to Label and\n * renders no toggle. That keeps the feature invisible until a consumer opts in.\n */\nexport function hasMergeTagSamples(mergeTags: MergeTag[]): boolean {\n return mergeTags.some((tag) => tag.sample !== undefined);\n}\n\n/**\n * Replace declared tokens with their sample values in a plain string — used for\n * values that reach no label-resolving component, namely `html` block content\n * and custom-block field values.\n *\n * Matching is on the exact configured `value`, so consumer text cannot\n * false-positive and `href=\"{{link}}\"` resolves correctly. Tags without a\n * sample are left untouched, which is what keeps a missing sample visible.\n */\nexport function substituteTextMergeTagSamples(\n text: string,\n mergeTags: MergeTag[],\n): string {\n if (!text) return text;\n\n let out = text;\n for (const tag of mergeTags) {\n if (tag.sample === undefined) continue;\n // split/join rather than a RegExp: the token is a literal, so this needs no\n // escaping of regex metacharacters (`{`, `|`, `*` all appear in real syntaxes).\n out = out.split(tag.value).join(tag.sample);\n }\n return out;\n}\n\n/**\n * Escape a sample before it is inlined into rich-text HTML. Samples are\n * consumer-authored strings, so `<`, `&` and quotes would otherwise alter the\n * surrounding markup.\n */\nfunction escapeTagText(text: string): string {\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\nexport function containsMergeTag(value: string, syntax: SyntaxPreset): boolean {\n if (!value) return false;\n\n const valueRegex = new RegExp(syntax.value.source, syntax.value.flags);\n const logicRegex = new RegExp(syntax.logic.source, syntax.logic.flags);\n\n return valueRegex.test(value) || logicRegex.test(value);\n}\n\nexport function isLogicMergeTagValue(\n value: string,\n syntax: SyntaxPreset,\n): boolean {\n return anchoredRegex(syntax.logic).test(value?.trim() || \"\");\n}\n\nexport function getLogicMergeTagKeyword(\n value: string,\n syntax: SyntaxPreset,\n): string {\n const regex = new RegExp(\n syntax.logic.source,\n syntax.logic.flags.replace(\"g\", \"\"),\n );\n const match = value.match(regex);\n return match && match[1] ? match[1].toUpperCase() : value;\n}\n\nexport function resolveHtmlLogicMergeTagLabels(\n html: string,\n syntax: SyntaxPreset,\n): string {\n return rewriteSpanByAttr(html, \"data-logic-merge-tag\", (value) =>\n getLogicMergeTagKeyword(value, syntax),\n );\n}\n\n/**\n * Walk `html` and rewrite the inner text of every `<span … {attrName}=\"…\">…</span>`\n * by passing the attribute value through `relabel`. Linear in `html.length`:\n * each `indexOf` advances the cursor monotonically, and no regex backtracking\n * can run over the whole string.\n *\n * Replaces the original `/<span[^>]*…[^>]*>(.*?)<\\/span>/g` pattern, which\n * was polynomial-ReDoS over inputs that contained many `<span` starts with\n * no closing `>`.\n *\n * Tag boundaries and attribute values are resolved by `findOpenTagEnd` /\n * `getTagAttrValue`, which are quote-aware. A merge-tag value may itself\n * contain `<` / `>` when the consumer configures a custom syntax — Smarty-style\n * `<% $email %>` — and those characters survive attribute serialization\n * verbatim, so anything that treats the first `>` as the tag end reads a\n * truncated attribute and resolves nothing.\n */\nfunction rewriteSpanByAttr(\n html: string,\n attrName: string,\n relabel: (value: string) => string,\n options?: { unwrap?: (value: string) => boolean },\n): string {\n let out = \"\";\n let i = 0;\n while (i < html.length) {\n const open = html.indexOf(\"<span\", i);\n if (open === -1) {\n out += html.substring(i);\n break;\n }\n const afterTagName = html[open + 5];\n if (\n afterTagName !== \">\" &&\n afterTagName !== \" \" &&\n afterTagName !== \"\\t\" &&\n afterTagName !== \"\\n\" &&\n afterTagName !== \"\\r\" &&\n afterTagName !== \"/\"\n ) {\n out += html.substring(i, open + 5);\n i = open + 5;\n continue;\n }\n const openEnd = findOpenTagEnd(html, open + 5);\n if (openEnd === -1) {\n out += html.substring(i);\n break;\n }\n const closeStart = html.indexOf(\"</span>\", openEnd + 1);\n if (closeStart === -1) {\n out += html.substring(i);\n break;\n }\n const attrs = html.substring(open + 5, openEnd);\n const value = getTagAttrValue(attrs, attrName);\n if (value === null) {\n // This `<span>` isn't the one we're looking for — emit up to and\n // including the `<span` literal and let the next iteration scan\n // inward. Skipping straight to the matching `</span>` would swallow\n // any nested merge-tag span in the same loop iteration.\n out += html.substring(i, open + 5);\n i = open + 5;\n continue;\n }\n const newLabel = relabel(value);\n if (options?.unwrap?.(value)) {\n // Emit the text before the span, then the replacement alone — the open\n // and close tags are dropped, so the span's styling (the merge-tag\n // highlight) no longer applies to it. Decided per tag, so a tag that\n // resolved to a sample loses the highlight while one that fell back to\n // its label keeps it.\n out += html.substring(i, open);\n out += newLabel;\n } else {\n out += html.substring(i, openEnd + 1);\n out += newLabel;\n out += \"</span>\";\n }\n i = closeStart + 7;\n }\n return out;\n}\n","import type { TemplateContent } from \"./template\";\n\n/**\n * Context handed to `resolvePreview`.\n *\n * `recipient` is present only on surfaces that have one — the test-email\n * dialog — and absent in the editor's own preview mode. Treat its absence as\n * \"no particular recipient\", not as an error: a resolver should still return\n * something renderable, typically its own default or sample data.\n */\nexport interface PreviewResolveContext {\n /**\n * The template as it currently stands. Already a copy — mutating it has no\n * effect on the editor, and returning it unchanged is a valid no-op.\n */\n content: TemplateContent;\n /** The address the preview is being shown for, when the surface has one. */\n recipient?: string;\n}\n\n/**\n * Resolves a template for display on preview surfaces — typically substituting\n * merge tags and **evaluating logic tags** against real data.\n *\n * Logic tags are the reason this hook exists. `MergeTag.sample` already covers\n * value tags client-side, but branching (`{% if %}` … `{% endif %}`) cannot be\n * evaluated in a browser for every supported syntax — mailchimp and ampscript\n * logic are server-side dialects — so only the consumer's own backend can do it.\n *\n * Display-only. The returned content reaches preview surfaces and nothing else:\n * it is never written to the editor's state, never returned from\n * `getContent()`, never sent, and never exported. Rejecting is safe — the\n * preview falls back to the unresolved template and says so.\n */\nexport type ResolvePreview = (\n context: PreviewResolveContext,\n) => Promise<TemplateContent>;\n\n/**\n * Whether `value` is shaped enough like `TemplateContent` to render.\n *\n * A resolver is consumer code returning data that often came from an HTTP\n * response, so the declared return type guarantees nothing at runtime. A\n * mis-shaped result is treated as a resolution failure — the preview degrades\n * to the unresolved template — rather than throwing inside the render.\n */\nexport function isRenderableTemplateContent(\n value: unknown,\n): value is TemplateContent {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { blocks?: unknown };\n return Array.isArray(candidate.blocks);\n}\n","import type { SyntaxPreset, SyntaxPresetName } from \"./merge-tags\";\n\nexport type ViewportSize = \"desktop\" | \"mobile\";\n\nexport type UiTheme = \"light\" | \"dark\" | \"auto\";\n\nexport interface CustomFont {\n name: string;\n url: string;\n fallback?: string;\n}\n\nexport interface FontsConfig {\n defaultFallback?: string;\n defaultFont?: string;\n customFonts?: CustomFont[];\n /**\n * Restrict which of the seven built-in fonts the font picker offers.\n *\n * - `true` / omitted — every built-in is offered (the default).\n * - `false` — no built-ins; the picker lists only `customFonts`. Use this to\n * keep authors on an embedded brand kit's typefaces.\n * - `string[]` — an allowlist of built-in names to keep, matched\n * case-insensitively (`['Georgia', 'arial']`). A name that isn't a built-in\n * is logged with a warning and skipped — consistent with how\n * `paletteBlocks` treats an unknown entry — so a typo narrows the list\n * rather than silently offering all seven.\n *\n * Independent of `customFonts`: excluding the built-ins never removes a custom\n * font, and a custom font can still be the `defaultFont` when every built-in\n * is excluded. Filtering the picker never affects rendering — content already\n * using an excluded built-in still resolves to its proper fallback stack.\n */\n builtIns?: boolean | string[];\n}\n\nexport interface ColorsConfig {\n /**\n * Preset colors rendered as a clickable grid inside every color picker\n * popover. Each entry is a hex string (`'#0b5cff'`); clicking one applies it,\n * and the preset matching the current value is marked selected (matched\n * case-insensitively). The grid supplements the wheel and hex input unless\n * `allowCustom` is `false`.\n */\n presets?: string[];\n /**\n * Allow free-form color entry — the wheel and hex input — alongside the\n * presets. Defaults to `true`.\n *\n * Set to `false` together with `presets` to lock authors to the preset\n * palette: the popover then offers only the preset grid, with no wheel or hex\n * field (a white-label / brand-kit constraint). Ignored with a warning when\n * no `presets` are configured — hiding the only inputs would leave the picker\n * with no way to choose a color.\n */\n allowCustom?: boolean;\n}\n\nexport interface ExportResult {\n html: string;\n mjml: string;\n}\n\nexport interface MergeTag {\n label: string;\n value: string;\n /**\n * Optional grouping label used by the built-in merge tag picker to\n * section the list. When no tag in the configured array carries\n * `group`, the picker renders a plain flat list with no headers.\n * Ignored by the renderer and by typing-autocomplete.\n */\n group?: string;\n /**\n * Optional helper text shown beneath the tag in the built-in merge\n * tag picker. Not rendered anywhere else (toolbar, autocomplete,\n * MJML output) and not stored on the inserted document node.\n */\n description?: string;\n /**\n * Example value shown in place of this tag on preview surfaces — e.g.\n * `\"Ada\"` for `{{first_name}}` — so a preview reads like a delivered\n * email instead of a list of field names.\n *\n * Display-only, and only in the previews' Sample mode: never written to\n * the template, never sent, never present in MJML output. Setting it is\n * the whole opt-in; there is no accompanying flag. A tag without a\n * sample keeps showing its `label`.\n */\n sample?: string;\n}\n\nexport interface MediaResult {\n url: string;\n alt?: string;\n}\n\nexport interface MergeTagsConfig {\n syntax?: SyntaxPresetName | SyntaxPreset;\n tags?: MergeTag[];\n onRequest?: () => Promise<MergeTag | null>;\n /**\n * Enables typing-based autocomplete in rich text blocks and in every\n * merge-tag-enabled input/textarea field (toolbars, template settings,\n * custom-block text fields). When the user types the syntax opener\n * (e.g. `{{`), a popup lists matching `tags`. Both surfaces share the\n * same popup, so behavior is identical.\n *\n * Defaults to `true`. Effective only when `tags` is non-empty AND\n * `syntax` matches a built-in preset (custom regex syntaxes cannot be\n * mapped to a trigger string and silently disable autocomplete).\n */\n autocomplete?: boolean;\n}\n\n/**\n * A standalone logic tag — a control-flow token (e.g. `{% else %}`) inserted\n * at the cursor. Distinct from data merge tags; rendered as a keyword badge.\n */\nexport interface LogicTag {\n label: string;\n value: string;\n /** Optional grouping label used to section the logic picker. */\n group?: string;\n /** Optional helper text shown beneath the tag in the picker. */\n description?: string;\n}\n\n/**\n * A paired logic construct — an opening tag (`before`) and its matching closer\n * (`after`), e.g. `{% if vip %}` … `{% endif %}`. Selecting one inserts both\n * pills at once, wrapping the selection (or with the caret placed between\n * them). Shares its `before`/`after` shape with `DisplayCondition`.\n */\nexport interface LogicPair {\n label: string;\n /** Opening logic tag, including delimiters (e.g. `{% if vip %}`). */\n before: string;\n /** Closing logic tag, including delimiters (e.g. `{% endif %}`). */\n after: string;\n /** Optional grouping label used to section the logic picker. */\n group?: string;\n /** Optional helper text shown beneath the pair in the picker. */\n description?: string;\n}\n\n/**\n * Standalone logic-tag configuration, independent of `mergeTags`. `tags` are\n * single control-flow tokens inserted at the cursor; `pairs` are open/close\n * constructs inserted around the selection. Both appear in the built-in logic\n * picker, grouped together by `group`. Typed/pasted logic highlighting is\n * always on regardless of this.\n */\nexport interface LogicTagsConfig {\n tags?: LogicTag[];\n pairs?: LogicPair[];\n /**\n * Consumer-owned picker. When set, the \"Insert logic\" affordance calls this\n * instead of the built-in logic picker — return the chosen tag/pair (or\n * `null` to cancel). Mirrors `MergeTagsConfig.onRequest`; lets consumers use\n * their own UI and custom syntax. Precedence: `onRequest` → built-in picker.\n */\n onRequest?: () => Promise<LogicTag | LogicPair | null>;\n}\n\nexport interface DisplayCondition {\n label: string;\n before: string;\n after: string;\n group?: string;\n description?: string;\n}\n\nexport interface DisplayConditionsConfig {\n conditions: DisplayCondition[];\n allowCustom?: boolean;\n}\n\nexport interface ThemeOverrides {\n bg?: string;\n bgElevated?: string;\n bgHover?: string;\n bgActive?: string;\n border?: string;\n borderLight?: string;\n text?: string;\n textMuted?: string;\n textDim?: string;\n primary?: string;\n primaryHover?: string;\n primaryLight?: string;\n secondary?: string;\n secondaryHover?: string;\n secondaryLight?: string;\n success?: string;\n successLight?: string;\n warning?: string;\n warningLight?: string;\n danger?: string;\n dangerLight?: string;\n canvasBg?: string;\n dark?: Omit<ThemeOverrides, \"dark\">;\n}\n\nexport class SdkError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n ) {\n super(message);\n this.name = \"SdkError\";\n }\n\n get isNotFound(): boolean {\n return this.statusCode === 404;\n }\n\n get isUnauthorized(): boolean {\n return this.statusCode === 401;\n }\n\n get isServerError(): boolean {\n return this.statusCode !== undefined && this.statusCode >= 500;\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"src-CjSrA_o4.js","names":[],"sources":["../../../../renderer/package.json","../../../../renderer/src/render-context.ts","../../../../renderer/src/visibility.ts","../../../../renderer/src/unrenderable.ts","../../../../renderer/src/escape.ts","../../../../renderer/src/padding.ts","../../../../renderer/src/utils.ts","../../../../renderer/src/renderers/title.ts","../../../../renderer/src/renderers/paragraph.ts","../../../../renderer/src/renderers/image.ts","../../../../renderer/src/renderers/button.ts","../../../../renderer/src/renderers/divider.ts","../../../../renderer/src/renderers/spacer.ts","../../../../renderer/src/renderers/html.ts","../../../../renderer/src/renderers/social.ts","../../../../renderer/src/renderers/menu.ts","../../../../renderer/src/renderers/table.ts","../../../../renderer/src/renderers/custom.ts","../../../../renderer/src/columns.ts","../../../../renderer/src/display-condition.ts","../../../../renderer/src/renderers/section.ts","../../../../renderer/src/renderers/video.ts","../../../../renderer/src/renderers/index.ts","../../../../renderer/src/index.ts"],"sourcesContent":["{\n \"name\": \"@templatical/renderer\",\n \"description\": \"Render Templatical email templates to MJML\",\n \"version\": \"0.29.1\",\n \"bugs\": \"https://github.com/templatical/sdk/issues\",\n \"dependencies\": {\n \"@templatical/types\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@resvg/resvg-js\": \"^2.6.2\",\n \"mjml\": \"^5.4.0\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.11\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"assets\"\n ],\n \"homepage\": \"https://templatical.com\",\n \"keywords\": [\n \"email\",\n \"email-template\",\n \"html-email\",\n \"mjml\",\n \"renderer\",\n \"templatical\"\n ],\n \"license\": \"MIT\",\n \"module\": \"./dist/index.js\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/templatical/sdk.git\",\n \"directory\": \"packages/renderer\"\n },\n \"scripts\": {\n \"build\": \"tsdown && node scripts/rasterize-social.mjs\",\n \"test\": \"vitest run --config vitest.config.ts\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"type\": \"module\",\n \"types\": \"./dist/index.d.ts\"\n}\n","import type { Block, BlockType, CustomFont } from \"@templatical/types\";\nimport pkg from \"../package.json\" with { type: \"json\" };\n\n/**\n * A function type that renders a single block to MJML markup.\n */\nexport type BlockRenderer = (block: Block, context: RenderContext) => string;\n\n/**\n * Per-block-type renderer overrides, keyed by `block.type`. An entry replaces the\n * built-in renderer for that type wholesale — including its hidden-on-all-\n * viewports check, which becomes the override's responsibility.\n *\n * Generalises `renderCustomBlock`, which is the same idea for one block type. Its\n * reason to exist is that Templatical Cloud's render output is a deliberate\n * *superset*: countdown blocks resolve to a server-generated animated GIF and\n * video thumbnails get a composited play button, neither of which a browser can\n * do at render time. With this hook Cloud's renderer is the published one plus\n * two injected functions, so parity for every other block type holds by\n * construction instead of by review.\n */\nexport type BlockRendererMap = Partial<Record<BlockType, BlockRenderer>>;\n\nexport const DEFAULT_SOCIAL_ICONS_BASE_URL = `https://cdn.jsdelivr.net/npm/@templatical/renderer@${pkg.version}/assets/social`;\n\nconst BUILT_IN_FONT_FALLBACKS: Record<string, string> = {\n arial: \"Arial, sans-serif\",\n helvetica: \"Helvetica, sans-serif\",\n georgia: \"Georgia, serif\",\n \"times new roman\": \"'Times New Roman', serif\",\n verdana: \"Verdana, sans-serif\",\n \"trebuchet ms\": \"'Trebuchet MS', sans-serif\",\n \"courier new\": \"'Courier New', monospace\",\n tahoma: \"Tahoma, sans-serif\",\n};\n\n/**\n * Immutable context passed through the block rendering chain.\n */\nexport class RenderContext {\n constructor(\n public readonly containerWidth: number,\n public readonly customFonts: CustomFont[],\n public readonly defaultFallbackFont: string,\n public readonly allowHtmlBlocks: boolean,\n /**\n * Map of custom block id → pre-rendered HTML, populated by `renderToMjml`\n * before the synchronous render pass. Set when the consumer provides a\n * `renderCustomBlock` option. Empty by default.\n */\n public readonly customBlockHtml: ReadonlyMap<string, string> = new Map(),\n /**\n * Base URL (no trailing slash) for the social icon PNG assets. Resolved to\n * `${baseUrl}/${style}/${platform}.png`. Outlook desktop has no SVG support\n * and rejects base64 data URIs in `<img src>`, so PNGs must be served over\n * HTTP. Default points at the version-pinned jsDelivr mirror of this\n * package; consumers can override to self-host.\n */\n public readonly socialIconsBaseUrl: string = DEFAULT_SOCIAL_ICONS_BASE_URL,\n /**\n * Per-block-type renderer overrides from `RenderOptions.blockRenderers`.\n * Consulted before every built-in renderer — see {@link BlockRendererMap}.\n */\n public readonly blockRenderers: BlockRendererMap = {},\n ) {}\n\n /**\n * Create a new context with a different container width.\n * Used when rendering columns with narrower widths.\n */\n withContainerWidth(width: number): RenderContext {\n return new RenderContext(\n width,\n this.customFonts,\n this.defaultFallbackFont,\n this.allowHtmlBlocks,\n this.customBlockHtml,\n this.socialIconsBaseUrl,\n this.blockRenderers,\n );\n }\n\n /**\n * Resolve a font family name to include custom font fallbacks.\n * If the font matches a custom font, returns `'FontName', fallback`.\n * Otherwise returns the original font family string.\n */\n resolveFontFamily(fontFamily: string): string {\n // Check custom fonts first\n for (const customFont of this.customFonts) {\n if (customFont.name.toLowerCase() === fontFamily.toLowerCase()) {\n const fallback = customFont.fallback ?? this.defaultFallbackFont;\n\n return `'${customFont.name}', ${fallback}`;\n }\n }\n\n // Resolve built-in fonts to include fallback stacks\n const builtIn = BUILT_IN_FONT_FALLBACKS[fontFamily.toLowerCase()];\n if (builtIn) {\n return builtIn;\n }\n\n return fontFamily;\n }\n}\n","import type { Block } from \"@templatical/types\";\n\n/**\n * Check if a block is hidden on all viewports.\n */\nexport function isHiddenOnAll(block: Block): boolean {\n const visibility = block.visibility;\n\n if (!visibility) {\n return false;\n }\n\n return !visibility.desktop && !visibility.mobile;\n}\n\n/**\n * Get the MJML css-class attribute string for visibility hiding.\n * Returns a string like ` css-class=\"tpl-hide-desktop\"` or empty string.\n */\nexport function getCssClassAttr(block: Block): string {\n const classes = getCssClasses(block);\n\n if (classes === \"\") {\n return \"\";\n }\n\n return ` css-class=\"${classes}\"`;\n}\n\n/**\n * Get the CSS classes for visibility hiding.\n */\nexport function getCssClasses(block: Block): string {\n const visibility = block.visibility;\n\n if (!visibility) {\n return \"\";\n }\n\n const classes: string[] = [];\n\n if (!visibility.desktop) {\n classes.push(\"tpl-hide-desktop\");\n }\n\n if (!visibility.mobile) {\n classes.push(\"tpl-hide-mobile\");\n }\n\n return classes.join(\" \");\n}\n","import type { Block } from \"@templatical/types\";\n\n/**\n * Prefix every unrenderable-block marker carries. Stable and greppable on\n * purpose: it is what a consumer searches for after noticing a gap in a rendered\n * email, and what a send pipeline can scan for before shipping.\n */\nexport const UNRENDERABLE_MARKER_PREFIX = \"templatical:unrenderable-block\";\n\n/**\n * Strip anything that would terminate or nest an HTML comment. `-->` and `--!>`\n * inside the marker would close it early and leak the rest as body text; a lone\n * `--` is enough to make the comment non-conforming, so both collapse.\n *\n * Brackets go **before** hyphens collapse, and the order is load-bearing.\n * Removing `<` from `-<-` brings two hyphens together that a collapse pass has\n * already walked past, so collapsing first leaves a `--` behind — the sanitizer\n * reintroducing the sequence it exists to remove.\n */\nfunction commentSafe(value: string): string {\n return value.replace(/[<>]/g, \"\").replace(/-{2,}/g, \"-\");\n}\n\n/**\n * Emit the placeholder for a block no renderer can handle — no built-in renderer\n * and no `blockRenderers` override for its type.\n *\n * **A marker, not a throw and not silence.** The renderer runs inside send\n * pipelines, so killing an entire render over one block is worse than shipping a\n * marked gap. Silence is worse still: a block that simply vanishes reaches\n * recipients as a missing section with nothing anywhere explaining why. The rule\n * is general rather than countdown-specific, so\n * a block type added to `@templatical/types` before its renderer lands degrades\n * the same way.\n *\n * `mj-raw` is used because it is the one element that passes its content through\n * verbatim and is valid everywhere a block renders — inside `mj-column`, which is\n * where every non-section block ends up.\n */\nexport function renderUnrenderableBlock(block: Block): string {\n console.warn(\n `[Templatical] No renderer for block type \"${block.type}\" (id: ${block.id}). ` +\n \"A placeholder comment was emitted in its place. Pass a `blockRenderers` \" +\n \"entry for this type to render it.\",\n );\n\n const type = commentSafe(block.type);\n const id = commentSafe(block.id);\n\n return `<mj-raw><!-- ${UNRENDERABLE_MARKER_PREFIX} type=\"${type}\" id=\"${id}\" --></mj-raw>`;\n}\n","import { findOpenTagEnd, getTagAttrValue } from \"@templatical/types\";\n\nconst HTML_ENTITIES: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#039;\",\n};\n\nconst HTML_ENTITY_REGEX = /[&<>\"']/g;\n\n/**\n * Escape HTML special characters (& < > \" ').\n * Equivalent to PHP htmlspecialchars with ENT_QUOTES | ENT_HTML5.\n */\nexport function escapeHtml(text: string): string {\n if (text === \"\") {\n return \"\";\n }\n\n return text.replace(HTML_ENTITY_REGEX, (char) => HTML_ENTITIES[char] ?? char);\n}\n\n/**\n * Escape a string for use in an HTML attribute value.\n * Same implementation as escapeHtml for consistency with PHP.\n */\nexport function escapeAttr(text: string): string {\n if (text === \"\") {\n return \"\";\n }\n\n return text.replace(HTML_ENTITY_REGEX, (char) => HTML_ENTITIES[char] ?? char);\n}\n\n/**\n * Escape a string for use as a CSS property value inside an inline\n * `style=\"prop: ${value}\"` attribute. Beyond HTML entity escaping (so the\n * value survives the attribute boundary), this strips characters that\n * could break out of the property value into a sibling property:\n *\n * `;` — separates CSS declarations\n * `{`/`}` — opens/closes a CSS rule (rejected by attribute parsers but\n * still safer to remove)\n * `\\n`/`\\r` — would smuggle past line-based CSS sanitizers\n *\n * Without this, an attacker-controlled color like\n * `\"red; background: url('//attacker/log')\"` lands as a real CSS rule.\n */\nexport function escapeCssValue(text: string): string {\n if (text === \"\") {\n return \"\";\n }\n return escapeAttr(text).replace(/[;{}\\r\\n]/g, \"\");\n}\n\n/**\n * Replace merge tag span elements with their data attribute values.\n * Converts `<span data-merge-tag=\"{{name}}\">Label</span>` to `{{name}}`.\n * Also handles `data-logic-merge-tag` attributes.\n *\n * Uses a single-pass linear scan instead of an `[^>]*…[^>]*` regex because\n * the latter is polynomial-ReDoS over inputs that contain many `<span`\n * starts but no closing `>` — the engine retries `[^>]*` at every span\n * position. The scan below resolves each `<span>` open tag with a bounded,\n * quote-aware `findOpenTagEnd`, keeping the work strictly O(n).\n */\nexport function convertMergeTagsToValues(html: string): string {\n if (html === \"\") {\n return \"\";\n }\n\n return rewriteMergeTagSpans(\n html,\n (attrs) =>\n findAttr(attrs, \"data-merge-tag\") ??\n findAttr(attrs, \"data-logic-merge-tag\"),\n );\n}\n\n/**\n * Walk `html`, find every `<span …>…</span>`, and replace the entire span\n * with whatever `extract` returns for its attribute string (or leave it\n * alone if `extract` returns `null`). Linear in the length of `html`:\n * every `indexOf` advances the cursor monotonically.\n */\nfunction rewriteMergeTagSpans(\n html: string,\n extract: (attrs: string) => string | null,\n): string {\n let out = \"\";\n let i = 0;\n while (i < html.length) {\n const open = html.indexOf(\"<span\", i);\n if (open === -1) {\n out += html.substring(i);\n break;\n }\n // `<span` must be followed by `>` or whitespace to be a real opening tag.\n const afterTagName = html[open + 5];\n if (\n afterTagName !== \">\" &&\n afterTagName !== \" \" &&\n afterTagName !== \"\\t\" &&\n afterTagName !== \"\\n\" &&\n afterTagName !== \"\\r\" &&\n afterTagName !== \"/\"\n ) {\n out += html.substring(i, open + 5);\n i = open + 5;\n continue;\n }\n const openEnd = findOpenTagEnd(html, open + 5);\n if (openEnd === -1) {\n out += html.substring(i);\n break;\n }\n const closeStart = html.indexOf(\"</span>\", openEnd + 1);\n if (closeStart === -1) {\n out += html.substring(i);\n break;\n }\n const attrs = html.substring(open + 5, openEnd);\n const replacement = extract(attrs);\n if (replacement === null) {\n // This `<span>` isn't a merge-tag — emit up to and including the\n // `<span` literal and let the next iteration scan inward, so any\n // nested merge-tag span still gets a chance to match.\n out += html.substring(i, open + 5);\n i = open + 5;\n continue;\n }\n out += html.substring(i, open);\n out += replacement;\n i = closeStart + 7;\n }\n return out;\n}\n\n/**\n * Extract the value of `name=\"…\"` from an HTML attribute string, or `null`\n * if absent.\n *\n * Delegates to `@templatical/types` so the editor's preview rewriter and this\n * export rewriter read markup identically. They were separate regexes once, and\n * both excluded `<` / `>` from the value — which silently left the whole span\n * in the rendered MJML whenever a consumer configured a merge-tag syntax whose\n * values contain those characters (`<% $email %>`), so the ESP never received\n * the token.\n */\nfunction findAttr(attrs: string, name: string): string | null {\n return getTagAttrValue(attrs, name);\n}\n","import type { SpacingValue } from \"@templatical/types\";\n\n/**\n * Convert a SpacingValue to a CSS padding string like \"10px 10px 10px 10px\".\n */\nexport function toPaddingString(padding: SpacingValue): string {\n return `${padding.top}px ${padding.right}px ${padding.bottom}px ${padding.left}px`;\n}\n","/**\n * MJML attribute helpers — single source of truth for placement rules\n * that the MJML spec enforces but accepts silently when violated.\n *\n * MJML drops unrecognized attributes without error. The most common trap is\n * background placement: only `mj-section`, `mj-button`, `mj-wrapper`, `mj-hero`\n * accept the native `background-color` attribute. Inner content elements\n * (`mj-text`, `mj-image`, `mj-table`, `mj-navbar`, `mj-video`) require\n * `container-background-color`, which paints the enclosing `<td>`. Passing\n * `background-color` to an inner element results in the attribute being\n * silently dropped — the email ships without the bg.\n *\n * https://documentation.mjml.io/\n */\n\n/**\n * Where the MJML element accepts a background-color attribute.\n * - `native`: the element has its own `background-color` (mj-section, mj-button).\n * - `container`: the element only accepts `container-background-color`,\n * which colors the wrapping `<td>` (mj-text, mj-image, mj-table, mj-navbar, mj-video).\n */\nexport type BgPlacement = \"native\" | \"container\";\n\n/**\n * Render the appropriate background-color attribute for an MJML element.\n * Returns an empty string when no color is set, or a leading-space attribute\n * fragment ready to interpolate into a tag's attribute list.\n */\nexport function bgAttr(\n backgroundColor: string | undefined,\n placement: BgPlacement,\n): string {\n if (!backgroundColor) {\n return \"\";\n }\n\n const name =\n placement === \"native\" ? \"background-color\" : \"container-background-color\";\n\n return ` ${name}=\"${backgroundColor}\"`;\n}\n\n/**\n * Render `mj-image`'s height attribute. Returns an empty string when no height\n * is set, so MJML applies its own `auto` and the image keeps its aspect ratio.\n *\n * The px suffix is not cosmetic: `height` is a Unit attribute accepting only\n * `px` or `auto`, so a bare number is a validation error and MJML drops it.\n * Non-finite or non-positive values are treated as unset — a `0` here would\n * collapse the image rather than express \"no opinion\".\n */\nexport function heightAttr(height: number | undefined): string {\n if (typeof height !== \"number\" || !Number.isFinite(height) || height <= 0) {\n return \"\";\n }\n\n return ` height=\"${height}px\"`;\n}\n","import type { TitleBlock } from \"@templatical/types\";\nimport { HEADING_LEVEL_FONT_SIZE } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { convertMergeTagsToValues, escapeAttr } from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a title block to MJML markup.\n */\nexport function renderTitle(block: TitleBlock, context: RenderContext): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n const content = unwrapParagraph(convertMergeTagsToValues(block.content));\n // Clamp out-of-range levels to a defined entry so we never interpolate\n // `undefined` into `font-size=\"${...}px\"` (mjml@5 rejects \"undefinedpx\").\n const fontSize =\n HEADING_LEVEL_FONT_SIZE[block.level] ?? HEADING_LEVEL_FONT_SIZE[2];\n // Emit the color only when the block sets one; otherwise the `mj-text`\n // inherits the document `textColor` default from `<mj-attributes>`.\n const colorAttr = block.color ? `\\n color=\"${escapeAttr(block.color)}\"` : \"\";\n const align = block.textAlign;\n const fontFamilyAttr = renderFontFamilyAttr(block.fontFamily, context);\n const visibilityAttr = getCssClassAttr(block);\n // Same clamp logic as fontSize so that an out-of-range level still\n // produces a valid heading element.\n const safeLevel = HEADING_LEVEL_FONT_SIZE[block.level] ? block.level : 2;\n const tag = `h${safeLevel}`;\n\n return `<mj-text\n font-size=\"${fontSize}px\"${colorAttr}\n align=\"${align}\"\n line-height=\"1.3\"\n padding=\"${padding}\"${bgColor}${fontFamilyAttr}${visibilityAttr}\n><${tag} style=\"margin:0;font-size:inherit;color:inherit;line-height:inherit\">${content}</${tag}></mj-text>`;\n}\n\n/**\n * The editor stores title content as a TipTap paragraph (`<p>...</p>`),\n * but the renderer wraps it in `<h${level}>`. `<p>` is invalid inside a\n * heading, so strip a single outer `<p>` wrapper if present.\n */\nfunction unwrapParagraph(html: string): string {\n const match = html.match(/^\\s*<p\\b[^>]*>([\\s\\S]*)<\\/p>\\s*$/);\n if (!match) return html;\n // Only unwrap when there is exactly one top-level <p> — otherwise the\n // content has multiple paragraphs and we must leave it alone.\n if (/<\\/p>\\s*<p\\b/i.test(match[1])) return html;\n return match[1];\n}\n\nfunction renderFontFamilyAttr(\n fontFamily: string | undefined,\n context: RenderContext,\n): string {\n if (!fontFamily) {\n return \"\";\n }\n\n const resolved = context.resolveFontFamily(fontFamily);\n\n return ` font-family=\"${resolved}\"`;\n}\n","import type { ParagraphBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { convertMergeTagsToValues } from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a paragraph block to MJML markup.\n * All text formatting is inline in the HTML content (managed by TipTap).\n */\nexport function renderParagraph(\n block: ParagraphBlock,\n _context: RenderContext,\n): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n // Skip when the user has cleared the paragraph — otherwise we emit a\n // styled `<td>` cell that adds visible whitespace to the email even\n // though the canvas shows nothing for an empty paragraph.\n //\n // Use `[^<>]*` (not `[^>]*`) inside the tag to keep the regex linear:\n // `[^>]*` lets the engine consume across nested `<` chars and then\n // backtrack one char at a time when no closing `>` exists, which is\n // O(n²) over inputs like `<p<p<p<p…`. `[^<>]*` fails fast at the\n // next `<` and keeps each match attempt O(1). Real HTML attributes\n // never contain a raw `<`, so the restriction is semantics-preserving.\n const stripped = block.content.replace(/<\\/?p\\b[^<>]*>/gi, \"\").trim();\n if (stripped === \"\") {\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n const content = convertMergeTagsToValues(block.content);\n const visibilityAttr = getCssClassAttr(block);\n\n return `<mj-text\n line-height=\"1.5\"\n padding=\"${padding}\"${bgColor}${visibilityAttr}\n>${content}</mj-text>`;\n}\n","import type { ImageBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { escapeAttr } from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr, heightAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render an image block to MJML markup.\n */\nexport function renderImage(block: ImageBlock, context: RenderContext): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n if (block.src === \"\") {\n // Skip rather than emit `<mj-image src=\"\">` which compiles to a\n // broken-image icon. Mirrors video.ts behavior when no source is set.\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n const width =\n block.width === \"full\" ? context.containerWidth + \"px\" : block.width + \"px\";\n const height = heightAttr(block.height);\n\n const visibilityAttr = getCssClassAttr(block);\n\n let linkAttr = \"\";\n if (block.linkUrl) {\n linkAttr = ` href=\"${escapeAttr(block.linkUrl)}\"`;\n if (block.linkOpenInNewTab) {\n linkAttr += ' target=\"_blank\" rel=\"noopener\"';\n }\n }\n\n const src = escapeAttr(block.src);\n const decorative = block.decorative === true;\n const alt = decorative ? \"\" : escapeAttr(block.alt);\n const align = block.align;\n const roleAttr = decorative ? ' role=\"presentation\"' : \"\";\n\n return `<mj-image\n src=\"${src}\"\n alt=\"${alt}\"\n width=\"${width}\"${height}\n align=\"${align}\"\n padding=\"${padding}\"${bgColor}${linkAttr}${visibilityAttr}${roleAttr}\n/>`;\n}\n","import type { ButtonBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { escapeAttr, escapeHtml } from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a button block to MJML markup.\n */\nexport function renderButton(\n block: ButtonBlock,\n context: RenderContext,\n): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n const buttonPadding = toPaddingString(block.buttonPadding);\n\n // Omit href entirely when no URL is set so we don't emit a clickable\n // `<a href=\"\">` that navigates to whatever URL the email is opened from.\n const href = block.url === \"\" ? \"\" : escapeAttr(block.url);\n const hrefAttr = href === \"\" ? \"\" : ` href=\"${href}\"`;\n const backgroundColor = escapeAttr(block.backgroundColor);\n const textColor = escapeAttr(block.textColor);\n const fontSize = block.fontSize;\n const borderRadius = block.borderRadius;\n const text = escapeHtml(block.text);\n const targetAttr = block.openInNewTab\n ? ' target=\"_blank\" rel=\"noopener\"'\n : \"\";\n const fontFamilyAttr = renderFontFamilyAttr(block.fontFamily, context);\n const widthAttr = renderWidthAttr(block.width);\n const visibilityAttr = getCssClassAttr(block);\n // Templates stored before `align` existed have no value for it. Fall back to\n // MJML's own default so they keep rendering exactly as they did.\n const align = block.align ?? \"center\";\n\n return `<mj-button${hrefAttr}${targetAttr}\n background-color=\"${backgroundColor}\"\n color=\"${textColor}\"\n font-size=\"${fontSize}px\"\n font-weight=\"bold\"\n border-radius=\"${borderRadius}px\"\n inner-padding=\"${buttonPadding}\"\n align=\"${align}\"\n padding=\"${padding}\"${bgColor}${fontFamilyAttr}${widthAttr}${visibilityAttr}\n>${text}</mj-button>`;\n}\n\nfunction renderFontFamilyAttr(\n fontFamily: string | undefined,\n context: RenderContext,\n): string {\n if (!fontFamily) {\n return \"\";\n }\n\n const resolved = context.resolveFontFamily(fontFamily);\n\n return ` font-family=\"${resolved}\"`;\n}\n\nfunction renderWidthAttr(width: number | \"full\" | undefined): string {\n if (width === undefined) {\n return \"\";\n }\n\n const value = width === \"full\" ? \"100%\" : `${width}px`;\n\n return ` width=\"${value}\"`;\n}\n","import type { DividerBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { escapeAttr } from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a divider block to MJML markup.\n */\nexport function renderDivider(\n block: DividerBlock,\n _context: RenderContext,\n): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = block.styles.backgroundColor\n ? ` container-background-color=\"${escapeAttr(block.styles.backgroundColor)}\"`\n : \"\";\n const width = block.width === \"full\" ? \"100%\" : block.width + \"px\";\n const thickness = block.thickness;\n const lineStyle = block.lineStyle;\n const color = escapeAttr(block.color);\n const visibilityAttr = getCssClassAttr(block);\n\n return `<mj-divider\n border-width=\"${thickness}px\"\n border-style=\"${lineStyle}\"\n border-color=\"${color}\"\n width=\"${width}\"\n padding=\"${padding}\"${bgColor}${visibilityAttr}\n/>`;\n}\n","import type { SpacerBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { escapeAttr } from \"../escape\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a spacer block to MJML markup.\n *\n * The canvas renders a spacer at exactly `block.height` pixels and ignores\n * `block.styles.padding`. Match that here: emit `padding=\"0\"` so the\n * exported email's spacer occupies the same vertical space the user saw\n * in the editor preview. Any non-zero `block.styles.padding` on a spacer\n * is meaningless and silently dropped from the export.\n */\nexport function renderSpacer(\n block: SpacerBlock,\n _context: RenderContext,\n): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n const height = block.height;\n const bgColor = block.styles.backgroundColor\n ? ` container-background-color=\"${escapeAttr(block.styles.backgroundColor)}\"`\n : \"\";\n const visibilityAttr = getCssClassAttr(block);\n\n return `<mj-spacer height=\"${height}px\" padding=\"0\"${bgColor}${visibilityAttr} />`;\n}\n","import type { HtmlBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render an HTML block to MJML markup.\n * No sanitization in the OSS version -- consumers are responsible for content safety.\n */\nexport function renderHtml(block: HtmlBlock, context: RenderContext): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n if (!context.allowHtmlBlocks) {\n return \"\";\n }\n\n const content = block.content;\n\n if (content === \"\") {\n return \"\";\n }\n\n const visibilityAttr = getCssClassAttr(block);\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n\n // Use mj-text to render HTML content inside proper table cell structure.\n // mj-raw bypasses MJML's table layout and content won't be visible.\n return `<mj-text padding=\"${padding}\"${bgColor}${visibilityAttr}>\n${content}\n</mj-text>`;\n}\n","import type { SocialIconsBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { escapeAttr } from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a social icons block to MJML markup.\n *\n * Icons are emitted as `<img src=\"…/{style}/{platform}.png\">` rather than\n * inline SVG or base64 data URIs. Outlook desktop (Word rendering engine)\n * does not support SVG and rejects base64 in `<img src>`, so hosted PNGs are\n * the only format that renders across every mainstream client. The base URL\n * is read from `context.socialIconsBaseUrl` (configurable via\n * `RenderOptions.socialIconsBaseUrl`; default is the version-pinned jsDelivr\n * mirror of this package).\n */\nexport function renderSocialIcons(\n block: SocialIconsBlock,\n context: RenderContext,\n): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n const icons = block.icons;\n\n if (icons.length === 0) {\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = block.styles.backgroundColor\n ? ` container-background-color=\"${escapeAttr(block.styles.backgroundColor)}\"`\n : \"\";\n const visibilityAttr = getCssClassAttr(block);\n const align = block.align;\n const iconSize = block.iconSize;\n const iconStyle = block.iconStyle;\n const spacing = block.spacing;\n\n let iconSizePx: number;\n switch (iconSize) {\n case \"small\":\n iconSizePx = 24;\n break;\n case \"large\":\n iconSizePx = 48;\n break;\n default:\n iconSizePx = 32;\n break;\n }\n\n // MJML mj-social-element has default border-radius of 3px, override per style\n let borderRadius: string;\n switch (iconStyle) {\n case \"circle\":\n borderRadius = \"50%\";\n break;\n case \"rounded\":\n borderRadius = \"8px\";\n break;\n case \"square\":\n borderRadius = \"0\";\n break;\n default:\n borderRadius = \"4px\"; // solid, outlined\n break;\n }\n\n const iconCount = icons.length;\n const socialElements = icons.map((icon, index) => {\n const platform = icon.platform;\n const url = escapeAttr(icon.url);\n const iconSrc = `${context.socialIconsBaseUrl}/${iconStyle}/${platform}.png`;\n\n // Apply spacing as right padding only (except last icon) to match CSS gap behavior\n const rightPad = index === iconCount - 1 ? 0 : spacing;\n\n // Empty content hides the platform name text, matching the editor display\n return `<mj-social-element src=\"${iconSrc}\" href=\"${url}\" icon-size=\"${iconSizePx}px\" padding=\"0 ${rightPad}px 0 0\" border-radius=\"${borderRadius}\" background-color=\"transparent\"></mj-social-element>`;\n });\n\n const socialContent = socialElements.join(\"\\n\");\n\n return `<mj-social\n mode=\"horizontal\"\n align=\"${align}\"\n icon-padding=\"0\"\n padding=\"${padding}\"${bgColor}${visibilityAttr}\n>\n${socialContent}\n</mj-social>`;\n}\n","import type { MenuBlock, MenuItemData } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { escapeHtml, escapeAttr, escapeCssValue } from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a menu block to MJML markup.\n * Uses mj-text with inline <a> tags separated by styled <span> separators.\n */\nexport function renderMenu(block: MenuBlock, context: RenderContext): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n if (block.items.length === 0) {\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n const visibilityAttr = getCssClassAttr(block);\n const fontFamilyAttr = renderFontFamilyAttr(block.fontFamily, context);\n const align = block.textAlign;\n const fontSize = block.fontSize;\n // Emit the color only when set; otherwise the `mj-text` inherits the\n // document `textColor` and the item anchors below inherit it in turn.\n const colorAttr = block.color ? `\\n color=\"${escapeAttr(block.color)}\"` : \"\";\n\n const content = renderMenuItems(block);\n\n return `<mj-text\n font-size=\"${fontSize}px\"${colorAttr}\n align=\"${align}\"\n line-height=\"1.5\"\n padding=\"${padding}\"${bgColor}${fontFamilyAttr}${visibilityAttr}\n>${content}</mj-text>`;\n}\n\nfunction renderMenuItems(block: MenuBlock): string {\n const items = block.items;\n const separator = escapeHtml(block.separator);\n const separatorColor = escapeCssValue(block.separatorColor);\n const spacing = block.spacing;\n const linkColor = block.linkColor ?? block.color;\n\n const parts: string[] = [];\n const itemCount = items.length;\n\n for (let index = 0; index < itemCount; index++) {\n parts.push(renderMenuItem(items[index], linkColor));\n\n if (index < itemCount - 1) {\n parts.push(\n `<span style=\"color: ${separatorColor}; padding: 0 ${spacing}px;\">${separator}</span>`,\n );\n }\n }\n\n return parts.join(\"\");\n}\n\nfunction renderMenuItem(\n item: MenuItemData,\n linkColor: string | undefined,\n): string {\n const text = escapeHtml(item.text);\n const url = escapeAttr(item.url);\n // Item color, else the menu link color; when neither is set the anchor omits\n // an explicit color and inherits the mj-text color (the document `textColor`).\n const resolvedColor = item.color ?? linkColor;\n const target = item.openInNewTab ? ' target=\"_blank\" rel=\"noopener\"' : \"\";\n\n const styles: string[] = [\"text-decoration: none\"];\n\n if (resolvedColor) {\n styles.unshift(`color: ${escapeCssValue(resolvedColor)}`);\n }\n\n if (item.bold) {\n styles.push(\"font-weight: bold\");\n }\n\n if (item.underline) {\n styles.push(\"text-decoration: underline\");\n }\n\n const styleAttr = styles.join(\"; \");\n\n return `<a href=\"${url}\" style=\"${styleAttr}\"${target}>${text}</a>`;\n}\n\nfunction renderFontFamilyAttr(\n fontFamily: string | undefined,\n context: RenderContext,\n): string {\n if (!fontFamily) {\n return \"\";\n }\n\n const resolved = context.resolveFontFamily(fontFamily);\n\n return ` font-family=\"${resolved}\"`;\n}\n","import type {\n TableBlock,\n TableRowData,\n TableCellData,\n} from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport {\n escapeAttr,\n escapeCssValue,\n escapeHtml,\n convertMergeTagsToValues,\n} from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a table block to MJML markup.\n * Uses mj-text wrapping an HTML <table> with styled <tr>/<td> elements.\n */\nexport function renderTable(block: TableBlock, context: RenderContext): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n if (block.rows.length === 0) {\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n const visibilityAttr = getCssClassAttr(block);\n const fontFamilyAttr = renderFontFamilyAttr(block.fontFamily, context);\n const fontSize = block.fontSize;\n // Emit the color only when set; otherwise the `mj-text` (and its cells,\n // which carry no color of their own) inherit the document `textColor`.\n const colorAttr = block.color ? `\\n color=\"${escapeAttr(block.color)}\"` : \"\";\n const align = block.textAlign;\n\n const tableHtml = renderTableElement(block);\n\n return `<mj-text\n font-size=\"${fontSize}px\"${colorAttr}\n align=\"${align}\"\n line-height=\"1.5\"\n padding=\"${padding}\"${bgColor}${fontFamilyAttr}${visibilityAttr}\n>${tableHtml}</mj-text>`;\n}\n\nfunction renderTableElement(block: TableBlock): string {\n const borderColor = escapeCssValue(block.borderColor);\n const borderWidth = block.borderWidth;\n\n const tableStyle = \"width: 100%; border-collapse: collapse;\";\n\n let rowsHtml = \"\";\n\n for (let index = 0; index < block.rows.length; index++) {\n const row = block.rows[index];\n const isHeader = block.hasHeaderRow && index === 0;\n rowsHtml += renderRow(row, block, isHeader, borderColor, borderWidth);\n }\n\n return `<table style=\"${tableStyle}\">${rowsHtml}</table>`;\n}\n\nfunction renderRow(\n row: TableRowData,\n block: TableBlock,\n isHeader: boolean,\n borderColor: string,\n borderWidth: number,\n): string {\n let cellsHtml = \"\";\n\n for (const cell of row.cells) {\n cellsHtml += renderCell(cell, block, isHeader, borderColor, borderWidth);\n }\n\n return `<tr>${cellsHtml}</tr>`;\n}\n\nfunction renderCell(\n cell: TableCellData,\n block: TableBlock,\n isHeader: boolean,\n borderColor: string,\n borderWidth: number,\n): string {\n const cellPadding = block.cellPadding;\n\n const styles: string[] = [\n `border: ${borderWidth}px solid ${borderColor}`,\n `padding: ${cellPadding}px`,\n ];\n\n if (isHeader) {\n styles.push(\"font-weight: bold\");\n\n if (block.headerBackgroundColor) {\n styles.push(\n `background-color: ${escapeCssValue(block.headerBackgroundColor)}`,\n );\n }\n }\n\n const styleAttr = styles.join(\"; \");\n // Cells are a plain-text field (the editor stores innerText; TableCellData\n // carries no rich-text hint), so escape the content like menu/button. Merge\n // tags are resolved first: convertMergeTagsToValues matches a literal\n // `<span`, so escaping has to run after it — escaping first would turn the\n // span into `&lt;span` and the `{{value}}` placeholder would never resolve.\n const content = escapeHtml(convertMergeTagsToValues(cell.content));\n\n const tag = isHeader ? \"th\" : \"td\";\n\n return `<${tag} style=\"${styleAttr}\">${content}</${tag}>`;\n}\n\nfunction renderFontFamilyAttr(\n fontFamily: string | undefined,\n context: RenderContext,\n): string {\n if (!fontFamily) {\n return \"\";\n }\n\n const resolved = context.resolveFontFamily(fontFamily);\n\n return ` font-family=\"${resolved}\"`;\n}\n","import type { CustomBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Render a custom block to MJML markup.\n *\n * Custom block HTML resolution order:\n * 1. `context.customBlockHtml` map — populated by `renderToMjml` when the\n * caller passes a `renderCustomBlock` option (typical for editor\n * consumers and headless callers wiring their own resolver).\n * 2. `block.renderedHtml` — populated by an external pre-render step\n * (e.g., a previous render pass that mutated the block).\n * 3. Empty — block omitted from output.\n */\nexport function renderCustom(\n block: CustomBlock,\n context: RenderContext,\n): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n const fromContext = context.customBlockHtml.get(block.id);\n const content = fromContext ?? block.renderedHtml;\n\n if (!content || content === \"\") {\n return \"\";\n }\n\n const visibilityAttr = getCssClassAttr(block);\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n\n return `<mj-text padding=\"${padding}\"${bgColor}${visibilityAttr}>\n${content}\n</mj-text>`;\n}\n","import type { ColumnLayout } from \"@templatical/types\";\n\n/**\n * Get width percentages for each column in a layout.\n */\nexport function getWidthPercentages(layout: ColumnLayout): string[] {\n switch (layout) {\n case \"2\":\n return [\"50%\", \"50%\"];\n case \"3\":\n // 33.33 × 3 = 99.99% — let the last column absorb the rounding gap\n // so widths sum to exactly 100% in the compiled HTML.\n return [\"33.33%\", \"33.33%\", \"33.34%\"];\n case \"1-2\":\n return [\"33.33%\", \"66.67%\"];\n case \"2-1\":\n return [\"66.67%\", \"33.33%\"];\n default:\n return [\"100%\"];\n }\n}\n\n/**\n * Get width in pixels for each column in a layout.\n */\nexport function getWidthPixels(\n layout: ColumnLayout,\n containerWidth: number,\n): number[] {\n switch (layout) {\n case \"2\":\n return [containerWidth * 0.5, containerWidth * 0.5];\n case \"3\":\n return [containerWidth / 3, containerWidth / 3, containerWidth / 3];\n case \"1-2\":\n return [containerWidth / 3, (containerWidth * 2) / 3];\n case \"2-1\":\n return [(containerWidth * 2) / 3, containerWidth / 3];\n default:\n return [containerWidth];\n }\n}\n","import type { Block } from \"@templatical/types\";\n\n/**\n * Wrap rendered block markup in the block's liquid display-condition guards\n * (`<mj-raw>{% if %}</mj-raw>` … `<mj-raw>{% endif %}</mj-raw>`), if present.\n *\n * Returns the input unchanged when the block has no display condition, and an\n * empty string when the rendered markup is empty (a hidden block) so callers\n * can keep using an `=== \"\"` filter to drop it.\n *\n * Used for BOTH top-level blocks (`index.ts`) and blocks nested inside section\n * columns (`renderers/section.ts`). A condition on a nested block must emit the\n * same guards as a top-level one — otherwise conditional content placed inside\n * a multi-column section renders unconditionally for every recipient.\n */\nexport function wrapWithDisplayCondition(\n block: Block,\n rendered: string,\n): string {\n if (rendered === \"\") {\n return \"\";\n }\n\n const displayCondition = block.displayCondition;\n\n if (!displayCondition) {\n return rendered;\n }\n\n return (\n `<mj-raw>${displayCondition.before}</mj-raw>` +\n \"\\n\" +\n rendered +\n \"\\n\" +\n `<mj-raw>${displayCondition.after}</mj-raw>`\n );\n}\n","import type { Block, SectionBlock } from \"@templatical/types\";\nimport { isSection } from \"@templatical/types\";\nimport type { BlockRenderer, RenderContext } from \"../render-context\";\nimport { getWidthPercentages, getWidthPixels } from \"../columns\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\nimport { wrapWithDisplayCondition } from \"../display-condition\";\n\n// `BlockRenderer` is defined in `../render-context`, next to the `blockRenderers`\n// override map it types. Re-exported here so the package's\n// `export type { BlockRenderer } from \"./renderers/section\"` entry point resolves\n// for consumers.\nexport type { BlockRenderer };\n\n/**\n * Render a section block with columns to MJML markup.\n */\nexport function renderSection(\n block: SectionBlock,\n context: RenderContext,\n renderBlock: BlockRenderer,\n): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n const columnsLayout = block.columns;\n const columnWidths = getWidthPercentages(columnsLayout);\n const columnWidthsPx = getWidthPixels(columnsLayout, context.containerWidth);\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"native\");\n const visibilityAttr = getCssClassAttr(block);\n const borderRadiusAttr =\n block.borderRadius && block.borderRadius > 0\n ? ` border-radius=\"${block.borderRadius}px\"`\n : \"\";\n\n const children = block.children;\n const columnsContent: string[] = [];\n\n for (let index = 0; index < children.length; index++) {\n const column = children[index];\n const width = columnWidths[index] ?? \"100%\";\n const columnWidth = Math.floor(\n columnWidthsPx[index] ?? context.containerWidth,\n );\n\n // Sections cannot be nested inside columns per MJML spec — drop any\n // SectionBlocks that landed inside a column (via tampered JSON or a\n // future API). Keeping them would emit `<mj-section>` inside\n // `<mj-column>`, which mjml@5 rejects with a hard error.\n const filteredColumn = filterHtmlBlocks(\n column,\n context.allowHtmlBlocks,\n ).filter((child) => !isSection(child));\n const columnContext = context.withContainerWidth(columnWidth);\n\n const columnBlocks = filteredColumn\n .map((child) =>\n wrapWithDisplayCondition(child, renderBlock(child, columnContext)),\n )\n .filter((value) => value !== \"\")\n .join(\"\\n\");\n\n const content =\n columnBlocks === \"\" ? \"<mj-text>&nbsp;</mj-text>\" : columnBlocks;\n\n columnsContent.push(`<mj-column width=\"${width}\">\n${content}\n</mj-column>`);\n }\n\n const columns = columnsContent.join(\"\\n\");\n\n // Opting out of mobile stacking wraps the columns in an `<mj-group>`, which\n // keeps them side-by-side below 480px instead of stacking (MJML's default).\n // `mj-group` requires percentage column widths — `getWidthPercentages`\n // already guarantees that. Only meaningful with 2+ columns.\n const body =\n block.stackOnMobile === false && columnsContent.length > 1\n ? `<mj-group>\n${columns}\n</mj-group>`\n : columns;\n\n return `<mj-section${bgColor} padding=\"${padding}\"${borderRadiusAttr}${visibilityAttr}>\n${body}\n</mj-section>`;\n}\n\n/**\n * Filter out HTML blocks if they are not allowed.\n */\nfunction filterHtmlBlocks(blocks: Block[], allowHtmlBlocks: boolean): Block[] {\n if (allowHtmlBlocks) {\n return blocks;\n }\n\n return blocks.filter((block) => block.type !== \"html\");\n}\n","import type { VideoBlock } from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { escapeAttr } from \"../escape\";\nimport { toPaddingString } from \"../padding\";\nimport { bgAttr, heightAttr } from \"../utils\";\nimport { isHiddenOnAll, getCssClassAttr } from \"../visibility\";\n\n/**\n * Extract video thumbnail URL from common platforms.\n * Works without server-side processing — YouTube and Vimeo thumbnails are publicly accessible.\n */\nfunction getVideoThumbnail(\n url: string,\n customThumbnail?: string,\n): string | null {\n if (customThumbnail) {\n return customThumbnail;\n }\n\n if (!url) {\n return null;\n }\n\n // YouTube\n const youtubePatterns = [\n /(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/|youtube\\.com\\/embed\\/)([a-zA-Z0-9_-]{11})/,\n /youtube\\.com\\/shorts\\/([a-zA-Z0-9_-]{11})/,\n ];\n\n for (const pattern of youtubePatterns) {\n const match = url.match(pattern);\n if (match) {\n return `https://img.youtube.com/vi/${match[1]}/maxresdefault.jpg`;\n }\n }\n\n // Vimeo\n const vimeoMatch = url.match(/vimeo\\.com\\/(?:video\\/)?(\\d+)/);\n if (vimeoMatch) {\n return `https://vumbnail.com/${vimeoMatch[1]}.jpg`;\n }\n\n return null;\n}\n\n/**\n * Render a video block to MJML markup.\n * Videos in email are rendered as a linked thumbnail image pointing to the video URL.\n */\nexport function renderVideo(block: VideoBlock, context: RenderContext): string {\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n const thumbnailUrl = getVideoThumbnail(block.url, block.thumbnailUrl);\n\n if (!thumbnailUrl) {\n return \"\";\n }\n\n const padding = toPaddingString(block.styles.padding);\n const bgColor = bgAttr(block.styles.backgroundColor, \"container\");\n const width =\n block.width === \"full\" ? context.containerWidth + \"px\" : block.width + \"px\";\n const height = heightAttr(block.height);\n const visibilityAttr = getCssClassAttr(block);\n\n const src = escapeAttr(thumbnailUrl);\n const alt = escapeAttr(block.alt);\n const align = block.align;\n const href = escapeAttr(block.url);\n\n return `<mj-image\n src=\"${src}\"\n alt=\"${alt}\"\n width=\"${width}\"${height}\n align=\"${align}\"\n padding=\"${padding}\"\n href=\"${href}\"\n target=\"_blank\"\n rel=\"noopener\"${bgColor}${visibilityAttr}\n/>`;\n}\n","import type { Block } from \"@templatical/types\";\nimport {\n isSection,\n isTitle,\n isParagraph,\n isImage,\n isButton,\n isDivider,\n isSpacer,\n isHtml,\n isSocialIcons,\n isMenu,\n isTable,\n isVideo,\n isCustomBlock,\n} from \"@templatical/types\";\nimport type { RenderContext } from \"../render-context\";\nimport { isHiddenOnAll } from \"../visibility\";\nimport { renderUnrenderableBlock } from \"../unrenderable\";\nimport { renderTitle } from \"./title\";\nimport { renderParagraph } from \"./paragraph\";\nimport { renderImage } from \"./image\";\nimport { renderButton } from \"./button\";\nimport { renderDivider } from \"./divider\";\nimport { renderSpacer } from \"./spacer\";\nimport { renderHtml } from \"./html\";\nimport { renderSocialIcons } from \"./social\";\nimport { renderMenu } from \"./menu\";\nimport { renderTable } from \"./table\";\nimport { renderCustom } from \"./custom\";\nimport { renderSection } from \"./section\";\nimport { renderVideo } from \"./video\";\n\n/**\n * Render a single block to MJML markup.\n * Dispatches to the appropriate block-type renderer.\n *\n * A `blockRenderers` override for the block's type wins over the built-in\n * renderer — see {@link RenderContext.blockRenderers}. A type with neither gets a\n * placeholder marker plus a warning rather than disappearing.\n */\nexport function renderBlock(block: Block, context: RenderContext): string {\n // Checked first so an override replaces the built-in wholesale rather than\n // running after it. The override then owns everything the built-in did,\n // including the hidden-on-all-viewports early return.\n const override = context.blockRenderers[block.type];\n if (override) {\n return override(block, context);\n }\n\n if (isSection(block)) {\n return renderSection(block, context, renderBlock);\n }\n\n if (isTitle(block)) {\n return renderTitle(block, context);\n }\n\n if (isParagraph(block)) {\n return renderParagraph(block, context);\n }\n\n if (isImage(block)) {\n return renderImage(block, context);\n }\n\n if (isButton(block)) {\n return renderButton(block, context);\n }\n\n if (isDivider(block)) {\n return renderDivider(block, context);\n }\n\n if (isSpacer(block)) {\n return renderSpacer(block, context);\n }\n\n if (isHtml(block)) {\n return renderHtml(block, context);\n }\n\n if (isSocialIcons(block)) {\n return renderSocialIcons(block, context);\n }\n\n if (isMenu(block)) {\n return renderMenu(block, context);\n }\n\n if (isTable(block)) {\n return renderTable(block, context);\n }\n\n if (isVideo(block)) {\n return renderVideo(block, context);\n }\n\n if (isCustomBlock(block)) {\n return renderCustom(block, context);\n }\n\n // Nothing here knows how to render this type. A block the author hid on every\n // viewport is meant to produce nothing, so it still does — every built-in\n // renderer above makes the same call, and warning about a deliberate hide would\n // be noise. Everything else gets a marker: `countdown` today (Cloud renders it\n // server-side as an animated GIF, which no browser can do), and any future type\n // whose renderer hasn't landed yet.\n if (isHiddenOnAll(block)) {\n return \"\";\n }\n\n return renderUnrenderableBlock(block);\n}\n","import type {\n Block,\n CustomBlock,\n TemplateContent,\n CustomFont,\n SectionWrapper,\n} from \"@templatical/types\";\nimport { isSection, isCustomBlock } from \"@templatical/types\";\nimport { RenderContext, DEFAULT_SOCIAL_ICONS_BASE_URL } from \"./render-context\";\nimport type { BlockRendererMap } from \"./render-context\";\nimport { renderBlock } from \"./renderers\";\nimport { escapeHtml, escapeAttr, escapeCssValue } from \"./escape\";\nimport { wrapWithDisplayCondition } from \"./display-condition\";\nimport { bgAttr } from \"./utils\";\nimport { toPaddingString } from \"./padding\";\n\nexport interface RenderOptions {\n customFonts?: CustomFont[];\n defaultFallbackFont?: string;\n allowHtmlBlocks?: boolean;\n /**\n * Resolves custom blocks to their HTML representation. Called once per\n * custom block in the content tree before MJML rendering. The renderer\n * has no built-in knowledge of how to render custom blocks; consumers\n * provide this function.\n *\n * Editor consumers: pass `editor.renderCustomBlock`.\n *\n * Headless consumers (Node.js, server, CLI): provide your own resolver,\n * typically using the same liquid template + field values pipeline as\n * the editor uses. If omitted, custom blocks fall back to\n * `block.renderedHtml` (if present) and otherwise are omitted from the\n * output.\n */\n renderCustomBlock?: (block: CustomBlock) => Promise<string>;\n /**\n * Per-block-type renderer overrides, keyed by `block.type`. An entry replaces\n * the built-in renderer for that type wholesale — including its\n * hidden-on-all-viewports check, which becomes the override's responsibility.\n *\n * ```ts\n * renderToMjml(content, {\n * blockRenderers: {\n * countdown: (block) => `<mj-image src=\"${countdownGifUrl(block)}\" />`,\n * video: (block, ctx) => renderVideoWithPlayButton(block, ctx),\n * },\n * });\n * ```\n *\n * This generalises {@link renderCustomBlock}, which is the same idea for a\n * single block type. It exists so a backend whose render output is a *superset*\n * of the browser's — a server-generated countdown GIF, a composited video\n * thumbnail — can inject exactly that delta instead of forking the renderer:\n * parity for every other block type then holds by construction.\n *\n * A block type with neither a built-in renderer nor an override emits an\n * `mj-raw` placeholder comment and warns, rather than vanishing from the\n * output.\n */\n blockRenderers?: BlockRendererMap;\n /**\n * Resolves the definition-level CSS for a custom block type. Called once\n * per unique `customType` present in the content tree (not per instance).\n * The non-empty results are deduped by content and emitted as additional\n * `<mj-style>` blocks inside `<mj-head>` alongside the built-in visibility\n * media queries.\n *\n * Editor consumers: pass a function that reads\n * `blockRegistry.getDefinition(customType)?.stylesheet`.\n *\n * Headless consumers: provide your own resolver, typically from the same\n * definitions map used by `renderCustomBlock`. Return `undefined` or `null`\n * for definitions without a stylesheet — those are skipped.\n */\n getCustomBlockStylesheet?: (customType: string) => string | undefined | null;\n /**\n * Base URL (no trailing slash) for the social icon PNG assets. Resolved to\n * `${baseUrl}/${style}/${platform}.png` per icon. Defaults to the\n * version-pinned jsDelivr mirror of this package. Override to self-host\n * (e.g., behind your own CDN or for air-gapped environments).\n *\n * Why PNGs: Outlook desktop (Word rendering engine) does not support SVG\n * and rejects base64 data URIs in `<img src>`, so social icons must be\n * served as raster images over HTTP for cross-client compatibility.\n */\n socialIconsBaseUrl?: string;\n}\n\n/**\n * Render template content to an MJML string.\n *\n * The function is async because resolving custom blocks may require\n * asynchronous work (e.g., the editor's liquid renderer dynamically imports\n * `liquidjs`). When the content has no custom blocks or `renderCustomBlock`\n * is omitted, no async work is performed but the function still resolves\n * synchronously — i.e., it always returns a Promise.\n */\nexport async function renderToMjml(\n content: TemplateContent,\n options?: RenderOptions,\n): Promise<string> {\n const customFonts = options?.customFonts ?? [];\n const defaultFallbackFont =\n options?.defaultFallbackFont ?? \"Arial, sans-serif\";\n const allowHtmlBlocks = options?.allowHtmlBlocks ?? true;\n const socialIconsBaseUrl = stripTrailingSlash(\n options?.socialIconsBaseUrl ?? DEFAULT_SOCIAL_ICONS_BASE_URL,\n );\n\n const customBlockHtml = await resolveCustomBlocks(\n content,\n options?.renderCustomBlock,\n );\n\n const customBlockStylesheets = collectCustomBlockStylesheets(\n content,\n options?.getCustomBlockStylesheet,\n );\n\n const renderContext = new RenderContext(\n content.settings.width,\n customFonts,\n defaultFallbackFont,\n allowHtmlBlocks,\n customBlockHtml,\n socialIconsBaseUrl,\n options?.blockRenderers ?? {},\n );\n\n const blocks = filterHtmlBlocks(content.blocks, allowHtmlBlocks);\n const fontFamily = renderContext.resolveFontFamily(\n content.settings.fontFamily,\n );\n const backgroundColor = content.settings.backgroundColor;\n // Document-level default text color → the `<mj-text>` default below. Blocks\n // that set their own color (e.g. Title) or carry inline text-color marks\n // override it. Omitted when unset so existing templates render identically.\n const textColorAttr = content.settings.textColor\n ? ` color=\"${escapeAttr(content.settings.textColor)}\"`\n : \"\";\n // Document-level link styling → the global `a { … }` rule below, cascading to\n // every link (rich-text and menu). An unset `linkColor` keeps `color: inherit`\n // so links follow the text color and legacy content renders identically; a\n // per-link/per-item color still overrides (inline styles beat this rule).\n const linkColor = content.settings.linkColor\n ? escapeCssValue(content.settings.linkColor)\n : \"inherit\";\n const linkDecoration = content.settings.linkUnderline ? \"underline\" : \"none\";\n\n const bodyContent = blocks\n .map((block) => renderTopLevelBlock(block, renderContext))\n .filter((value) => value !== \"\")\n .join(\"\\n\");\n\n const fontDeclarations = generateFontDeclarations(customFonts);\n const previewTag = generatePreviewTag(content.settings.preheaderText);\n\n const lang = escapeAttr(content.settings.locale);\n\n return `<mjml lang=\"${lang}\">\n <mj-head>${previewTag}\n <mj-attributes>\n <mj-all font-family=\"${fontFamily}\" />\n <mj-text font-size=\"14px\"${textColorAttr} />\n <mj-section padding=\"0\" />\n <mj-column padding=\"0\" />\n <mj-image fluid-on-mobile=\"true\" />\n </mj-attributes>${fontDeclarations}\n <mj-style>\n a { color: ${linkColor}; text-decoration: ${linkDecoration}; }\n @media only screen and (max-width: 480px) {\n .tpl-hide-mobile { display: none !important; mso-hide: all !important; }\n }\n @media only screen and (min-width: 481px) {\n .tpl-hide-desktop { display: none !important; mso-hide: all !important; }\n }\n </mj-style>${renderCustomBlockStylesheets(customBlockStylesheets)}\n </mj-head>\n <mj-body width=\"${renderContext.containerWidth}px\" background-color=\"${backgroundColor}\">\n${bodyContent}\n </mj-body>\n</mjml>`;\n}\n\n/**\n * Render a top-level block. Sections are rendered directly,\n * non-section blocks are wrapped in a default section/column.\n */\nfunction renderTopLevelBlock(block: Block, context: RenderContext): string {\n if (isSection(block)) {\n const rendered = renderBlock(block, context);\n // An empty render (hidden section) stays empty — never emit a bare wrapper.\n const framed =\n block.wrapper && rendered !== \"\"\n ? renderSectionWrapper(rendered, block.wrapper)\n : rendered;\n return wrapWithDisplayCondition(block, framed);\n }\n\n const content = renderBlock(block, context);\n const wrapped = wrapInSection(content);\n return wrapWithDisplayCondition(block, wrapped);\n}\n\n/**\n * Wrap a rendered section's `mj-section` in an `mj-wrapper` — a full-width band\n * (its own background + padding + optional radius) that frames the section.\n * `mj-wrapper` is the only MJML element that may contain `mj-section`.\n */\nfunction renderSectionWrapper(inner: string, wrapper: SectionWrapper): string {\n const bg = bgAttr(wrapper.backgroundColor, \"native\");\n const padding = ` padding=\"${\n wrapper.padding ? toPaddingString(wrapper.padding) : \"0\"\n }\"`;\n const radius =\n wrapper.borderRadius && wrapper.borderRadius > 0\n ? ` border-radius=\"${wrapper.borderRadius}px\"`\n : \"\";\n return `<mj-wrapper${bg}${padding}${radius}>\n${inner}\n</mj-wrapper>`;\n}\n\n/**\n * Wrap block content in a default mj-section/mj-column for non-section blocks.\n */\nfunction wrapInSection(content: string): string {\n if (content === \"\") {\n return \"\";\n }\n\n return `<mj-section>\n <mj-column>\n${content}\n </mj-column>\n</mj-section>`;\n}\n\nfunction stripTrailingSlash(url: string): string {\n return url.endsWith(\"/\") ? url.slice(0, -1) : url;\n}\n\nfunction generatePreviewTag(preheaderText?: string): string {\n if (!preheaderText) {\n return \"\";\n }\n\n const trimmed = preheaderText.trim();\n\n if (trimmed === \"\") {\n return \"\";\n }\n\n const escaped = escapeHtml(trimmed);\n\n return `\\n <mj-preview>${escaped}</mj-preview>`;\n}\n\nfunction generateFontDeclarations(customFonts: CustomFont[]): string {\n if (customFonts.length === 0) {\n return \"\";\n }\n\n return customFonts\n .map(\n (font) =>\n `\\n <mj-font name=\"${escapeAttr(font.name)}\" href=\"${escapeAttr(font.url)}\" />`,\n )\n .join(\"\");\n}\n\n/**\n * Filter out HTML blocks if they are not allowed.\n */\nfunction filterHtmlBlocks(blocks: Block[], allowHtmlBlocks: boolean): Block[] {\n if (allowHtmlBlocks) {\n return blocks;\n }\n\n return blocks.filter((block) => block.type !== \"html\");\n}\n\n/**\n * Walk the content tree, collect every custom block, then resolve each in\n * parallel via the supplied callback. Returns a map keyed by block id that\n * the synchronous render pass reads from. If no callback is provided, returns\n * an empty map and the sync pass falls back to `block.renderedHtml`.\n *\n * Per-block failures bubble up — the caller decides whether to swallow or\n * rethrow. We don't replace failures with placeholders here because that's\n * a policy decision (the editor swallows; a strict CLI may want to fail).\n */\nasync function resolveCustomBlocks(\n content: TemplateContent,\n renderCustomBlock: RenderOptions[\"renderCustomBlock\"],\n): Promise<Map<string, string>> {\n const result = new Map<string, string>();\n\n if (!renderCustomBlock) {\n return result;\n }\n\n const customBlocks: CustomBlock[] = [];\n collectCustomBlocks(content.blocks, customBlocks);\n\n if (customBlocks.length === 0) {\n return result;\n }\n\n const rendered = await Promise.all(\n customBlocks.map((block) => renderCustomBlock(block)),\n );\n\n for (let index = 0; index < customBlocks.length; index++) {\n result.set(customBlocks[index].id, rendered[index]);\n }\n\n return result;\n}\n\nfunction collectCustomBlocks(blocks: Block[], out: CustomBlock[]): void {\n for (const block of blocks) {\n if (isCustomBlock(block)) {\n out.push(block);\n continue;\n }\n\n if (isSection(block)) {\n for (const column of block.children) {\n collectCustomBlocks(column, out);\n }\n }\n }\n}\n\n/**\n * Walk the content tree, find every unique `customType`, ask the consumer's\n * resolver for that definition's stylesheet, and return the non-empty,\n * content-deduped set in insertion order.\n *\n * Content-level dedupe (not just by customType) means two definitions that\n * happen to ship the same stylesheet string emit it only once — cheap and\n * matches the \"one rule, emitted once\" mental model. Whitespace-only and\n * empty stylesheets are skipped.\n */\nfunction collectCustomBlockStylesheets(\n content: TemplateContent,\n resolver: RenderOptions[\"getCustomBlockStylesheet\"],\n): string[] {\n if (!resolver) {\n return [];\n }\n\n const customBlocks: CustomBlock[] = [];\n collectCustomBlocks(content.blocks, customBlocks);\n\n if (customBlocks.length === 0) {\n return [];\n }\n\n const seenTypes = new Set<string>();\n const seenContent = new Set<string>();\n const stylesheets: string[] = [];\n\n for (const block of customBlocks) {\n if (seenTypes.has(block.customType)) {\n continue;\n }\n seenTypes.add(block.customType);\n\n const css = resolver(block.customType);\n if (!css) {\n continue;\n }\n\n const trimmed = css.trim();\n if (trimmed === \"\" || seenContent.has(trimmed)) {\n continue;\n }\n seenContent.add(trimmed);\n stylesheets.push(trimmed);\n }\n\n return stylesheets;\n}\n\nfunction renderCustomBlockStylesheets(stylesheets: string[]): string {\n if (stylesheets.length === 0) {\n return \"\";\n }\n\n // One `<mj-style>` per unique stylesheet so per-definition CSS can be\n // independently inspected in the rendered MJML, and authors can grep their\n // contribution without disentangling a merged blob.\n return stylesheets\n .map((css) => `\\n <mj-style>\\n${css}\\n </mj-style>`)\n .join(\"\");\n}\n\n// Re-export utilities for consumers\nexport { RenderContext } from \"./render-context\";\nexport { escapeHtml, escapeAttr, convertMergeTagsToValues } from \"./escape\";\nexport { isHiddenOnAll, getCssClassAttr, getCssClasses } from \"./visibility\";\nexport { getWidthPercentages, getWidthPixels } from \"./columns\";\nexport { toPaddingString } from \"./padding\";\nexport { DEFAULT_SOCIAL_ICONS_BASE_URL } from \"./render-context\";\nexport { renderBlock } from \"./renderers\";\nexport {\n renderUnrenderableBlock,\n UNRENDERABLE_MARKER_PREFIX,\n} from \"./unrenderable\";\nexport type { BlockRenderer, BlockRendererMap } from \"./render-context\";\n"],"mappings":"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"}