@templatical/editor 0.41.0 → 0.42.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/dist/{AiChatSidebar-a8TPBAl2.js → AiChatSidebar-DOCvzGBe.js} +8 -8
  2. package/dist/{AiFeatureMenu-CroDMqRG.js → AiFeatureMenu-CfijAx4G.js} +4 -4
  3. package/dist/{BlockIssueBadge-D8KsGWY6.js → BlockIssueBadge-BJ3A6mqh.js} +2 -2
  4. package/dist/{BlockPreviewCanvas-Z9SZIgfA.js → BlockPreviewCanvas-DggfBaoJ.js} +33 -33
  5. package/dist/{CloudHeaderExtras-CVqHeqc6.js → CloudHeaderExtras-dFbdqBr5.js} +2 -2
  6. package/dist/{CloudPanels-CmEpQUJB.js → CloudPanels-DmMxhzzZ.js} +4 -4
  7. package/dist/{CollaboratorBar-AIQC9fEF.js → CollaboratorBar-XXk1tOC5.js} +2 -2
  8. package/dist/{CommentsPanel-9k1q-79y.js → CommentsPanel-CGEhbjx0.js} +1 -1
  9. package/dist/{CommentsSidebar-Bc7nORmD.js → CommentsSidebar-CUpst9ou.js} +10 -10
  10. package/dist/{CountdownToolbar-DkC-qSgq.js → CountdownToolbar-B1a_UIuB.js} +3 -3
  11. package/dist/{DesignReferenceSidebar-OoiYJAKS.js → DesignReferenceSidebar-DkAmsBgM.js} +6 -6
  12. package/dist/{IssuesPanel-Dnns3O9z.js → IssuesPanel-lTpsCV4a.js} +5 -5
  13. package/dist/{LogicTagInsertButton-BimKobaG.js → LogicTagInsertButton-B5YymR4U.js} +243 -219
  14. package/dist/{MediaEditModal-C-InB-H2.js → MediaEditModal-B1X8qtJb.js} +1 -1
  15. package/dist/{MediaPanels-CTosUpeo.js → MediaPanels-DO30L1KS.js} +1 -1
  16. package/dist/{MergeTagInput-DqpVzhy7.js → MergeTagInput-B0M_-X0K.js} +1 -1
  17. package/dist/{MergeTagModeToggle-BkIiAgpQ.js → MergeTagModeToggle-B-8W1tK7.js} +4 -4
  18. package/dist/{ParagraphEditor-DaZ03d1U.js → ParagraphEditor-BhhpXgoO.js} +35 -35
  19. package/dist/{RestoreVersionDialog-DHb1mPoF.js → RestoreVersionDialog-DE8aqmdi.js} +3 -3
  20. package/dist/{RichTextEditorContent-AEtfKvLz.js → RichTextEditorContent-AaLAArA0.js} +5 -5
  21. package/dist/{SaveBlockDialog-hGwLDWfE.js → SaveBlockDialog-BJ-hEwLv.js} +8 -8
  22. package/dist/{SavedBlocksBrowserModal-C0lYVBFi.js → SavedBlocksBrowserModal-nLI8aAQ5.js} +9 -9
  23. package/dist/{SavedBlocksPanels-CaTbeVDv.js → SavedBlocksPanels-RnzUMUJI.js} +1 -1
  24. package/dist/{SavedBlocksPickBar-DR2afid2.js → SavedBlocksPickBar-D3QA3Tgy.js} +2 -2
  25. package/dist/{TemplateScoringPanel-Cs0TGtRF.js → TemplateScoringPanel-C6ellAcs.js} +11 -11
  26. package/dist/{TemplateSettings-BD1WNP4C.js → TemplateSettings-C_0qK-zs.js} +6 -6
  27. package/dist/{TestEmailModal-DqoosG1u.js → TestEmailModal-CnyxLhWJ.js} +7 -7
  28. package/dist/{TestEmailPanel-DpozqyHF.js → TestEmailPanel-BRisIL4G.js} +1 -1
  29. package/dist/{TitleEditor-BCBdZLt_.js → TitleEditor-lPITPzw6.js} +12 -12
  30. package/dist/{ToggleSwitch-CJfQ8u57.js → ToggleSwitch-CtZ6adlX.js} +1 -1
  31. package/dist/{Toolbar-C7SjilzH.js → Toolbar-B6dG5_IP.js} +847 -554
  32. package/dist/{TplModal-CVO-2KrU.js → TplModal-BiAf7tWe.js} +2 -2
  33. package/dist/{VersionHistoryMenu-b0A8mS2_.js → VersionHistoryMenu-DdspCRSA.js} +5 -5
  34. package/dist/{VersionHistoryPanels-BzF7dmwa.js → VersionHistoryPanels-C589Jm_B.js} +1 -1
  35. package/dist/{VersionPreviewBanner-xB9r83r0.js → VersionPreviewBanner-XUuLe36h.js} +1 -1
  36. package/dist/{WrapperBlock-BDjOn3fY.js → WrapperBlock-CVQ4t1tY.js} +4 -4
  37. package/dist/{blockTypeIcons-B0Bq1WT1.js → blockTypeIcons-Sg8SY1NQ.js} +2 -2
  38. package/dist/bundle-stats.json +6 -6
  39. package/dist/{cdn/chunks/ca-Ckgw9yd0.js → ca--zGWn9AU.js} +14 -2
  40. package/dist/cdn/chunks/{AiChatSidebar-mKImUXi6.js → AiChatSidebar-DiG-EQ-E.js} +8 -8
  41. package/dist/cdn/chunks/AiChatSidebar-DiG-EQ-E.js.map +1 -0
  42. package/dist/cdn/chunks/{AiFeatureMenu-Cx3qdStQ.js → AiFeatureMenu-BXSPgOzA.js} +5 -5
  43. package/dist/cdn/chunks/AiFeatureMenu-BXSPgOzA.js.map +1 -0
  44. package/dist/cdn/chunks/{BlockIssueBadge-DS1pUf5g.js → BlockIssueBadge-ChQ0mPf5.js} +2 -2
  45. package/dist/cdn/chunks/BlockIssueBadge-ChQ0mPf5.js.map +1 -0
  46. package/dist/cdn/chunks/{BlockPreviewCanvas-D31TNib3.js → BlockPreviewCanvas-CMmv1FTA.js} +28 -28
  47. package/dist/cdn/chunks/BlockPreviewCanvas-CMmv1FTA.js.map +1 -0
  48. package/dist/cdn/chunks/{CloudHeaderExtras-0zdlKiq7.js → CloudHeaderExtras-yvFz2_e-.js} +3 -3
  49. package/dist/cdn/chunks/CloudHeaderExtras-yvFz2_e-.js.map +1 -0
  50. package/dist/cdn/chunks/{CloudPanels-DPh71yOO.js → CloudPanels-DpKck9Na.js} +4 -4
  51. package/dist/cdn/chunks/CloudPanels-DpKck9Na.js.map +1 -0
  52. package/dist/cdn/chunks/{CollaboratorBar-lCZU8qkg.js → CollaboratorBar-Clm1ZVXQ.js} +3 -3
  53. package/dist/cdn/chunks/CollaboratorBar-Clm1ZVXQ.js.map +1 -0
  54. package/dist/cdn/chunks/{CommentsPanel-BtAGZfF6.js → CommentsPanel-CjhxGMjL.js} +2 -2
  55. package/dist/cdn/chunks/CommentsPanel-CjhxGMjL.js.map +1 -0
  56. package/dist/cdn/chunks/{CommentsSidebar-Ws07MXYj.js → CommentsSidebar-D9bqMnlt.js} +16 -16
  57. package/dist/cdn/chunks/CommentsSidebar-D9bqMnlt.js.map +1 -0
  58. package/dist/cdn/chunks/CountdownBlock-sVDjKkRw.js.map +1 -1
  59. package/dist/cdn/chunks/{CountdownToolbar-Bu93WiS8.js → CountdownToolbar-CIRx5w1U.js} +4 -4
  60. package/dist/cdn/chunks/CountdownToolbar-CIRx5w1U.js.map +1 -0
  61. package/dist/cdn/chunks/{DesignReferenceSidebar-BlSdh5B7.js → DesignReferenceSidebar-C1-SbE_R.js} +9 -9
  62. package/dist/cdn/chunks/DesignReferenceSidebar-C1-SbE_R.js.map +1 -0
  63. package/dist/cdn/chunks/{IssuesPanel-CKkv9z9g.js → IssuesPanel-qKY6UDd-.js} +8 -8
  64. package/dist/cdn/chunks/IssuesPanel-qKY6UDd-.js.map +1 -0
  65. package/dist/cdn/chunks/LoadingTrack-_7DH_5aw.js.map +1 -1
  66. package/dist/cdn/chunks/{LogicTagInsertButton-CHc1yZ9v.js → LogicTagInsertButton-CItDS_U1.js} +250 -226
  67. package/dist/cdn/chunks/LogicTagInsertButton-CItDS_U1.js.map +1 -0
  68. package/dist/cdn/chunks/{MediaEditModal-Cw9MhjVz.js → MediaEditModal-CzUtXkpk.js} +2 -2
  69. package/dist/cdn/chunks/MediaEditModal-CzUtXkpk.js.map +1 -0
  70. package/dist/cdn/chunks/{MediaPanels-FD_aX3H5.js → MediaPanels-DOLsh7WC.js} +2 -2
  71. package/dist/cdn/chunks/MediaPanels-DOLsh7WC.js.map +1 -0
  72. package/dist/cdn/chunks/{MergeTagInput--qTYfCWk.js → MergeTagInput-B33u3nxj.js} +2 -2
  73. package/dist/cdn/chunks/MergeTagInput-B33u3nxj.js.map +1 -0
  74. package/dist/cdn/chunks/{MergeTagModeToggle-CdWIGo3Q.js → MergeTagModeToggle-Bz1CH3NT.js} +10 -10
  75. package/dist/cdn/chunks/MergeTagModeToggle-Bz1CH3NT.js.map +1 -0
  76. package/dist/cdn/chunks/{ParagraphEditor-w2qEZTkM.js → ParagraphEditor-J74SIn-m.js} +51 -51
  77. package/dist/cdn/chunks/ParagraphEditor-J74SIn-m.js.map +1 -0
  78. package/dist/cdn/chunks/{RestoreVersionDialog-cnWVN3nX.js → RestoreVersionDialog-CFE7jqDB.js} +3 -3
  79. package/dist/cdn/chunks/RestoreVersionDialog-CFE7jqDB.js.map +1 -0
  80. package/dist/cdn/chunks/{RichTextEditorContent-Fzuu9pLP.js → RichTextEditorContent-dOg1xFqv.js} +5 -5
  81. package/dist/cdn/chunks/RichTextEditorContent-dOg1xFqv.js.map +1 -0
  82. package/dist/cdn/chunks/{SaveBlockDialog-jxQtKnVs.js → SaveBlockDialog-DZOmDCC8.js} +38 -38
  83. package/dist/cdn/chunks/SaveBlockDialog-DZOmDCC8.js.map +1 -0
  84. package/dist/cdn/chunks/{SavedBlocksBrowserModal-DpXWf4Pi.js → SavedBlocksBrowserModal-B43H5zKA.js} +10 -10
  85. package/dist/cdn/chunks/SavedBlocksBrowserModal-B43H5zKA.js.map +1 -0
  86. package/dist/cdn/chunks/{SavedBlocksPanels-B-ASmf1P.js → SavedBlocksPanels-uTSb2xO_.js} +2 -2
  87. package/dist/cdn/chunks/SavedBlocksPanels-uTSb2xO_.js.map +1 -0
  88. package/dist/cdn/chunks/{SavedBlocksPickBar-CEFIQ8Nd.js → SavedBlocksPickBar-BUvmGqHK.js} +3 -3
  89. package/dist/cdn/chunks/SavedBlocksPickBar-BUvmGqHK.js.map +1 -0
  90. package/dist/cdn/chunks/{TemplateScoringPanel-d_Ppowsq.js → TemplateScoringPanel-ebsrVge3.js} +19 -19
  91. package/dist/cdn/chunks/TemplateScoringPanel-ebsrVge3.js.map +1 -0
  92. package/dist/cdn/chunks/{TemplateSettings-Dr5OJ0Gi.js → TemplateSettings-BaEVdUTM.js} +9 -9
  93. package/dist/cdn/chunks/TemplateSettings-BaEVdUTM.js.map +1 -0
  94. package/dist/cdn/chunks/{TestEmailModal-CrjzVw8e.js → TestEmailModal-ide7UP_H.js} +7 -7
  95. package/dist/cdn/chunks/TestEmailModal-ide7UP_H.js.map +1 -0
  96. package/dist/cdn/chunks/{TestEmailPanel-k9vdulTu.js → TestEmailPanel-Cqdsnufx.js} +2 -2
  97. package/dist/cdn/chunks/TestEmailPanel-Cqdsnufx.js.map +1 -0
  98. package/dist/cdn/chunks/{TitleEditor-laILWfKh.js → TitleEditor-CoFzxLPA.js} +16 -16
  99. package/dist/cdn/chunks/TitleEditor-CoFzxLPA.js.map +1 -0
  100. package/dist/cdn/chunks/{ToggleSwitch-0dGCYnRY.js → ToggleSwitch-D-8dCEbI.js} +2 -2
  101. package/dist/cdn/chunks/ToggleSwitch-D-8dCEbI.js.map +1 -0
  102. package/dist/cdn/chunks/{Toolbar-BsiHW9gY.js → Toolbar-BDzhrmGV.js} +814 -566
  103. package/dist/cdn/chunks/Toolbar-BDzhrmGV.js.map +1 -0
  104. package/dist/cdn/chunks/{TplModal-D8DoPbFa.js → TplModal-mLMmolQp.js} +3 -3
  105. package/dist/cdn/chunks/TplModal-mLMmolQp.js.map +1 -0
  106. package/dist/cdn/chunks/{VersionHistoryMenu-B3-hNu9c.js → VersionHistoryMenu-C_bBKOYU.js} +7 -7
  107. package/dist/cdn/chunks/VersionHistoryMenu-C_bBKOYU.js.map +1 -0
  108. package/dist/cdn/chunks/{VersionHistoryPanels-zw1AtzGN.js → VersionHistoryPanels-B9LwOKxm.js} +2 -2
  109. package/dist/cdn/chunks/VersionHistoryPanels-B9LwOKxm.js.map +1 -0
  110. package/dist/cdn/chunks/{VersionPreviewBanner-PzVQSBJE.js → VersionPreviewBanner-CKyrcgxJ.js} +2 -2
  111. package/dist/cdn/chunks/VersionPreviewBanner-CKyrcgxJ.js.map +1 -0
  112. package/dist/cdn/chunks/{WrapperBlock-CpRvfAV0.js → WrapperBlock-DI8vSvTO.js} +4 -4
  113. package/dist/cdn/chunks/WrapperBlock-DI8vSvTO.js.map +1 -0
  114. package/dist/cdn/chunks/blockTypeIcons-CdfCfqHE.js +21 -0
  115. package/dist/cdn/chunks/blockTypeIcons-CdfCfqHE.js.map +1 -0
  116. package/dist/{ca-Ckgw9yd0.js → cdn/chunks/ca--zGWn9AU.js} +16 -0
  117. package/dist/cdn/chunks/ca--zGWn9AU.js.map +1 -0
  118. package/dist/cdn/chunks/ca-BTf1Zbqb.js.map +1 -1
  119. package/dist/cdn/chunks/{cloud-CIT4yPp4.js → cloud-De-eh1u6.js} +2 -2
  120. package/dist/cdn/chunks/cloud-De-eh1u6.js.map +1 -0
  121. package/dist/cdn/chunks/{createCloudRuntime-COUxbPvd.js → createCloudRuntime-DsaUaWvr.js} +3 -3
  122. package/dist/cdn/chunks/createCloudRuntime-DsaUaWvr.js.map +1 -0
  123. package/dist/cdn/chunks/{de-D4dweQw8.js → de-BRNLKcDl.js} +15 -1
  124. package/dist/cdn/chunks/de-BRNLKcDl.js.map +1 -0
  125. package/dist/cdn/chunks/de-mMY5yQJu.js.map +1 -1
  126. package/dist/cdn/chunks/de-xzrh9PA3.js.map +1 -1
  127. package/dist/cdn/chunks/dist-BRZhN8qJ.js.map +1 -1
  128. package/dist/cdn/chunks/dist-CXB2_kBa.js.map +1 -1
  129. package/dist/cdn/chunks/draggable-IB4x6w2O.js.map +1 -1
  130. package/dist/cdn/chunks/{editor-modal-CKu8HhiB.js → editor-modal-CZQArGNj.js} +88 -88
  131. package/dist/cdn/chunks/editor-modal-CZQArGNj.js.map +1 -0
  132. package/dist/cdn/chunks/emojiData-6m0DBh7O.js.map +1 -1
  133. package/dist/cdn/chunks/en-9unxBjV8.js +2 -0
  134. package/dist/cdn/chunks/en-ChVeGQBY.js.map +1 -1
  135. package/dist/{en-VE7R7NyL.js → cdn/chunks/en-JJjqHMjy.js} +16 -0
  136. package/dist/cdn/chunks/en-JJjqHMjy.js.map +1 -0
  137. package/dist/cdn/chunks/{es-B9OhP8H3.js → es-BIh8BxV9.js} +15 -1
  138. package/dist/cdn/chunks/es-BIh8BxV9.js.map +1 -0
  139. package/dist/cdn/chunks/es-BT4LSpE2.js.map +1 -1
  140. package/dist/cdn/chunks/{extensions-CafoGF65.js → extensions-Dy251lPd.js} +5 -5
  141. package/dist/cdn/chunks/extensions-Dy251lPd.js.map +1 -0
  142. package/dist/cdn/chunks/formatAbsoluteDateTime-DMmop3C-.js.map +1 -1
  143. package/dist/cdn/chunks/formatRelativeTime-CtUU-QZ8.js.map +1 -1
  144. package/dist/{fr-wrXhIi00.js → cdn/chunks/fr-C5VUZogP.js} +16 -0
  145. package/dist/cdn/chunks/fr-C5VUZogP.js.map +1 -0
  146. package/dist/cdn/chunks/fr-CI7OJoql.js.map +1 -1
  147. package/dist/cdn/chunks/htmlparser-ClUZ6waR.js.map +1 -1
  148. package/dist/cdn/chunks/{icons-BKkJ-5xF.js → icons-CQnjugjy.js} +86 -45
  149. package/dist/cdn/chunks/icons-CQnjugjy.js.map +1 -0
  150. package/dist/cdn/chunks/ja-DhlWUfke.js.map +1 -1
  151. package/dist/cdn/chunks/{ja-fKnVWXHC.js → ja-x5JYxaCW.js} +15 -1
  152. package/dist/cdn/chunks/ja-x5JYxaCW.js.map +1 -0
  153. package/dist/cdn/chunks/keys-DCWeHkSF.js.map +1 -1
  154. package/dist/cdn/chunks/liquid.browser-BypTT2oc.js.map +1 -1
  155. package/dist/cdn/chunks/logger-ByvdoAwq.js.map +1 -1
  156. package/dist/cdn/chunks/nl-D8y5OWGB.js.map +1 -1
  157. package/dist/cdn/chunks/{nl-DeFatKJe.js → nl-UXxFyXV6.js} +15 -1
  158. package/dist/cdn/chunks/nl-UXxFyXV6.js.map +1 -0
  159. package/dist/cdn/chunks/{preRenderCustomBlocks-Dpj-_cOj.js → preRenderCustomBlocks-h4ZFBKbD.js} +2 -2
  160. package/dist/cdn/chunks/preRenderCustomBlocks-h4ZFBKbD.js.map +1 -0
  161. package/dist/cdn/chunks/pt-BR-CoCwRUi0.js.map +1 -1
  162. package/dist/{pt-BR-Bh1J8ey6.js → cdn/chunks/pt-BR-DHm3SP6W.js} +16 -0
  163. package/dist/cdn/chunks/pt-BR-DHm3SP6W.js.map +1 -0
  164. package/dist/cdn/chunks/pt-BR-DMCbUBvJ.js.map +1 -1
  165. package/dist/cdn/chunks/pusher-BbIHJKf3.js.map +1 -1
  166. package/dist/cdn/chunks/readableTextColor-f8Kykfnh.js.map +1 -1
  167. package/dist/cdn/chunks/{socialIcons-BvYNMn1G.js → socialIcons-ZOCwCCyn.js} +3 -3
  168. package/dist/cdn/chunks/socialIcons-ZOCwCCyn.js.map +1 -0
  169. package/dist/cdn/chunks/{src-DveVYoWS.js → src-BR3I3gOW.js} +265 -224
  170. package/dist/cdn/chunks/src-BR3I3gOW.js.map +1 -0
  171. package/dist/cdn/chunks/{src-Cnc5E71L.js → src-fZSLjhjy.js} +12 -12
  172. package/dist/cdn/chunks/src-fZSLjhjy.js.map +1 -0
  173. package/dist/cdn/chunks/{src-L6HEdwFn.js → src-nhIF5-mf.js} +179 -166
  174. package/dist/cdn/chunks/src-nhIF5-mf.js.map +1 -0
  175. package/dist/cdn/chunks/styleConstants-C_YAPdQS.js.map +1 -1
  176. package/dist/cdn/chunks/templateSettingsFields-YCFVBVYh.js.map +1 -1
  177. package/dist/cdn/chunks/timeouts-DHPZQ0G3.js.map +1 -1
  178. package/dist/cdn/chunks/{tiptap-DhLuKyDc.js → tiptap-D1u8JIUW.js} +1916 -1917
  179. package/dist/cdn/chunks/tiptap-D1u8JIUW.js.map +1 -0
  180. package/dist/cdn/chunks/useAliveFlag-DAlQLbM2.js.map +1 -1
  181. package/dist/cdn/chunks/useCloudI18n-CrjWbpbu.js.map +1 -1
  182. package/dist/cdn/chunks/{useEditorCore-DZmtKwJh.js → useEditorCore-D4kzTMtQ.js} +458 -446
  183. package/dist/cdn/chunks/useEditorCore-D4kzTMtQ.js.map +1 -0
  184. package/dist/cdn/chunks/useEditorRoot-CshefZLP.js.map +1 -1
  185. package/dist/cdn/chunks/useI18n-CyO_Nmca.js.map +1 -1
  186. package/dist/cdn/chunks/{useLogicTag-DF7-l66G.js → useLogicTag-J_i_hvZg.js} +2 -2
  187. package/dist/cdn/chunks/useLogicTag-J_i_hvZg.js.map +1 -0
  188. package/dist/cdn/chunks/{useMergeTag-DbIHw4NG.js → useMergeTag-C5MyHYxJ.js} +2 -2
  189. package/dist/cdn/chunks/useMergeTag-C5MyHYxJ.js.map +1 -0
  190. package/dist/cdn/chunks/{usePopoverPosition-BJRvAb-h.js → usePopoverPosition-DGXjXKjM.js} +25 -12
  191. package/dist/cdn/chunks/usePopoverPosition-DGXjXKjM.js.map +1 -0
  192. package/dist/cdn/chunks/useScrollToBlock-DgHZJvID.js.map +1 -1
  193. package/dist/cdn/editor.css +1 -1
  194. package/dist/cdn/editor.js +493 -464
  195. package/dist/cdn/editor.js.map +1 -1
  196. package/dist/{check-eqb2JhqU.js → check-BMx_TLAS.js} +1 -1
  197. package/dist/{chevron-down-Dkr-7Ywl.js → chevron-down-KZf5mh9_.js} +1 -1
  198. package/dist/{chevron-right-Bge4XF_B.js → chevron-right-BLZ60Vxw.js} +1 -1
  199. package/dist/{chevron-up-CQAyl0kC.js → chevron-up-B9ynB8eU.js} +1 -1
  200. package/dist/{circle-alert-CYgTHKWr.js → circle-alert-pjvFFDrF.js} +1 -1
  201. package/dist/{clock-BgSJZJP5.js → clock-CiiTBfF3.js} +1 -1
  202. package/dist/{cloud-DsqqUfzh.js → cloud-AO_X8T9g.js} +1 -1
  203. package/dist/{copy-mw6PVnOJ.js → copy-BF0_pQjH.js} +1 -1
  204. package/dist/{createCloudRuntime-iLflkYzP.js → createCloudRuntime-D641nhri.js} +2 -2
  205. package/dist/{createLucideIcon-BxY5yz5u.js → createLucideIcon-C2YOVVWx.js} +8 -8
  206. package/dist/{de-D4dweQw8.js → de-BRNLKcDl.js} +14 -0
  207. package/dist/{dist-CQSVro7b.js → dist-B0dkvy7z.js} +1 -1
  208. package/dist/{dist-BJM3eFyT.js → dist-BPWuzECC.js} +1 -1
  209. package/dist/{dist-EDkj3Ub1.js → dist-BUHovM4k.js} +1 -1
  210. package/dist/{dist-BmsLcnrO.js → dist-BwoEME8p.js} +1 -1
  211. package/dist/{dist-DerFNpDY.js → dist-C2Ge44fD.js} +760 -761
  212. package/dist/{dist-BdHF7nyq.js → dist-CIxmOOSG.js} +5 -5
  213. package/dist/{dist-wyXxj3R1.js → dist-CJ7RZARo.js} +1 -1
  214. package/dist/{dist-Bl4rxpX9.js → dist-CxmLZQso.js} +1 -1
  215. package/dist/{dist-DyrEOKEJ.js → dist-DRmafAUz.js} +1 -1
  216. package/dist/{dist-Djmzp6wi.js → dist-DdOAotfz.js} +1 -1
  217. package/dist/{dist-BxVnMgXZ.js → dist-W_ERo6c_.js} +1 -1
  218. package/dist/{dist-DbUZvK04.js → dist-iLUVPysa.js} +263 -222
  219. package/dist/{dist-DQbOebGW.js → dist-p-LkiWIQ.js} +1 -1
  220. package/dist/{editor-modal-qzmEVcIk.js → editor-modal-99FB40dl.js} +16 -16
  221. package/dist/en-BvOjRLiw.js +2 -0
  222. package/dist/{cdn/chunks/en-VE7R7NyL.js → en-JJjqHMjy.js} +14 -2
  223. package/dist/{es-B9OhP8H3.js → es-BIh8BxV9.js} +14 -0
  224. package/dist/{extensions-DDhjuVKy.js → extensions-DqQXxrvP.js} +13 -13
  225. package/dist/{eye-DphkRtAD.js → eye-RdXYgrQZ.js} +1 -1
  226. package/dist/{cdn/chunks/fr-wrXhIi00.js → fr-C5VUZogP.js} +14 -2
  227. package/dist/{image-up-Qi2BXD7T.js → image-up-BwdoReQt.js} +1 -1
  228. package/dist/{info-VSyAs02q.js → info-zFMSGrL1.js} +1 -1
  229. package/dist/{ja-fKnVWXHC.js → ja-x5JYxaCW.js} +14 -0
  230. package/dist/{link-CNuozGqD.js → link-D7orqFBT.js} +1 -1
  231. package/dist/{list-BA0I5Wmu.js → list-BGt4Pgxc.js} +1 -1
  232. package/dist/{loader-circle-z5eeqasv.js → loader-circle-BVBgkRGz.js} +1 -1
  233. package/dist/{message-circle-BsQ9hEup.js → message-circle-D8YLsarv.js} +1 -1
  234. package/dist/{nl-DeFatKJe.js → nl-UXxFyXV6.js} +14 -0
  235. package/dist/{package-OkXfuRoO.js → package-CuFvk0L5.js} +1 -1
  236. package/dist/{pencil-DFVFA7Dj.js → pencil-DRYbmZW7.js} +1 -1
  237. package/dist/{plus-D8bkVjZ7.js → plus-Dv0b3kh0.js} +1 -1
  238. package/dist/{preRenderCustomBlocks-BBSqQgke.js → preRenderCustomBlocks-CTstI3Q-.js} +4 -4
  239. package/dist/{cdn/chunks/pt-BR-Bh1J8ey6.js → pt-BR-DHm3SP6W.js} +14 -2
  240. package/dist/{refresh-cw-DPB7YFuz.js → refresh-cw-gYTIS5bJ.js} +1 -1
  241. package/dist/{search-C-dCgqIa.js → search-D84_Ki_a.js} +1 -1
  242. package/dist/{send-Cm2fy2zm.js → send-Cn-8_H_U.js} +1 -1
  243. package/dist/{shield-check-COgBYFDF.js → shield-check-BOoVWJtD.js} +1 -1
  244. package/dist/{smartphone-v0u_MOEV.js → smartphone-4Ej3PBw5.js} +1 -1
  245. package/dist/{socialIcons-O7PZCW2P.js → socialIcons-CzRJskEk.js} +47 -47
  246. package/dist/{sparkles-Ds0RF8Iu.js → sparkles-D3vnNe7O.js} +1 -1
  247. package/dist/style.css +1 -1
  248. package/dist/templatical-editor.js +432 -403
  249. package/dist/{text-align-start-DiavaIm6.js → text-align-start-Ci2h_Xly.js} +1 -1
  250. package/dist/{trash-DnOkfu2V.js → trash-wmi4UKvv.js} +1 -1
  251. package/dist/{triangle-alert-DGLAyXnh.js → triangle-alert-DJ0r2wmQ.js} +1 -1
  252. package/dist/{upload-BBDme2cy.js → upload-XMde-TXf.js} +1 -1
  253. package/dist/{useEditorCore-dcdHB_7H.js → useEditorCore-Dhit8Ygg.js} +894 -882
  254. package/dist/{useLogicTag-D9pvgxQR.js → useLogicTag-BaH8gey0.js} +1 -1
  255. package/dist/{useMergeTag-BaVFPdlq.js → useMergeTag-Cyad1yBE.js} +1 -1
  256. package/dist/{usePopoverPosition-DH7z3Ghm.js → usePopoverPosition-BYmd-lhR.js} +24 -11
  257. package/dist/{useScrollToBlock-Dj4v3rxr.js → useScrollToBlock-B4F7KCrf.js} +1 -1
  258. package/dist/{x-3BHV3Q6K.js → x-BWrtpVl-.js} +1 -1
  259. package/package.json +10 -10
  260. package/dist/cdn/chunks/AiChatSidebar-mKImUXi6.js.map +0 -1
  261. package/dist/cdn/chunks/AiFeatureMenu-Cx3qdStQ.js.map +0 -1
  262. package/dist/cdn/chunks/BlockIssueBadge-DS1pUf5g.js.map +0 -1
  263. package/dist/cdn/chunks/BlockPreviewCanvas-D31TNib3.js.map +0 -1
  264. package/dist/cdn/chunks/CloudHeaderExtras-0zdlKiq7.js.map +0 -1
  265. package/dist/cdn/chunks/CloudPanels-DPh71yOO.js.map +0 -1
  266. package/dist/cdn/chunks/CollaboratorBar-lCZU8qkg.js.map +0 -1
  267. package/dist/cdn/chunks/CommentsPanel-BtAGZfF6.js.map +0 -1
  268. package/dist/cdn/chunks/CommentsSidebar-Ws07MXYj.js.map +0 -1
  269. package/dist/cdn/chunks/CountdownToolbar-Bu93WiS8.js.map +0 -1
  270. package/dist/cdn/chunks/DesignReferenceSidebar-BlSdh5B7.js.map +0 -1
  271. package/dist/cdn/chunks/IssuesPanel-CKkv9z9g.js.map +0 -1
  272. package/dist/cdn/chunks/LogicTagInsertButton-CHc1yZ9v.js.map +0 -1
  273. package/dist/cdn/chunks/MediaEditModal-Cw9MhjVz.js.map +0 -1
  274. package/dist/cdn/chunks/MediaPanels-FD_aX3H5.js.map +0 -1
  275. package/dist/cdn/chunks/MergeTagInput--qTYfCWk.js.map +0 -1
  276. package/dist/cdn/chunks/MergeTagModeToggle-CdWIGo3Q.js.map +0 -1
  277. package/dist/cdn/chunks/ParagraphEditor-w2qEZTkM.js.map +0 -1
  278. package/dist/cdn/chunks/RestoreVersionDialog-cnWVN3nX.js.map +0 -1
  279. package/dist/cdn/chunks/RichTextEditorContent-Fzuu9pLP.js.map +0 -1
  280. package/dist/cdn/chunks/SaveBlockDialog-jxQtKnVs.js.map +0 -1
  281. package/dist/cdn/chunks/SavedBlocksBrowserModal-DpXWf4Pi.js.map +0 -1
  282. package/dist/cdn/chunks/SavedBlocksPanels-B-ASmf1P.js.map +0 -1
  283. package/dist/cdn/chunks/SavedBlocksPickBar-CEFIQ8Nd.js.map +0 -1
  284. package/dist/cdn/chunks/TemplateScoringPanel-d_Ppowsq.js.map +0 -1
  285. package/dist/cdn/chunks/TemplateSettings-Dr5OJ0Gi.js.map +0 -1
  286. package/dist/cdn/chunks/TestEmailModal-CrjzVw8e.js.map +0 -1
  287. package/dist/cdn/chunks/TestEmailPanel-k9vdulTu.js.map +0 -1
  288. package/dist/cdn/chunks/TitleEditor-laILWfKh.js.map +0 -1
  289. package/dist/cdn/chunks/ToggleSwitch-0dGCYnRY.js.map +0 -1
  290. package/dist/cdn/chunks/Toolbar-BsiHW9gY.js.map +0 -1
  291. package/dist/cdn/chunks/TplModal-D8DoPbFa.js.map +0 -1
  292. package/dist/cdn/chunks/VersionHistoryMenu-B3-hNu9c.js.map +0 -1
  293. package/dist/cdn/chunks/VersionHistoryPanels-zw1AtzGN.js.map +0 -1
  294. package/dist/cdn/chunks/VersionPreviewBanner-PzVQSBJE.js.map +0 -1
  295. package/dist/cdn/chunks/WrapperBlock-CpRvfAV0.js.map +0 -1
  296. package/dist/cdn/chunks/blockTypeIcons-raBjStuv.js +0 -21
  297. package/dist/cdn/chunks/blockTypeIcons-raBjStuv.js.map +0 -1
  298. package/dist/cdn/chunks/ca-Ckgw9yd0.js.map +0 -1
  299. package/dist/cdn/chunks/cloud-CIT4yPp4.js.map +0 -1
  300. package/dist/cdn/chunks/createCloudRuntime-COUxbPvd.js.map +0 -1
  301. package/dist/cdn/chunks/de-D4dweQw8.js.map +0 -1
  302. package/dist/cdn/chunks/editor-modal-CKu8HhiB.js.map +0 -1
  303. package/dist/cdn/chunks/en-DqzAdO8F.js +0 -2
  304. package/dist/cdn/chunks/en-VE7R7NyL.js.map +0 -1
  305. package/dist/cdn/chunks/es-B9OhP8H3.js.map +0 -1
  306. package/dist/cdn/chunks/extensions-CafoGF65.js.map +0 -1
  307. package/dist/cdn/chunks/fr-wrXhIi00.js.map +0 -1
  308. package/dist/cdn/chunks/icons-BKkJ-5xF.js.map +0 -1
  309. package/dist/cdn/chunks/ja-fKnVWXHC.js.map +0 -1
  310. package/dist/cdn/chunks/nl-DeFatKJe.js.map +0 -1
  311. package/dist/cdn/chunks/preRenderCustomBlocks-Dpj-_cOj.js.map +0 -1
  312. package/dist/cdn/chunks/pt-BR-Bh1J8ey6.js.map +0 -1
  313. package/dist/cdn/chunks/socialIcons-BvYNMn1G.js.map +0 -1
  314. package/dist/cdn/chunks/src-Cnc5E71L.js.map +0 -1
  315. package/dist/cdn/chunks/src-DveVYoWS.js.map +0 -1
  316. package/dist/cdn/chunks/src-L6HEdwFn.js.map +0 -1
  317. package/dist/cdn/chunks/tiptap-DhLuKyDc.js.map +0 -1
  318. package/dist/cdn/chunks/useEditorCore-DZmtKwJh.js.map +0 -1
  319. package/dist/cdn/chunks/useLogicTag-DF7-l66G.js.map +0 -1
  320. package/dist/cdn/chunks/useMergeTag-DbIHw4NG.js.map +0 -1
  321. package/dist/cdn/chunks/usePopoverPosition-BJRvAb-h.js.map +0 -1
  322. package/dist/en-1tgLzB8q.js +0 -2
@@ -1,8 +1,8 @@
1
1
  import { A as e, At as t, B as n, N as r, S as i, Z as a, at as o, c as s, d as c, g as l, i as u, l as d, s as f, u as p, v as m } from "./vue.runtime.esm-bundler-CyqhBwpY.js";
2
2
  import { c as h, t as g } from "./runtime-dom.esm-bundler-BGbPz4-g.js";
3
- import { T as _ } from "./useEditorCore-dcdHB_7H.js";
3
+ import { x as _ } from "./useEditorCore-Dhit8Ygg.js";
4
4
  import { J as v, Z as y } from "./keys-CDqfZIRt.js";
5
- import { n as b } from "./usePopoverPosition-DH7z3Ghm.js";
5
+ import { n as b } from "./usePopoverPosition-BYmd-lhR.js";
6
6
  //#region src/components/TplModal.vue?vue&type=script&setup=true&lang.ts
7
7
  var x = ["data-tpl-theme"], S = /* @__PURE__ */ m({
8
8
  __name: "TplModal",
@@ -3,11 +3,11 @@ import { c as g, t as _ } from "./runtime-dom.esm-bundler-BGbPz4-g.js";
3
3
  import { t as v } from "./dist-BDuPwOyn.js";
4
4
  import { X as y } from "./keys-CDqfZIRt.js";
5
5
  import { t as b } from "./useI18n-B_CdcBwG.js";
6
- import { t as x } from "./createLucideIcon-BxY5yz5u.js";
7
- import { t as S } from "./chevron-down-Dkr-7Ywl.js";
8
- import { t as C } from "./chevron-right-Bge4XF_B.js";
9
- import { t as w } from "./clock-BgSJZJP5.js";
10
- import { t as ee } from "./loader-circle-z5eeqasv.js";
6
+ import { t as x } from "./createLucideIcon-C2YOVVWx.js";
7
+ import { t as S } from "./chevron-down-KZf5mh9_.js";
8
+ import { t as C } from "./chevron-right-BLZ60Vxw.js";
9
+ import { t as w } from "./clock-CiiTBfF3.js";
10
+ import { t as ee } from "./loader-circle-BVBgkRGz.js";
11
11
  import { t as T } from "./formatAbsoluteDateTime-DMmop3C-.js";
12
12
  import { t as E } from "./formatRelativeTime-CtUU-QZ8.js";
13
13
  var D = x({
@@ -5,7 +5,7 @@ var c = /* @__PURE__ */ s({
5
5
  __name: "VersionHistoryPanels",
6
6
  props: { feature: {} },
7
7
  setup(s) {
8
- let c = s, l = t(() => import("./VersionPreviewBanner-xB9r83r0.js")), u = t(() => import("./RestoreVersionDialog-DHb1mPoF.js"));
8
+ let c = s, l = t(() => import("./VersionPreviewBanner-XUuLe36h.js")), u = t(() => import("./RestoreVersionDialog-DE8aqmdi.js"));
9
9
  async function d() {
10
10
  try {
11
11
  await c.feature.requestRestore();
@@ -1,6 +1,6 @@
1
1
  import { A as e, at as t, c as n, d as r, g as i, jt as a, kt as o, u as s, v as c } from "./vue.runtime.esm-bundler-CyqhBwpY.js";
2
2
  import { t as l } from "./useI18n-B_CdcBwG.js";
3
- import { t as u } from "./clock-BgSJZJP5.js";
3
+ import { t as u } from "./clock-CiiTBfF3.js";
4
4
  import { f as d, v as f } from "./styleConstants-C_YAPdQS.js";
5
5
  //#region src/components/VersionPreviewBanner.vue?vue&type=script&setup=true&lang.ts
6
6
  var p = {
@@ -1,5 +1,5 @@
1
1
  import { A as e, At as t, F as n, M as r, S as i, at as a, d as o, l as s, r as c, s as l, v as u } from "./vue.runtime.esm-bundler-CyqhBwpY.js";
2
- import { f as d, p as f, u as p } from "./useEditorCore-dcdHB_7H.js";
2
+ import { A as d, D as f, k as p } from "./useEditorCore-Dhit8Ygg.js";
3
3
  import { s as m } from "./keys-CDqfZIRt.js";
4
4
  function h(e, t = "desktop") {
5
5
  return t === "mobile" ? 375 : e?.width ?? 600;
@@ -12,9 +12,9 @@ var g = "width 300ms cubic-bezier(0.34, 1.56, 0.64, 1)", _ = ["data-block-id"],
12
12
  viewport: {}
13
13
  },
14
14
  setup(u) {
15
- let h = u, g = i(m, null), v = l(() => d(h.block) ?? {});
15
+ let h = u, g = i(m, null), v = l(() => p(h.block) ?? {});
16
16
  function y(e) {
17
- return f(e, g, {});
17
+ return d(e, g, {});
18
18
  }
19
19
  return (i, l) => (e(), o("div", {
20
20
  "data-testid": "layout-wrapper",
@@ -23,7 +23,7 @@ var g = "width 300ms cubic-bezier(0.34, 1.56, 0.64, 1)", _ = ["data-block-id"],
23
23
  }, [(e(!0), o(c, null, r(u.block.children, (r) => (e(), o("div", {
24
24
  key: r.id,
25
25
  "data-block-id": r.id,
26
- style: t(a(p)(r))
26
+ style: t(a(f)(r))
27
27
  }, [(e(), s(n(y(r)), {
28
28
  block: r,
29
29
  viewport: u.viewport
@@ -1,5 +1,5 @@
1
- import { a as e, c as t, l as n, o as r, s as i } from "./socialIcons-O7PZCW2P.js";
2
- import { t as a } from "./createLucideIcon-BxY5yz5u.js";
1
+ import { a as e, c as t, l as n, o as r, s as i } from "./socialIcons-CzRJskEk.js";
2
+ import { t as a } from "./createLucideIcon-C2YOVVWx.js";
3
3
  var o = a({
4
4
  name: "columns-3",
5
5
  size: 24,
@@ -1,10 +1,10 @@
1
1
  {
2
- "version": "0.41.0",
3
- "initialGzipBytes": 175519,
4
- "initialRawBytes": 585077,
2
+ "version": "0.42.1",
3
+ "initialGzipBytes": 176576,
4
+ "initialRawBytes": 587937,
5
5
  "initialFileCount": 48,
6
- "lazyGzipBytes": 424844,
7
- "lazyRawBytes": 1497600,
6
+ "lazyGzipBytes": 427758,
7
+ "lazyRawBytes": 1510742,
8
8
  "lazyFileCount": 84,
9
- "generatedAt": "2026-09-25T07:08:00.122Z"
9
+ "generatedAt": "2026-09-29T07:48:42.066Z"
10
10
  }
@@ -359,6 +359,19 @@ var e = {
359
359
  spacing: "Espaiat",
360
360
  padding: "Farciment",
361
361
  background: "Fons",
362
+ borderWidth: "Amplada de la vora",
363
+ borderStyle: "Estil de la vora",
364
+ borderColor: "Color de la vora",
365
+ border: "Vora",
366
+ borderSide: "Costat",
367
+ linkSides: "La mateixa vora a tots els costats",
368
+ unlinkSides: "Defineix cada costat per separat",
369
+ linkCorners: "El mateix radi a totes les cantonades",
370
+ unlinkCorners: "Defineix cada cantonada per separat",
371
+ cornerTopLeft: "A dalt a l'esquerra",
372
+ cornerTopRight: "A dalt a la dreta",
373
+ cornerBottomRight: "A baix a la dreta",
374
+ cornerBottomLeft: "A baix a l'esquerra",
362
375
  color: "Color",
363
376
  display: "Visualització",
364
377
  showOnDesktop: "Mostra a l'escriptori",
@@ -422,6 +435,7 @@ var e = {
422
435
  hexValue: "Valor del color en Hex",
423
436
  notSet: "No definit",
424
437
  clear: "Neteja el color",
438
+ transparent: "Transparent",
425
439
  presetColors: "Colors predefinits"
426
440
  },
427
441
  mergeTag: {
@@ -621,5 +635,3 @@ var e = {
621
635
  };
622
636
  //#endregion
623
637
  export { e as default };
624
-
625
- //# sourceMappingURL=ca-Ckgw9yd0.js.map
@@ -1,11 +1,11 @@
1
1
  import { B as e, E as t, F as n, H as r, N as i, Q as a, S as o, U as ee, at as s, b as c, ct as te, g as l, h as u, k as ne, m as d, n as re, o as ie, p as f, u as p, ut as m, y as h } from "./draggable-IB4x6w2O.js";
2
2
  import { _ as g, g as ae } from "./dist-BRZhN8qJ.js";
3
3
  import { $ as _, F as oe, O as se, g as ce, i as le, u as ue } from "./keys-DCWeHkSF.js";
4
- import { B as de, E as v, M as fe, Mt as pe, d as me, it as y, l as b, n as x } from "./icons-BKkJ-5xF.js";
4
+ import { D as v, N as de, Nt as fe, V as pe, at as me, f as y, l as b, n as x } from "./icons-CQnjugjy.js";
5
5
  import { t as S } from "./LoadingTrack-_7DH_5aw.js";
6
6
  import { t as C } from "./_plugin-vue_export-helper-B3ysoDQm.js";
7
7
  import { t as w } from "./useAliveFlag-DAlQLbM2.js";
8
- import { b as T } from "./cloud-CIT4yPp4.js";
8
+ import { b as T } from "./cloud-De-eh1u6.js";
9
9
  //#region src/cloud/components/AiChatSidebar.vue?vue&type=script&setup=true&lang.ts
10
10
  var E = ["aria-label"], D = { class: "tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3" }, O = { class: "tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]" }, k = { class: "tpl:flex tpl:items-center tpl:gap-1" }, A = ["aria-label", "title"], j = ["aria-label"], M = { class: "tpl:relative tpl:flex tpl:min-h-0 tpl:flex-1 tpl:flex-col" }, N = {
11
11
  key: 0,
@@ -122,7 +122,7 @@ var E = ["aria-label"], D = { class: "tpl:flex tpl:items-center tpl:justify-betw
122
122
  "aria-label": s(V).aiChat.clear,
123
123
  title: s(V).aiChat.clear,
124
124
  onClick: t[0] ||= (e) => s(G).clearChat()
125
- }, [c(s(me), {
125
+ }, [c(s(y), {
126
126
  size: 14,
127
127
  "stroke-width": 2
128
128
  })], 8, A)) : u("", !0), f("button", {
@@ -139,7 +139,7 @@ var E = ["aria-label"], D = { class: "tpl:flex tpl:items-center tpl:justify-betw
139
139
  ref_key: "messagesContainer",
140
140
  ref: q,
141
141
  class: "tpl:flex-1 tpl:overflow-y-auto tpl:p-4"
142
- }, [s(G).isLoadingHistory.value ? (i(), l("div", N, [c(s(y), {
142
+ }, [s(G).isLoadingHistory.value ? (i(), l("div", N, [c(s(me), {
143
143
  class: "tpl-spinner tpl:text-[var(--tpl-text-muted)]",
144
144
  size: 24,
145
145
  "stroke-width": 2
@@ -159,14 +159,14 @@ var E = ["aria-label"], D = { class: "tpl:flex tpl:items-center tpl:justify-betw
159
159
  "background-color": "transparent"
160
160
  },
161
161
  onClick: t[2] ||= (e) => s(G).toggleLastRevert()
162
- }, [s(G).isLastChangeReverted.value ? (i(), l(p, { key: 0 }, [c(s(de), {
162
+ }, [s(G).isLastChangeReverted.value ? (i(), l(p, { key: 0 }, [c(s(pe), {
163
163
  size: 12,
164
164
  "stroke-width": 2
165
165
  }), h(" " + m(s(V).aiChat.reapply), 1)], 64)) : (i(), l(p, { key: 1 }, [c(s(b), {
166
166
  size: 12,
167
167
  "stroke-width": 2
168
168
  }), h(" " + m(s(V).aiChat.revert), 1)], 64))])) : u("", !0)]))]))), 128))]))], 512),
169
- s(G).error.value ? (i(), l("div", ge, [c(s(pe), {
169
+ s(G).error.value ? (i(), l("div", ge, [c(s(fe), {
170
170
  size: 14,
171
171
  "stroke-width": 2,
172
172
  class: "tpl:mt-0.5 tpl:shrink-0"
@@ -194,7 +194,7 @@ var E = ["aria-label"], D = { class: "tpl:flex tpl:items-center tpl:justify-betw
194
194
  class: "tpl-ai-send-btn tpl:flex tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-md tpl:p-1.5 tpl:transition-all tpl:disabled:opacity-40 tpl:text-[var(--tpl-primary)]",
195
195
  disabled: !K.value.trim() || s(G).isGenerating.value,
196
196
  onClick: Q
197
- }, [c(s(fe), {
197
+ }, [c(s(de), {
198
198
  size: 16,
199
199
  "stroke-width": 2
200
200
  })], 8, Ce)]), f("p", we, m(s(V).aiMenu.disclaimer), 1)])
@@ -206,4 +206,4 @@ var E = ["aria-label"], D = { class: "tpl:flex tpl:items-center tpl:justify-betw
206
206
  //#endregion
207
207
  export { B as default };
208
208
 
209
- //# sourceMappingURL=AiChatSidebar-mKImUXi6.js.map
209
+ //# sourceMappingURL=AiChatSidebar-DiG-EQ-E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiChatSidebar-DiG-EQ-E.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementBlock","_unref","_createElementVNode","_createVNode","_toDisplayString","Trash2","_createCommentVNode","_Fragment","_renderList","LoadingTrack","_createTextVNode","_normalizeClass","_withDirectives","_vModelText","_sfc_main","watch","inject","renderList","withCtx","openBlock","ref","defineComponent","withDirectives","unref","createVNode","normalizeClass","createElementBlock","createCommentVNode","nextTick","createBlock","Transition","vModelText","createBaseVNode","Fragment","toDisplayString","createTextVNode","useTimeoutFn","useIntervalFn","requireInject","NO_MERGE_TAGS","MERGE_TAGS_KEY","EDITOR_KEY","AUTH_MANAGER_KEY","CLOUD_TRANSLATIONS_KEY","Sparkles","Send","CircleAlert","Redo2","LoaderCircle","Trash","Undo2","X","LoadingTrack_default","_plugin_vue_export_helper_default","useAliveFlag","useAiChat","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","\"color\"","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","AiChatSidebar_default","__emit","props","__props","emit","cloudTranslations","editor","authManager","mergeTags","aliveFlag","aiChat","promptInput","messagesContainer","historyLoaded","visibleSuggestionCount","pauseReveal","resumeReveal","startRevealTimeout","count","scrollToBottom","isVisible","handleSend","prompt","stripJsonBlock","text","handleSuggestionClick","suggestion","handleKeydown","event","_cache","message","index","$event"],"sources":["../../../src/cloud/components/AiChatSidebar.vue","../../../src/cloud/components/AiChatSidebar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport { useAiChat } from \"@templatical/core/cloud\";\nimport {\n CLOUD_TRANSLATIONS_KEY,\n EDITOR_KEY,\n AUTH_MANAGER_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport { useAliveFlag } from \"../../composables/useAliveFlag\";\nimport type { TemplateContent } from \"@templatical/types\";\nimport {\n CircleAlert,\n LoaderCircle,\n Redo2,\n Send,\n Sparkles,\n Trash2,\n Undo2,\n X,\n} from \"@lucide/vue\";\nimport { inject, nextTick, ref, watch } from \"vue\";\nimport { useIntervalFn, useTimeoutFn } from \"@vueuse/core\";\n\nconst props = defineProps<{\n visible: boolean;\n onApply?: (content: TemplateContent) => void;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst cloudTranslations = requireInject(\n CLOUD_TRANSLATIONS_KEY,\n \"AiChatSidebar\",\n);\nconst editor = requireInject(EDITOR_KEY, \"AiChatSidebar\");\nconst authManager = requireInject(AUTH_MANAGER_KEY, \"AiChatSidebar\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\nconst aliveFlag = useAliveFlag();\n\nconst aiChat = useAiChat({\n authManager,\n getTemplateId: () => editor.state.template?.id ?? null,\n onApply: props.onApply,\n onError: undefined,\n});\n\nconst promptInput = ref(\"\");\nconst messagesContainer = ref<HTMLElement | null>(null);\nconst historyLoaded = ref(false);\nconst visibleSuggestionCount = ref(0);\n\nconst { pause: pauseReveal, resume: resumeReveal } = useIntervalFn(\n () => {\n const count = aiChat.suggestions.value?.length ?? 0;\n if (visibleSuggestionCount.value < count) {\n visibleSuggestionCount.value++;\n } else {\n pauseReveal();\n }\n },\n 150,\n { immediate: false },\n);\n\nconst { start: startRevealTimeout } = useTimeoutFn(() => resumeReveal(), 100, {\n immediate: false,\n});\n\nwatch(\n () => aiChat.suggestions.value?.length ?? 0,\n (count) => {\n pauseReveal();\n if (count === 0) {\n visibleSuggestionCount.value = 0;\n return;\n }\n\n visibleSuggestionCount.value = 0;\n startRevealTimeout();\n },\n);\n\nfunction scrollToBottom(): void {\n nextTick(() => {\n if (messagesContainer.value) {\n messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;\n }\n });\n}\n\nwatch(\n () => aiChat.messages.value?.length ?? 0,\n () => scrollToBottom(),\n);\n\nwatch(\n () => props.visible,\n async (isVisible) => {\n if (isVisible && !historyLoaded.value) {\n historyLoaded.value = true;\n await aiChat.loadConversation();\n if (!aliveFlag.alive) return;\n\n if (\n (aiChat.messages.value?.length ?? 0) === 0 &&\n editor.content.value.blocks.length === 0\n ) {\n aiChat.loadSuggestions(editor.content.value, mergeTags.value);\n }\n }\n },\n);\n\nasync function handleSend(): Promise<void> {\n const prompt = promptInput.value.trim();\n if (!prompt || aiChat.isGenerating.value) {\n return;\n }\n\n promptInput.value = \"\";\n aiChat.error.value = null;\n aiChat.failedPrompt.value = null;\n scrollToBottom();\n\n await aiChat.sendPrompt(prompt, editor.content.value, mergeTags.value);\n if (!aliveFlag.alive) return;\n\n if (aiChat.failedPrompt.value) {\n promptInput.value = aiChat.failedPrompt.value;\n }\n\n scrollToBottom();\n}\n\nfunction stripJsonBlock(text: string): string {\n return text\n .replace(/```json[\\s\\S]*?```/g, \"\")\n .replace(/```json[\\s\\S]*/g, \"\")\n .trim();\n}\n\nfunction handleSuggestionClick(suggestion: string): void {\n pauseReveal();\n promptInput.value = suggestion;\n handleSend();\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSend();\n }\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-ai-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-ai-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n role=\"complementary\"\n :aria-label=\"cloudTranslations.aiChat.title\"\n class=\"tpl-ai-sidebar tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <Sparkles :size=\"13\" :stroke-width=\"2\" />\n <span>\n {{ cloudTranslations.aiChat.title }}\n </span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"(aiChat.messages.value?.length ?? 0) > 0\"\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudTranslations.aiChat.clear\"\n :title=\"cloudTranslations.aiChat.clear\"\n @click=\"aiChat.clearChat()\"\n >\n <Trash2 :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudTranslations.aiChat.close\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Messages wrapper -->\n <div class=\"tpl:relative tpl:flex tpl:min-h-0 tpl:flex-1 tpl:flex-col\">\n <!-- Messages -->\n <div\n ref=\"messagesContainer\"\n class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\"\n >\n <!-- Loading history state -->\n <div\n v-if=\"aiChat.isLoadingHistory.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <LoaderCircle\n class=\"tpl-spinner tpl:text-[var(--tpl-text-muted)]\"\n :size=\"24\"\n :stroke-width=\"2\"\n />\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudTranslations.aiChat.loadingHistory }}\n </p>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"(aiChat.messages.value?.length ?? 0) === 0\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <Sparkles\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudTranslations.aiChat.placeholder }}\n </p>\n </div>\n\n <!-- Message list -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-4\">\n <div\n v-for=\"(message, index) in aiChat.messages.value\"\n :key=\"message.id\"\n class=\"tpl:flex tpl:flex-col tpl:gap-2\"\n >\n <!-- User message -->\n <div\n v-if=\"message.role === 'user'\"\n class=\"tpl:self-end tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm\"\n style=\"\n background-color: var(--tpl-primary-light);\n color: var(--tpl-text);\n max-width: 85%;\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{ message.content }}\n </div>\n\n <!-- Assistant message -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-2\">\n <LoadingTrack\n v-if=\"\n !stripJsonBlock(message.content) &&\n aiChat.isGenerating.value &&\n index === (aiChat.messages.value?.length ?? 0) - 1\n \"\n />\n <div\n v-else\n class=\"tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm tpl:whitespace-pre-wrap\"\n style=\"\n max-width: 85%;\n background-color: var(--tpl-bg);\n color: var(--tpl-text);\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{\n stripJsonBlock(message.content) ||\n cloudTranslations.aiChat.applied\n }}\n </div>\n <button\n v-if=\"\n message.id === aiChat.lastApplyMessageId.value &&\n !aiChat.isGenerating.value\n \"\n class=\"tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:self-start tpl:rounded-md tpl:border tpl:px-2.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all\"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-text-muted);\n background-color: transparent;\n \"\n @click=\"aiChat.toggleLastRevert()\"\n >\n <template v-if=\"aiChat.isLastChangeReverted.value\">\n <Redo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.reapply }}\n </template>\n <template v-else>\n <Undo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.revert }}\n </template>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Error message -->\n <div\n v-if=\"aiChat.error.value\"\n class=\"tpl:mx-3 tpl:mb-2 tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs\"\n style=\"\n background-color: var(--tpl-danger-light);\n color: var(--tpl-danger);\n \"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{\n aiChat.error.value === \"ai_apply_failed\"\n ? cloudTranslations.aiChat.applyFailed\n : cloudTranslations.aiChat.error\n }}</span>\n </div>\n\n <!-- Suggestions (overlay) -->\n <div\n v-if=\"(aiChat.suggestions.value?.length ?? 0) > 0\"\n class=\"tpl:absolute tpl:right-0 tpl:bottom-0 tpl:left-0 tpl:z-10 tpl:px-3 tpl:pb-3\"\n style=\"\n background-color: color-mix(\n in srgb,\n var(--tpl-bg) 50%,\n transparent\n );\n backdrop-filter: blur(2px);\n \"\n >\n <div class=\"tpl:flex tpl:flex-col tpl:gap-1.5\">\n <button\n v-for=\"(suggestion, index) in aiChat.suggestions.value ?? []\"\n :key=\"index\"\n class=\"tpl-suggestion-btn tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border tpl:px-3 tpl:py-2 tpl:text-left tpl:text-xs tpl:leading-snug tpl:transition-all tpl:duration-300 tpl:ease-out\"\n :class=\"\n (aiChat.suggestions.value?.length ?? 0) - 1 - index <\n visibleSuggestionCount\n ? 'tpl:translate-y-0 tpl:opacity-100'\n : 'tpl:pointer-events-none tpl:-translate-y-2 tpl:opacity-0'\n \"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-primary);\n background-color: var(--tpl-bg);\n box-shadow: var(--tpl-shadow);\n \"\n @click=\"handleSuggestionClick(suggestion)\"\n >\n {{ suggestion }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Input area -->\n <div class=\"tpl:border-t tpl:p-3 tpl:border-[var(--tpl-border)]\">\n <div\n class=\"tpl-ai-input-wrapper tpl-focus-ring-host tpl:flex tpl:items-end tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:border tpl:px-3 tpl:py-2 tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)]\"\n >\n <textarea\n v-model=\"promptInput\"\n class=\"tpl:max-h-32 tpl:min-h-[64px] tpl:flex-1 tpl:resize-none tpl:border-none tpl:bg-transparent tpl:font-sans tpl:text-sm tpl:outline-none tpl:text-[var(--tpl-text)]\"\n :placeholder=\"cloudTranslations.aiChat.inputPlaceholder\"\n :disabled=\"aiChat.isGenerating.value\"\n rows=\"3\"\n @keydown=\"handleKeydown\"\n />\n <button\n class=\"tpl-ai-send-btn tpl:flex tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-md tpl:p-1.5 tpl:transition-all tpl:disabled:opacity-40 tpl:text-[var(--tpl-primary)]\"\n :disabled=\"!promptInput.trim() || aiChat.isGenerating.value\"\n @click=\"handleSend\"\n >\n <Send :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-1 tpl:pt-2 tpl:text-center tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudTranslations.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-ai-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-input-wrapper:focus-within {\n border-color: var(--tpl-primary);\n box-shadow: var(--tpl-ring);\n}\n\n.tpl-ai-send-btn:not(:disabled):hover {\n transform: scale(1.05);\n}\n\n.tpl-suggestion-btn:hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport { useAiChat } from \"@templatical/core/cloud\";\nimport {\n CLOUD_TRANSLATIONS_KEY,\n EDITOR_KEY,\n AUTH_MANAGER_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport { useAliveFlag } from \"../../composables/useAliveFlag\";\nimport type { TemplateContent } from \"@templatical/types\";\nimport {\n CircleAlert,\n LoaderCircle,\n Redo2,\n Send,\n Sparkles,\n Trash2,\n Undo2,\n X,\n} from \"@lucide/vue\";\nimport { inject, nextTick, ref, watch } from \"vue\";\nimport { useIntervalFn, useTimeoutFn } from \"@vueuse/core\";\n\nconst props = defineProps<{\n visible: boolean;\n onApply?: (content: TemplateContent) => void;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst cloudTranslations = requireInject(\n CLOUD_TRANSLATIONS_KEY,\n \"AiChatSidebar\",\n);\nconst editor = requireInject(EDITOR_KEY, \"AiChatSidebar\");\nconst authManager = requireInject(AUTH_MANAGER_KEY, \"AiChatSidebar\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\nconst aliveFlag = useAliveFlag();\n\nconst aiChat = useAiChat({\n authManager,\n getTemplateId: () => editor.state.template?.id ?? null,\n onApply: props.onApply,\n onError: undefined,\n});\n\nconst promptInput = ref(\"\");\nconst messagesContainer = ref<HTMLElement | null>(null);\nconst historyLoaded = ref(false);\nconst visibleSuggestionCount = ref(0);\n\nconst { pause: pauseReveal, resume: resumeReveal } = useIntervalFn(\n () => {\n const count = aiChat.suggestions.value?.length ?? 0;\n if (visibleSuggestionCount.value < count) {\n visibleSuggestionCount.value++;\n } else {\n pauseReveal();\n }\n },\n 150,\n { immediate: false },\n);\n\nconst { start: startRevealTimeout } = useTimeoutFn(() => resumeReveal(), 100, {\n immediate: false,\n});\n\nwatch(\n () => aiChat.suggestions.value?.length ?? 0,\n (count) => {\n pauseReveal();\n if (count === 0) {\n visibleSuggestionCount.value = 0;\n return;\n }\n\n visibleSuggestionCount.value = 0;\n startRevealTimeout();\n },\n);\n\nfunction scrollToBottom(): void {\n nextTick(() => {\n if (messagesContainer.value) {\n messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;\n }\n });\n}\n\nwatch(\n () => aiChat.messages.value?.length ?? 0,\n () => scrollToBottom(),\n);\n\nwatch(\n () => props.visible,\n async (isVisible) => {\n if (isVisible && !historyLoaded.value) {\n historyLoaded.value = true;\n await aiChat.loadConversation();\n if (!aliveFlag.alive) return;\n\n if (\n (aiChat.messages.value?.length ?? 0) === 0 &&\n editor.content.value.blocks.length === 0\n ) {\n aiChat.loadSuggestions(editor.content.value, mergeTags.value);\n }\n }\n },\n);\n\nasync function handleSend(): Promise<void> {\n const prompt = promptInput.value.trim();\n if (!prompt || aiChat.isGenerating.value) {\n return;\n }\n\n promptInput.value = \"\";\n aiChat.error.value = null;\n aiChat.failedPrompt.value = null;\n scrollToBottom();\n\n await aiChat.sendPrompt(prompt, editor.content.value, mergeTags.value);\n if (!aliveFlag.alive) return;\n\n if (aiChat.failedPrompt.value) {\n promptInput.value = aiChat.failedPrompt.value;\n }\n\n scrollToBottom();\n}\n\nfunction stripJsonBlock(text: string): string {\n return text\n .replace(/```json[\\s\\S]*?```/g, \"\")\n .replace(/```json[\\s\\S]*/g, \"\")\n .trim();\n}\n\nfunction handleSuggestionClick(suggestion: string): void {\n pauseReveal();\n promptInput.value = suggestion;\n handleSend();\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSend();\n }\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-ai-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-ai-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n role=\"complementary\"\n :aria-label=\"cloudTranslations.aiChat.title\"\n class=\"tpl-ai-sidebar tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <Sparkles :size=\"13\" :stroke-width=\"2\" />\n <span>\n {{ cloudTranslations.aiChat.title }}\n </span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"(aiChat.messages.value?.length ?? 0) > 0\"\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudTranslations.aiChat.clear\"\n :title=\"cloudTranslations.aiChat.clear\"\n @click=\"aiChat.clearChat()\"\n >\n <Trash2 :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudTranslations.aiChat.close\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Messages wrapper -->\n <div class=\"tpl:relative tpl:flex tpl:min-h-0 tpl:flex-1 tpl:flex-col\">\n <!-- Messages -->\n <div\n ref=\"messagesContainer\"\n class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\"\n >\n <!-- Loading history state -->\n <div\n v-if=\"aiChat.isLoadingHistory.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <LoaderCircle\n class=\"tpl-spinner tpl:text-[var(--tpl-text-muted)]\"\n :size=\"24\"\n :stroke-width=\"2\"\n />\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudTranslations.aiChat.loadingHistory }}\n </p>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"(aiChat.messages.value?.length ?? 0) === 0\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <Sparkles\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudTranslations.aiChat.placeholder }}\n </p>\n </div>\n\n <!-- Message list -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-4\">\n <div\n v-for=\"(message, index) in aiChat.messages.value\"\n :key=\"message.id\"\n class=\"tpl:flex tpl:flex-col tpl:gap-2\"\n >\n <!-- User message -->\n <div\n v-if=\"message.role === 'user'\"\n class=\"tpl:self-end tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm\"\n style=\"\n background-color: var(--tpl-primary-light);\n color: var(--tpl-text);\n max-width: 85%;\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{ message.content }}\n </div>\n\n <!-- Assistant message -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-2\">\n <LoadingTrack\n v-if=\"\n !stripJsonBlock(message.content) &&\n aiChat.isGenerating.value &&\n index === (aiChat.messages.value?.length ?? 0) - 1\n \"\n />\n <div\n v-else\n class=\"tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm tpl:whitespace-pre-wrap\"\n style=\"\n max-width: 85%;\n background-color: var(--tpl-bg);\n color: var(--tpl-text);\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{\n stripJsonBlock(message.content) ||\n cloudTranslations.aiChat.applied\n }}\n </div>\n <button\n v-if=\"\n message.id === aiChat.lastApplyMessageId.value &&\n !aiChat.isGenerating.value\n \"\n class=\"tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:self-start tpl:rounded-md tpl:border tpl:px-2.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all\"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-text-muted);\n background-color: transparent;\n \"\n @click=\"aiChat.toggleLastRevert()\"\n >\n <template v-if=\"aiChat.isLastChangeReverted.value\">\n <Redo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.reapply }}\n </template>\n <template v-else>\n <Undo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.revert }}\n </template>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Error message -->\n <div\n v-if=\"aiChat.error.value\"\n class=\"tpl:mx-3 tpl:mb-2 tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs\"\n style=\"\n background-color: var(--tpl-danger-light);\n color: var(--tpl-danger);\n \"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{\n aiChat.error.value === \"ai_apply_failed\"\n ? cloudTranslations.aiChat.applyFailed\n : cloudTranslations.aiChat.error\n }}</span>\n </div>\n\n <!-- Suggestions (overlay) -->\n <div\n v-if=\"(aiChat.suggestions.value?.length ?? 0) > 0\"\n class=\"tpl:absolute tpl:right-0 tpl:bottom-0 tpl:left-0 tpl:z-10 tpl:px-3 tpl:pb-3\"\n style=\"\n background-color: color-mix(\n in srgb,\n var(--tpl-bg) 50%,\n transparent\n );\n backdrop-filter: blur(2px);\n \"\n >\n <div class=\"tpl:flex tpl:flex-col tpl:gap-1.5\">\n <button\n v-for=\"(suggestion, index) in aiChat.suggestions.value ?? []\"\n :key=\"index\"\n class=\"tpl-suggestion-btn tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border tpl:px-3 tpl:py-2 tpl:text-left tpl:text-xs tpl:leading-snug tpl:transition-all tpl:duration-300 tpl:ease-out\"\n :class=\"\n (aiChat.suggestions.value?.length ?? 0) - 1 - index <\n visibleSuggestionCount\n ? 'tpl:translate-y-0 tpl:opacity-100'\n : 'tpl:pointer-events-none tpl:-translate-y-2 tpl:opacity-0'\n \"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-primary);\n background-color: var(--tpl-bg);\n box-shadow: var(--tpl-shadow);\n \"\n @click=\"handleSuggestionClick(suggestion)\"\n >\n {{ suggestion }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Input area -->\n <div class=\"tpl:border-t tpl:p-3 tpl:border-[var(--tpl-border)]\">\n <div\n class=\"tpl-ai-input-wrapper tpl-focus-ring-host tpl:flex tpl:items-end tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:border tpl:px-3 tpl:py-2 tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)]\"\n >\n <textarea\n v-model=\"promptInput\"\n class=\"tpl:max-h-32 tpl:min-h-[64px] tpl:flex-1 tpl:resize-none tpl:border-none tpl:bg-transparent tpl:font-sans tpl:text-sm tpl:outline-none tpl:text-[var(--tpl-text)]\"\n :placeholder=\"cloudTranslations.aiChat.inputPlaceholder\"\n :disabled=\"aiChat.isGenerating.value\"\n rows=\"3\"\n @keydown=\"handleKeydown\"\n />\n <button\n class=\"tpl-ai-send-btn tpl:flex tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-md tpl:p-1.5 tpl:transition-all tpl:disabled:opacity-40 tpl:text-[var(--tpl-primary)]\"\n :disabled=\"!promptInput.trim() || aiChat.isGenerating.value\"\n @click=\"handleSend\"\n >\n <Send :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-1 tpl:pt-2 tpl:text-center tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudTranslations.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-ai-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-input-wrapper:focus-within {\n border-color: var(--tpl-primary);\n box-shadow: var(--tpl-ring);\n}\n\n.tpl-ai-send-btn:not(:disabled):hover {\n transform: scale(1.05);\n}\n\n.tpl-suggestion-btn:hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { F as e, N as t, R as n, S as r, f as i, g as a, lt as o, m as s, p as c, u as l, ut as u } from "./draggable-IB4x6w2O.js";
2
- import "./useEditorCore-DZmtKwJh.js";
2
+ import "./useEditorCore-D4kzTMtQ.js";
3
3
  import { $ as d, t as f } from "./keys-DCWeHkSF.js";
4
- import { E as p, k as m, pt as h } from "./icons-BKkJ-5xF.js";
4
+ import { A as p, D as m, mt as h } from "./icons-CQnjugjy.js";
5
5
  import { t as g } from "./_plugin-vue_export-helper-B3ysoDQm.js";
6
6
  import { n as _ } from "./useCloudI18n-CrjWbpbu.js";
7
7
  //#region src/cloud/components/AiFeatureMenu.vue?vue&type=script&setup=true&lang.ts
@@ -17,7 +17,7 @@ var v = { class: "tpl-ai-feature-menu tpl:w-[280px] tpl:overflow-hidden tpl:roun
17
17
  }, D = [
18
18
  {
19
19
  key: "ai-chat",
20
- icon: p
20
+ icon: m
21
21
  },
22
22
  {
23
23
  key: "design-reference",
@@ -25,7 +25,7 @@ var v = { class: "tpl-ai-feature-menu tpl:w-[280px] tpl:overflow-hidden tpl:roun
25
25
  },
26
26
  {
27
27
  key: "scoring",
28
- icon: m
28
+ icon: p
29
29
  }
30
30
  ], O = i(() => D.filter((e) => T.isFeatureEnabled(E[e.key])));
31
31
  function k(e) {
@@ -54,4 +54,4 @@ var v = { class: "tpl-ai-feature-menu tpl:w-[280px] tpl:overflow-hidden tpl:roun
54
54
  //#endregion
55
55
  export { C as default };
56
56
 
57
- //# sourceMappingURL=AiFeatureMenu-Cx3qdStQ.js.map
57
+ //# sourceMappingURL=AiFeatureMenu-BXSPgOzA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiFeatureMenu-BXSPgOzA.js","names":["_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeStyle","_createElementVNode","_createBlock","_resolveDynamicComponent","_toDisplayString","_sfc_main","renderList","openBlock","resolveDynamicComponent","defineComponent","computed","createElementBlock","normalizeStyle","createBlock","createBaseVNode","Fragment","toDisplayString","requireInject","AI_CONFIG_KEY","ShieldCheck","Sparkles","ImageUp","_plugin_vue_export_helper_default","useCloudI18nStrict","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","AiFeatureMenu_default","__emit","emit","cloudT","aiConfig","configKeyMap","allFeatures","features","f","getTitle","key","getDescription","feature","__props"],"sources":["../../../src/cloud/components/AiFeatureMenu.vue","../../../src/cloud/components/AiFeatureMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { AI_CONFIG_KEY, requireInject } from \"../../keys\";\nimport type { AiConfig } from \"@templatical/types\";\nimport { ImageUp, ShieldCheck, Sparkles } from \"@lucide/vue\";\nimport { computed } from \"vue\";\n\nexport type AiFeature = \"ai-chat\" | \"design-reference\" | \"scoring\";\n\ndefineProps<{\n activeFeature: AiFeature | null;\n}>();\n\nconst emit = defineEmits<{\n (e: \"select\", feature: AiFeature): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\n\nconst aiConfig = requireInject(AI_CONFIG_KEY, \"AiFeatureMenu\");\n\nconst configKeyMap: Record<AiFeature, keyof AiConfig> = {\n \"ai-chat\": \"chat\",\n \"design-reference\": \"designToTemplate\",\n scoring: \"scoring\",\n};\n\nconst allFeatures: { key: AiFeature; icon: typeof Sparkles }[] = [\n { key: \"ai-chat\", icon: Sparkles },\n { key: \"design-reference\", icon: ImageUp },\n { key: \"scoring\", icon: ShieldCheck },\n];\n\nconst features = computed(() =>\n allFeatures.filter((f) => aiConfig.isFeatureEnabled(configKeyMap[f.key])),\n);\n\nfunction getTitle(key: AiFeature): string {\n if (key === \"ai-chat\") return cloudT.aiMenu.aiAssistant;\n if (key === \"design-reference\") return cloudT.aiMenu.designToTemplate;\n return cloudT.aiMenu.templateScore;\n}\n\nfunction getDescription(key: AiFeature): string {\n if (key === \"ai-chat\") return cloudT.aiMenu.aiAssistantDesc;\n if (key === \"design-reference\") return cloudT.aiMenu.designToTemplateDesc;\n return cloudT.aiMenu.templateScoreDesc;\n}\n</script>\n\n<template>\n <div\n class=\"tpl-ai-feature-menu tpl:w-[280px] tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:py-1 tpl:bg-[var(--tpl-bg)] tpl:border tpl:border-[var(--tpl-border)] tpl:shadow-[var(--tpl-shadow-lg)]\"\n >\n <button\n v-for=\"feature in features\"\n :key=\"feature.key\"\n class=\"tpl-ai-feature-menu-item tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-start tpl:gap-3 tpl:border-none tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors\"\n :style=\"{\n backgroundColor:\n activeFeature === feature.key\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n @click=\"emit('select', feature.key)\"\n >\n <div\n class=\"tpl:mt-0.5 tpl:flex tpl:size-7 tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-[var(--tpl-radius-sm)]\"\n :style=\"{\n backgroundColor:\n activeFeature === feature.key\n ? 'var(--tpl-primary)'\n : 'var(--tpl-bg-active)',\n color:\n activeFeature === feature.key\n ? 'var(--tpl-bg)'\n : 'var(--tpl-text-muted)',\n }\"\n >\n <component :is=\"feature.icon\" :size=\"15\" :stroke-width=\"2\" />\n </div>\n <div class=\"tpl:flex tpl:min-w-0 tpl:flex-col tpl:gap-0.5\">\n <span class=\"tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text)]\">\n {{ getTitle(feature.key) }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ getDescription(feature.key) }}\n </span>\n </div>\n </button>\n </div>\n</template>\n\n<style scoped>\n.tpl-ai-feature-menu-item:hover {\n background-color: var(--tpl-bg-hover) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { AI_CONFIG_KEY, requireInject } from \"../../keys\";\nimport type { AiConfig } from \"@templatical/types\";\nimport { ImageUp, ShieldCheck, Sparkles } from \"@lucide/vue\";\nimport { computed } from \"vue\";\n\nexport type AiFeature = \"ai-chat\" | \"design-reference\" | \"scoring\";\n\ndefineProps<{\n activeFeature: AiFeature | null;\n}>();\n\nconst emit = defineEmits<{\n (e: \"select\", feature: AiFeature): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\n\nconst aiConfig = requireInject(AI_CONFIG_KEY, \"AiFeatureMenu\");\n\nconst configKeyMap: Record<AiFeature, keyof AiConfig> = {\n \"ai-chat\": \"chat\",\n \"design-reference\": \"designToTemplate\",\n scoring: \"scoring\",\n};\n\nconst allFeatures: { key: AiFeature; icon: typeof Sparkles }[] = [\n { key: \"ai-chat\", icon: Sparkles },\n { key: \"design-reference\", icon: ImageUp },\n { key: \"scoring\", icon: ShieldCheck },\n];\n\nconst features = computed(() =>\n allFeatures.filter((f) => aiConfig.isFeatureEnabled(configKeyMap[f.key])),\n);\n\nfunction getTitle(key: AiFeature): string {\n if (key === \"ai-chat\") return cloudT.aiMenu.aiAssistant;\n if (key === \"design-reference\") return cloudT.aiMenu.designToTemplate;\n return cloudT.aiMenu.templateScore;\n}\n\nfunction getDescription(key: AiFeature): string {\n if (key === \"ai-chat\") return cloudT.aiMenu.aiAssistantDesc;\n if (key === \"design-reference\") return cloudT.aiMenu.designToTemplateDesc;\n return cloudT.aiMenu.templateScoreDesc;\n}\n</script>\n\n<template>\n <div\n class=\"tpl-ai-feature-menu tpl:w-[280px] tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:py-1 tpl:bg-[var(--tpl-bg)] tpl:border tpl:border-[var(--tpl-border)] tpl:shadow-[var(--tpl-shadow-lg)]\"\n >\n <button\n v-for=\"feature in features\"\n :key=\"feature.key\"\n class=\"tpl-ai-feature-menu-item tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-start tpl:gap-3 tpl:border-none tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors\"\n :style=\"{\n backgroundColor:\n activeFeature === feature.key\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n @click=\"emit('select', feature.key)\"\n >\n <div\n class=\"tpl:mt-0.5 tpl:flex tpl:size-7 tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-[var(--tpl-radius-sm)]\"\n :style=\"{\n backgroundColor:\n activeFeature === feature.key\n ? 'var(--tpl-primary)'\n : 'var(--tpl-bg-active)',\n color:\n activeFeature === feature.key\n ? 'var(--tpl-bg)'\n : 'var(--tpl-text-muted)',\n }\"\n >\n <component :is=\"feature.icon\" :size=\"15\" :stroke-width=\"2\" />\n </div>\n <div class=\"tpl:flex tpl:min-w-0 tpl:flex-col tpl:gap-0.5\">\n <span class=\"tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text)]\">\n {{ getTitle(feature.key) }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ getDescription(feature.key) }}\n </span>\n </div>\n </button>\n </div>\n</template>\n\n<style scoped>\n.tpl-ai-feature-menu-item:hover {\n background-color: var(--tpl-bg-hover) !important;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;EAaA,IAAMmC,IAAOD,GAIP,EAAE,GAAGE,MAAWT,EAAmB,GAEnCU,IAAWhB,EAAcC,GAAe,eAAe,GAEvDgB,IAAkD;GACtD,WAAW;GACX,oBAAoB;GACpB,SAAS;EACX,GAEMC,IAA2D;GAC/D;IAAE,KAAK;IAAW,MAAMf;GAAS;GACjC;IAAE,KAAK;IAAoB,MAAMC;GAAQ;GACzC;IAAE,KAAK;IAAW,MAAMF;GAAY;EACtC,GAEMiB,IAAW1B,QACfyB,EAAY,QAAQ,MAAMF,EAAS,iBAAiBC,EAAaG,EAAE,IAAI,CAAC,CAC1E;EAEA,SAASC,EAAS,GAAwB;GAGxC,OAFIC,MAAQ,YAAkBP,EAAO,OAAO,cACxCO,MAAQ,qBAA2BP,EAAO,OAAO,mBAC9CA,EAAO,OAAO;EACvB;EAEA,SAASQ,EAAe,GAAwB;GAG9C,OAFID,MAAQ,YAAkBP,EAAO,OAAO,kBACxCO,MAAQ,qBAA2BP,EAAO,OAAO,uBAC9CA,EAAO,OAAO;EACvB;oBAIEpC,EAAA,GAAAC,EAyCM,OAzCN2B,GAyCM,EAtCJ5B,EAAA,EAAA,GAAAC,EAqCSC,GAAA,MAAAC,EApCWqC,EAAA,QAAX,OADTxC,EAAA,GAAAC,EAqCS,UAAA;GAnCN,KAAK4C,EAAQ;GACd,OAAM;GACL,OAAKzC,EAAA,EAAA,iBAAuC0C,EAAA,kBAAkBD,EAAQ,MAAA,6BAAA,cAAA,CAAA;GAMtE,UAAK,MAAEV,EAAI,UAAWU,EAAQ,GAAG;EAElCxC,GAAAA,CAAAA,EAcM,OAAA;GAbJ,OAAM;GACL,OAAKD,EAAA;IAA2C,iBAAA0C,EAAA,kBAAkBD,EAAQ,MAAA,uBAAA;IAA8G,OAAAC,EAAA,kBAAkBD,EAAQ,MAAA,kBAAA;;EAWnN7C,GAAAA,EAAAA,EAAA,GAAAM,EAA6DC,EAA7CsC,EAAQ,IAAI,GAAA;GAAG,MAAM;GAAK,gBAAc;EAE1DxC,CAAAA,EAAAA,GAAAA,CAAAA,GAAAA,EASM,OATNyB,GASM,CARJzB,EAEO,QAFP0B,GAEOvB,EADFkC,EAASG,EAAQ,GAAG,CAAA,GAAA,CAAA,GAEzBxC,EAIO,QAJP2B,GAIOxB,EADFoC,EAAeC,EAAQ,GAAG,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,IAAAhB,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { E as e, N as t, S as n, at as r, ct as i, f as a, g as o, h as s, m as c } from "./draggable-IB4x6w2O.js";
2
2
  import { K as l } from "./keys-DCWeHkSF.js";
3
3
  import { t as u } from "./useI18n-CyO_Nmca.js";
4
- import { Mt as d, u as f } from "./icons-BKkJ-5xF.js";
4
+ import { Nt as d, d as f } from "./icons-CQnjugjy.js";
5
5
  //#region src/components/canvas/BlockIssueBadge.vue?vue&type=script&setup=true&lang.ts
6
6
  var p = ["title", "aria-label"], m = /* @__PURE__ */ n({
7
7
  __name: "BlockIssueBadge",
@@ -32,4 +32,4 @@ var p = ["title", "aria-label"], m = /* @__PURE__ */ n({
32
32
  //#endregion
33
33
  export { m as default };
34
34
 
35
- //# sourceMappingURL=BlockIssueBadge-DS1pUf5g.js.map
35
+ //# sourceMappingURL=BlockIssueBadge-ChQ0mPf5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlockIssueBadge-ChQ0mPf5.js","names":["_openBlock","_createElementBlock","_normalizeClass","_createBlock","_unref","_createCommentVNode","_sfc_main","inject","openBlock","defineComponent","unref","normalizeClass","computed","createElementBlock","createCommentVNode","createBlock","TEMPLATE_LINT_KEY","useI18n","CircleAlert","TriangleAlert","_hoisted_1","BlockIssueBadge_default","props","__props","lint","blockIssues","i","severity","tooltip","t"],"sources":["../../../src/components/canvas/BlockIssueBadge.vue","../../../src/components/canvas/BlockIssueBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, inject } from \"vue\";\nimport { CircleAlert, TriangleAlert } from \"@lucide/vue\";\nimport { useI18n } from \"../../composables/useI18n\";\nimport { TEMPLATE_LINT_KEY } from \"../../keys\";\n\nconst props = defineProps<{ blockId: string }>();\nconst { t } = useI18n();\nconst lint = inject(TEMPLATE_LINT_KEY, null);\n\nconst blockIssues = computed(() =>\n (lint?.issues.value ?? []).filter((i) => i.blockId === props.blockId),\n);\n\nconst severity = computed<\"error\" | \"warning\" | null>(() => {\n if (blockIssues.value.some((i) => i.severity === \"error\")) return \"error\";\n if (blockIssues.value.some((i) => i.severity === \"warning\")) return \"warning\";\n return null;\n});\n\nconst tooltip = computed(() =>\n severity.value === \"error\" ? t.issues.badgeError : t.issues.badgeWarning,\n);\n</script>\n\n<template>\n <span\n v-if=\"severity\"\n class=\"tpl:absolute tpl:top-1 tpl:right-1 tpl:z-10 tpl:flex tpl:size-5 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-bg)] tpl:shadow-[var(--tpl-shadow-sm)] tpl:ring-1 tpl:ring-[var(--tpl-border)]\"\n :class=\"\n severity === 'error'\n ? 'tpl:text-[var(--tpl-danger)]'\n : 'tpl:text-[var(--tpl-warning)]'\n \"\n :title=\"tooltip\"\n :aria-label=\"tooltip\"\n role=\"img\"\n >\n <CircleAlert\n v-if=\"severity === 'error'\"\n :size=\"14\"\n :stroke-width=\"2.25\"\n fill=\"currentColor\"\n stroke=\"var(--tpl-bg)\"\n />\n <TriangleAlert\n v-else\n :size=\"14\"\n :stroke-width=\"2.25\"\n fill=\"currentColor\"\n stroke=\"var(--tpl-bg)\"\n />\n </span>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject } from \"vue\";\nimport { CircleAlert, TriangleAlert } from \"@lucide/vue\";\nimport { useI18n } from \"../../composables/useI18n\";\nimport { TEMPLATE_LINT_KEY } from \"../../keys\";\n\nconst props = defineProps<{ blockId: string }>();\nconst { t } = useI18n();\nconst lint = inject(TEMPLATE_LINT_KEY, null);\n\nconst blockIssues = computed(() =>\n (lint?.issues.value ?? []).filter((i) => i.blockId === props.blockId),\n);\n\nconst severity = computed<\"error\" | \"warning\" | null>(() => {\n if (blockIssues.value.some((i) => i.severity === \"error\")) return \"error\";\n if (blockIssues.value.some((i) => i.severity === \"warning\")) return \"warning\";\n return null;\n});\n\nconst tooltip = computed(() =>\n severity.value === \"error\" ? t.issues.badgeError : t.issues.badgeWarning,\n);\n</script>\n\n<template>\n <span\n v-if=\"severity\"\n class=\"tpl:absolute tpl:top-1 tpl:right-1 tpl:z-10 tpl:flex tpl:size-5 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-bg)] tpl:shadow-[var(--tpl-shadow-sm)] tpl:ring-1 tpl:ring-[var(--tpl-border)]\"\n :class=\"\n severity === 'error'\n ? 'tpl:text-[var(--tpl-danger)]'\n : 'tpl:text-[var(--tpl-warning)]'\n \"\n :title=\"tooltip\"\n :aria-label=\"tooltip\"\n role=\"img\"\n >\n <CircleAlert\n v-if=\"severity === 'error'\"\n :size=\"14\"\n :stroke-width=\"2.25\"\n fill=\"currentColor\"\n stroke=\"var(--tpl-bg)\"\n />\n <TriangleAlert\n v-else\n :size=\"14\"\n :stroke-width=\"2.25\"\n fill=\"currentColor\"\n stroke=\"var(--tpl-bg)\"\n />\n </span>\n</template>\n"],"mappings":";;;;;;;;;EAMA,IAAMsB,IAAQC,GACR,EAAE,SAAMN,EAAQ,GAChBO,IAAOjB,EAAOS,GAAmB,IAAI,GAErCS,IAAcb,SACjBY,GAAM,OAAO,SAAS,CAAC,EAAA,CAAG,QAAQ,MAAME,EAAE,YAAYJ,EAAM,OAAO,CACtE,GAEMK,IAAWf,QACXa,EAAY,MAAM,MAAM,MAAMC,EAAE,aAAa,OAAO,IAAU,UAC9DD,EAAY,MAAM,MAAM,MAAMC,EAAE,aAAa,SAAS,IAAU,YAC7D,IACR,GAEKE,IAAUhB,QACde,EAAS,UAAU,UAAUE,EAAE,OAAO,aAAaA,EAAE,OAAO,YAC9D;mBAKUF,EAAA,SADR3B,EAAA,GAAAC,EA0BO,QAAA;;GAxBL,OAAKC,EAAA,CAAC,yNACSyB,EAAA,UAAQ,UAAA,iCAAA,+BAAA,CAAA;GAKtB,OAAOC,EAAA;GACP,cAAYA,EAAA;GACb,MAAK;EAGG,GAAA,CAAAD,EAAA,UAAQ,WADhB3B,EAAA,GAAAG,EAMEC,EAAAc,CAAA,GAAA;;GAJC,MAAM;GACN,gBAAc;GACf,MAAK;GACL,QAAO;EAETlB,CAAAA,MAAAA,EAAA,GAAAG,EAMEC,EAAAe,CAAA,GAAA;;GAJC,MAAM;GACN,gBAAc;GACf,MAAK;GACL,QAAO"}
@@ -1,9 +1,9 @@
1
1
  import { n as e } from "./rolldown-runtime-B0aSnxlc.js";
2
2
  import { E as t, F as n, L as r, N as i, P as a, R as o, S as s, at as c, f as l, g as u, lt as d, m as f, p, u as m } from "./draggable-IB4x6w2O.js";
3
- import { G as h } from "./src-DveVYoWS.js";
4
- import { E as g, _, a as v, f as y, g as b, h as x, i as S, l as C, m as w, n as T, p as E, r as D, s as O, u as k, v as A } from "./useEditorCore-DZmtKwJh.js";
3
+ import { G as h } from "./src-BR3I3gOW.js";
4
+ import { C as g, E as _, S as v, a as y, d as b, f as x, i as S, l as C, m as w, n as T, p as E, r as D, s as O, u as k, w as A } from "./useEditorCore-D4kzTMtQ.js";
5
5
  import { M as j, Q as M, f as N, g as P, s as F } from "./keys-DCWeHkSF.js";
6
- import { n as I, r as L, t as R } from "./WrapperBlock-CpRvfAV0.js";
6
+ import { n as I, r as L, t as R } from "./WrapperBlock-DI8vSvTO.js";
7
7
  //#region src/components/blocks/PreviewSectionBlock.vue?vue&type=script&setup=true&lang.ts
8
8
  var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__PURE__ */ s({
9
9
  name: "PreviewSectionBlock",
@@ -15,18 +15,18 @@ var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__
15
15
  setup(e) {
16
16
  let a = {
17
17
  title: O,
18
- paragraph: E,
19
- image: x,
18
+ paragraph: C,
19
+ image: b,
20
20
  video: T,
21
- button: g,
22
- divider: _,
23
- social: v,
24
- menu: w,
21
+ button: v,
22
+ divider: E,
23
+ social: y,
24
+ menu: k,
25
25
  table: D,
26
26
  spacer: S,
27
- html: b,
28
- custom: A
29
- }, s = e, h = t(F, null), k = l(() => {
27
+ html: x,
28
+ custom: w
29
+ }, s = e, h = t(F, null), A = l(() => {
30
30
  switch (s.block.columns) {
31
31
  case "2": return ["50%", "50%"];
32
32
  case "3": return [
@@ -39,7 +39,7 @@ var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__
39
39
  default: return ["100%"];
40
40
  }
41
41
  }), j = l(() => {
42
- let e = k.value.length, t = [...s.block.children];
42
+ let e = A.value.length, t = [...s.block.children];
43
43
  for (; t.length < e;) t.push([]);
44
44
  return t.slice(0, e);
45
45
  });
@@ -47,16 +47,16 @@ var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__
47
47
  return j.value[e] || [];
48
48
  }
49
49
  function N(e) {
50
- return y(e, h, a);
50
+ return _(e, h, a);
51
51
  }
52
52
  return (e, t) => {
53
53
  let a = r("PreviewSectionBlock", !0);
54
54
  return i(), u("div", z, [p("div", B, [(i(!0), u(m, null, n(j.value, (e, t) => (i(), u("div", {
55
55
  key: t,
56
- style: d({ width: k.value[t] })
56
+ style: d({ width: A.value[t] })
57
57
  }, [(i(!0), u(m, null, n(M(t), (e) => (i(), u("div", {
58
58
  key: e.id,
59
- style: d(c(C)(e))
59
+ style: d(c(g)(e))
60
60
  }, [e.type === "section" ? (i(), f(a, {
61
61
  key: 0,
62
62
  block: e,
@@ -82,24 +82,24 @@ var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__
82
82
  setup(e) {
83
83
  let r = e, s = t(F), z = t(P, null), B = t(N, null), U = t(j, null);
84
84
  a(M, l(() => U?.value ?? !1));
85
- let W = l(() => r.applyConditionFilter ? r.blocks.filter((e) => !B?.isHidden(e.id)) : r.blocks), G = l(() => r.settings ?? z?.content.value.settings), K = l(() => L(G.value, r.viewport)), q = l(() => G.value ? k(G.value) : {}), J = l(() => G.value?.locale?.trim() || void 0), Y = l(() => h(G.value ?? { locale: "en" })), X = l(() => G.value?.backgroundColor || "var(--tpl-canvas-bg)"), Z = l(() => K.value + 192), Q = {
85
+ let W = l(() => r.applyConditionFilter ? r.blocks.filter((e) => !B?.isHidden(e.id)) : r.blocks), G = l(() => r.settings ?? z?.content.value.settings), K = l(() => L(G.value, r.viewport)), q = l(() => G.value ? A(G.value) : {}), J = l(() => G.value?.locale?.trim() || void 0), Y = l(() => h(G.value ?? { locale: "en" })), X = l(() => G.value?.backgroundColor || "var(--tpl-canvas-bg)"), Z = l(() => K.value + 192), Q = {
86
86
  section: V,
87
87
  title: O,
88
- paragraph: E,
89
- image: x,
88
+ paragraph: C,
89
+ image: b,
90
90
  video: T,
91
- button: g,
92
- divider: _,
93
- social: v,
94
- menu: w,
91
+ button: v,
92
+ divider: E,
93
+ social: y,
94
+ menu: k,
95
95
  table: D,
96
96
  spacer: S,
97
- html: b,
98
- custom: A,
97
+ html: x,
98
+ custom: w,
99
99
  wrapper: R
100
100
  };
101
101
  function $(e) {
102
- return y(e, s, Q);
102
+ return _(e, s, Q);
103
103
  }
104
104
  return (t, r) => (i(), u("div", {
105
105
  "data-testid": "block-preview-stage",
@@ -122,7 +122,7 @@ var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__
122
122
  })
123
123
  }, [(i(!0), u(m, null, n(W.value, (t) => (i(), u("div", {
124
124
  key: t.id,
125
- style: d(c(C)(t))
125
+ style: d(c(g)(t))
126
126
  }, [(i(), f(o($(t)), {
127
127
  block: t,
128
128
  viewport: e.viewport
@@ -132,4 +132,4 @@ var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__
132
132
  //#endregion
133
133
  export { W as n, G as t };
134
134
 
135
- //# sourceMappingURL=BlockPreviewCanvas-D31TNib3.js.map
135
+ //# sourceMappingURL=BlockPreviewCanvas-CMmv1FTA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlockPreviewCanvas-CMmv1FTA.js","names":["_hoisted_1","TitleBlock","ParagraphBlock","ImageBlock","VideoBlock","ButtonBlock","DividerBlock","SocialIconsBlock","MenuBlock","TableBlock","SpacerBlock","HtmlBlock","CustomBlock","_resolveComponent","_openBlock","_createElementBlock","_createElementVNode","_Fragment","_renderList","_normalizeStyle","_unref","_createBlock","_resolveDynamicComponent","_sfc_main","PreviewSectionBlock","TitleBlock","ParagraphBlock","ImageBlock","VideoBlock","ButtonBlock","DividerBlock","SocialIconsBlock","MenuBlock","TableBlock","SpacerBlock","HtmlBlock","CustomBlock","WrapperBlock","_openBlock","_createElementBlock","_normalizeStyle","_createElementVNode","_unref","_Fragment","_renderList","_createBlock","_resolveDynamicComponent","_sfc_main","__exportAll","inject","renderList","resolveComponent","openBlock","provide","resolveDynamicComponent","defineComponent","unref","computed","createElementBlock","normalizeStyle","createBlock","Fragment","resolveContentDirection","getBlockWrapperStyle","resolveBlockComponent","ButtonBlock_default","SocialIconsBlock_default","ImageBlock_default","HtmlBlock_default","SpacerBlock_default","ParagraphBlock_default","CustomBlock_default","VideoBlock_default","DividerBlock_default","TableBlock_default","TitleBlock_default","MenuBlock_default","getDocumentStyle","MERGE_TAG_SAMPLE_MODE_KEY","USE_MERGE_TAG_SAMPLES_KEY","CONDITION_PREVIEW_KEY","EDITOR_KEY","BLOCK_REGISTRY_KEY","EMAIL_FRAME_WIDTH_TRANSITION","getEmailFrameWidth","WrapperBlock_default","_hoisted_1$1","_hoisted_2","PreviewSectionBlock_default","previewBlockComponentMap","props","__props","blockRegistry","columnWidths","columns","count","children","getColumnBlocks","colIndex","getBlockComponent","block","_component_PreviewSectionBlock","createBaseVNode","childBlock","_hoisted_1","BlockPreviewCanvas_vue_vue_type_script_setup_true_lang_default","editor","conditionPreview","mergeTagSampleMode","visibleBlocks","previewSettings","frameWidth","documentStyle","contentLang","contentDir","emailBackground","stageWidth","previewComponentMap","BlockPreviewCanvas_exports","BlockPreviewCanvas_default"],"sources":["../../../src/components/blocks/PreviewSectionBlock.vue","../../../src/components/blocks/PreviewSectionBlock.vue","../../../src/components/BlockPreviewCanvas.vue","../../../src/components/BlockPreviewCanvas.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport ButtonBlock from \"./ButtonBlock.vue\";\nimport CustomBlock from \"./CustomBlock.vue\";\nimport DividerBlock from \"./DividerBlock.vue\";\nimport HtmlBlock from \"./HtmlBlock.vue\";\nimport ImageBlock from \"./ImageBlock.vue\";\nimport MenuBlock from \"./MenuBlock.vue\";\nimport SocialIconsBlock from \"./SocialIconsBlock.vue\";\nimport SpacerBlock from \"./SpacerBlock.vue\";\nimport TableBlock from \"./TableBlock.vue\";\nimport TitleBlock from \"./TitleBlock.vue\";\nimport ParagraphBlock from \"./ParagraphBlock.vue\";\nimport VideoBlock from \"./VideoBlock.vue\";\nimport {\n resolveBlockComponent,\n getBlockWrapperStyle,\n} from \"../../utils/blockComponentResolver\";\nimport type {\n Block,\n SectionBlock as SectionBlockType,\n} from \"@templatical/types\";\nimport { computed, inject, type Component } from \"vue\";\nimport { BLOCK_REGISTRY_KEY } from \"../../keys\";\n\nconst previewBlockComponentMap: Record<string, Component> = {\n title: TitleBlock,\n paragraph: ParagraphBlock,\n image: ImageBlock,\n video: VideoBlock,\n button: ButtonBlock,\n divider: DividerBlock,\n social: SocialIconsBlock,\n menu: MenuBlock,\n table: TableBlock,\n spacer: SpacerBlock,\n html: HtmlBlock,\n custom: CustomBlock,\n};\n\nconst props = defineProps<{\n block: SectionBlockType;\n viewport: \"desktop\";\n}>();\n\ndefineOptions({ name: \"PreviewSectionBlock\" });\n\nconst blockRegistry = inject(BLOCK_REGISTRY_KEY, null);\n\nconst columnWidths = computed(() => {\n switch (props.block.columns) {\n case \"2\":\n return [\"50%\", \"50%\"];\n case \"3\":\n return [\"33.33%\", \"33.33%\", \"33.33%\"];\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\nconst columns = computed(() => {\n const count = columnWidths.value.length;\n const children = [...props.block.children];\n while (children.length < count) {\n children.push([]);\n }\n return children.slice(0, count);\n});\n\nfunction getColumnBlocks(colIndex: number): Block[] {\n return columns.value[colIndex] || [];\n}\n\nfunction getBlockComponent(block: Block): Component | null {\n return resolveBlockComponent(block, blockRegistry, previewBlockComponentMap);\n}\n</script>\n\n<template>\n <div class=\"tpl:w-full\">\n <div class=\"tpl:flex tpl:gap-0\">\n <div\n v-for=\"(_, colIndex) in columns\"\n :key=\"colIndex\"\n :style=\"{ width: columnWidths[colIndex] }\"\n >\n <div\n v-for=\"childBlock in getColumnBlocks(colIndex)\"\n :key=\"childBlock.id\"\n :style=\"getBlockWrapperStyle(childBlock)\"\n >\n <!-- Recursive self-reference for nested sections -->\n <PreviewSectionBlock\n v-if=\"childBlock.type === 'section'\"\n :block=\"childBlock\"\n viewport=\"desktop\"\n />\n <component\n :is=\"getBlockComponent(childBlock)\"\n v-else\n :block=\"childBlock\"\n viewport=\"desktop\"\n />\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ButtonBlock from \"./ButtonBlock.vue\";\nimport CustomBlock from \"./CustomBlock.vue\";\nimport DividerBlock from \"./DividerBlock.vue\";\nimport HtmlBlock from \"./HtmlBlock.vue\";\nimport ImageBlock from \"./ImageBlock.vue\";\nimport MenuBlock from \"./MenuBlock.vue\";\nimport SocialIconsBlock from \"./SocialIconsBlock.vue\";\nimport SpacerBlock from \"./SpacerBlock.vue\";\nimport TableBlock from \"./TableBlock.vue\";\nimport TitleBlock from \"./TitleBlock.vue\";\nimport ParagraphBlock from \"./ParagraphBlock.vue\";\nimport VideoBlock from \"./VideoBlock.vue\";\nimport {\n resolveBlockComponent,\n getBlockWrapperStyle,\n} from \"../../utils/blockComponentResolver\";\nimport type {\n Block,\n SectionBlock as SectionBlockType,\n} from \"@templatical/types\";\nimport { computed, inject, type Component } from \"vue\";\nimport { BLOCK_REGISTRY_KEY } from \"../../keys\";\n\nconst previewBlockComponentMap: Record<string, Component> = {\n title: TitleBlock,\n paragraph: ParagraphBlock,\n image: ImageBlock,\n video: VideoBlock,\n button: ButtonBlock,\n divider: DividerBlock,\n social: SocialIconsBlock,\n menu: MenuBlock,\n table: TableBlock,\n spacer: SpacerBlock,\n html: HtmlBlock,\n custom: CustomBlock,\n};\n\nconst props = defineProps<{\n block: SectionBlockType;\n viewport: \"desktop\";\n}>();\n\ndefineOptions({ name: \"PreviewSectionBlock\" });\n\nconst blockRegistry = inject(BLOCK_REGISTRY_KEY, null);\n\nconst columnWidths = computed(() => {\n switch (props.block.columns) {\n case \"2\":\n return [\"50%\", \"50%\"];\n case \"3\":\n return [\"33.33%\", \"33.33%\", \"33.33%\"];\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\nconst columns = computed(() => {\n const count = columnWidths.value.length;\n const children = [...props.block.children];\n while (children.length < count) {\n children.push([]);\n }\n return children.slice(0, count);\n});\n\nfunction getColumnBlocks(colIndex: number): Block[] {\n return columns.value[colIndex] || [];\n}\n\nfunction getBlockComponent(block: Block): Component | null {\n return resolveBlockComponent(block, blockRegistry, previewBlockComponentMap);\n}\n</script>\n\n<template>\n <div class=\"tpl:w-full\">\n <div class=\"tpl:flex tpl:gap-0\">\n <div\n v-for=\"(_, colIndex) in columns\"\n :key=\"colIndex\"\n :style=\"{ width: columnWidths[colIndex] }\"\n >\n <div\n v-for=\"childBlock in getColumnBlocks(colIndex)\"\n :key=\"childBlock.id\"\n :style=\"getBlockWrapperStyle(childBlock)\"\n >\n <!-- Recursive self-reference for nested sections -->\n <PreviewSectionBlock\n v-if=\"childBlock.type === 'section'\"\n :block=\"childBlock\"\n viewport=\"desktop\"\n />\n <component\n :is=\"getBlockComponent(childBlock)\"\n v-else\n :block=\"childBlock\"\n viewport=\"desktop\"\n />\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ButtonBlock from \"./blocks/ButtonBlock.vue\";\nimport CustomBlock from \"./blocks/CustomBlock.vue\";\nimport DividerBlock from \"./blocks/DividerBlock.vue\";\nimport HtmlBlock from \"./blocks/HtmlBlock.vue\";\nimport ImageBlock from \"./blocks/ImageBlock.vue\";\nimport MenuBlock from \"./blocks/MenuBlock.vue\";\nimport PreviewSectionBlock from \"./blocks/PreviewSectionBlock.vue\";\nimport SocialIconsBlock from \"./blocks/SocialIconsBlock.vue\";\nimport SpacerBlock from \"./blocks/SpacerBlock.vue\";\nimport TableBlock from \"./blocks/TableBlock.vue\";\nimport TitleBlock from \"./blocks/TitleBlock.vue\";\nimport ParagraphBlock from \"./blocks/ParagraphBlock.vue\";\nimport VideoBlock from \"./blocks/VideoBlock.vue\";\nimport WrapperBlock from \"./blocks/WrapperBlock.vue\";\nimport {\n BLOCK_REGISTRY_KEY,\n CONDITION_PREVIEW_KEY,\n EDITOR_KEY,\n MERGE_TAG_SAMPLE_MODE_KEY,\n USE_MERGE_TAG_SAMPLES_KEY,\n} from \"../keys\";\nimport {\n resolveBlockComponent,\n getBlockWrapperStyle,\n getDocumentStyle,\n} from \"../utils/blockComponentResolver\";\nimport {\n EMAIL_FRAME_WIDTH_TRANSITION,\n EMAIL_GUTTER,\n getEmailFrameWidth,\n} from \"../utils/emailFrameWidth\";\nimport {\n resolveContentDirection,\n type Block,\n type TemplateSettings,\n type ViewportSize,\n} from \"@templatical/types\";\nimport { computed, inject, provide, type Component } from \"vue\";\n\nconst props = withDefaults(\n defineProps<{\n blocks: Block[];\n /**\n * Which viewport to render. Defaults to `desktop`, so the saved-blocks\n * surfaces — which have no viewport control — behave exactly as before.\n * The test-email dialog passes the user's choice so responsive blocks show\n * the variant a recipient on that device would receive.\n */\n viewport?: ViewportSize;\n /**\n * Whether the hand-toggled display-condition filter still applies here.\n * `false` where a resolver owns the preview: it has already evaluated every\n * condition against real data, so layering a manual hide on top would veto\n * the answer that was asked for.\n *\n * A prop rather than an injected `PREVIEW_RESOLUTION_KEY` read, because the\n * test-email dialog builds its *own* resolution instance (keyed to the\n * selected recipient) — injecting would consult the shared canvas instance\n * and get the wrong answer.\n */\n applyConditionFilter?: boolean;\n /**\n * Document settings for this surface. Test-email passes the composed\n * document so the mat is layout `backgroundColor` (`mj-body`). Saved-block\n * previews omit it and read the live editor template.\n */\n settings?: TemplateSettings;\n }>(),\n { viewport: \"desktop\", applyConditionFilter: true, settings: undefined },\n);\n\nconst blockRegistry = inject(BLOCK_REGISTRY_KEY);\nconst editor = inject(EDITOR_KEY, null);\nconst conditionPreview = inject(CONDITION_PREVIEW_KEY, null);\n\n/**\n * This canvas is only ever a preview — nothing here is editable — so it honours\n * the user's mode directly, with no `previewMode` gate of the kind `Canvas.vue`\n * needs. Re-provided rather than left to inherit, because a `BlockPreviewCanvas`\n * inside a dialog may sit under an editing `Canvas` that provides `false`.\n */\nconst mergeTagSampleMode = inject(MERGE_TAG_SAMPLE_MODE_KEY, null);\nprovide(\n USE_MERGE_TAG_SAMPLES_KEY,\n computed(() => mergeTagSampleMode?.value ?? false),\n);\n\n/**\n * Blocks a display condition currently excludes, so a preview never shows\n * content the recipient won't get. The canvas does the same via\n * `v-show=\"!conditionPreview?.isHidden(block.id)\"`.\n *\n * A no-op for the saved-blocks browser: entries there carry their *stored* ids,\n * which aren't in the current template, so nothing is tracked as hidden. It\n * bites where it should — the save dialog and the test-email preview, both of\n * which show blocks that are live on the canvas.\n *\n * Skipped entirely when `applyConditionFilter` is false — see the prop.\n */\nconst visibleBlocks = computed(() =>\n props.applyConditionFilter\n ? props.blocks.filter((block) => !conditionPreview?.isHidden(block.id))\n : props.blocks,\n);\n\nconst previewSettings = computed(\n () => props.settings ?? editor?.content.value.settings,\n);\n\n/**\n * Frame width, from the one helper the canvas and the scaled preview rows also\n * use — so all three agree by construction rather than by three constants that\n * happen to match. A template with a custom body width now previews at that\n * width instead of a flat 600.\n */\nconst frameWidth = computed(() =>\n getEmailFrameWidth(previewSettings.value, props.viewport),\n);\n\n/**\n * The same document-level style the canvas applies, so a previewed block\n * renders identically to the canvas one: without it the font falls back to the\n * editor UI's and the link rules hit their unset defaults, dropping the\n * underline and the link colour.\n *\n * Read from the *current* template even in the saved-blocks browser, where the\n * previewed content came from elsewhere — a saved block stores only `Block[]`,\n * and the current settings are what it will actually look like once inserted.\n */\nconst documentStyle = computed(() =>\n previewSettings.value ? getDocumentStyle(previewSettings.value) : {},\n);\n\n/**\n * The email's own language, for the browser's spellchecker and hyphenation —\n * the same binding the editing canvas carries, so a preview is checked by the\n * same rules as the block it mirrors.\n *\n * From `settings.locale`, never `config.locale`: the chrome's language says\n * nothing about the content's. Read from the *current* template for the same\n * reason `documentStyle` is — a saved block stores only `Block[]`. Undefined\n * rather than `\"\"`, which would declare \"unknown language\" and suppress\n * spellcheck instead of falling back.\n */\nconst contentLang = computed(\n () => previewSettings.value?.locale?.trim() || undefined,\n);\nconst contentDir = computed(() =>\n resolveContentDirection(previewSettings.value ?? { locale: \"en\" }),\n);\n\n/**\n * The email's body background — `mj-body background-color` when sent, and the\n * `.tpl-canvas-bg` layer on the editing canvas.\n *\n * Deliberately NOT part of `getDocumentStyle`: the canvas applies that helper\n * to `.tpl-canvas`, which must stay transparent so the invertible background\n * layer beneath it shows through. A background there would double-paint and\n * defeat the dark-mode preview.\n *\n * Truthiness, not `??`: the colour pickers clear to an empty string to mean\n * \"unset\", which as an inline style renders the frame transparent rather than\n * falling back to the neutral preview surface.\n */\nconst emailBackground = computed(\n () => previewSettings.value?.backgroundColor || \"var(--tpl-canvas-bg)\",\n);\n\n/**\n * Width the stage asks for: the content column plus a full gutter on each side,\n * the same stage the canvas builds. It is an ask rather than a fixed size —\n * paired with `max-width: 100%` below, so a container with less room hands over\n * what it has and shows a narrower band instead of overflowing.\n *\n * It has to be a specified width, not `100%`: `TplModal`'s wrapper is\n * shrink-to-fit, so a percentage there resolves against a container whose size\n * the stage is itself supposed to influence, and the stage collapses to its\n * `min-width` — no gutters, on the one surface this exists for.\n */\nconst stageWidth = computed(() => frameWidth.value + EMAIL_GUTTER * 2);\n\nconst previewComponentMap: Record<string, Component> = {\n section: PreviewSectionBlock,\n title: TitleBlock,\n paragraph: ParagraphBlock,\n image: ImageBlock,\n video: VideoBlock,\n button: ButtonBlock,\n divider: DividerBlock,\n social: SocialIconsBlock,\n menu: MenuBlock,\n table: TableBlock,\n spacer: SpacerBlock,\n html: HtmlBlock,\n custom: CustomBlock,\n wrapper: WrapperBlock,\n};\n\nfunction getBlockComponent(block: Block): Component | null {\n return resolveBlockComponent(block, blockRegistry, previewComponentMap);\n}\n</script>\n\n<template>\n <!-- STAGE — the email body, holding the background and a gutter of it on\n each side of the content column, the same shape `Canvas.vue` builds.\n `max-width: 100%` is what makes it fit anywhere: a roomy surface shows\n the full band, a dialog shows as much as it has, and a container sized to\n the content column shows none. `min-width` keeps it from squeezing the\n column, so a cramped surface clips exactly as it did when the frame\n carried the width itself. -->\n <div\n data-testid=\"block-preview-stage\"\n class=\"tpl:pointer-events-none tpl:mx-auto tpl:flex tpl:select-none tpl:justify-center tpl:rounded-lg\"\n :style=\"{\n width: `${stageWidth}px`,\n minWidth: `${frameWidth}px`,\n maxWidth: '100%',\n backgroundColor: emailBackground,\n boxShadow: 'var(--tpl-shadow-sm)',\n }\"\n >\n <!-- CONTENT COLUMN — the blocks at their true email width. Keeps the\n testid: this is the element whose width *is* the email width, which is\n what every viewport assertion measures. -->\n <div\n data-testid=\"block-preview-canvas\"\n :lang=\"contentLang\"\n :dir=\"contentDir\"\n :style=\"{\n width: `${frameWidth}px`,\n transition: EMAIL_FRAME_WIDTH_TRANSITION,\n ...documentStyle,\n }\"\n >\n <div\n v-for=\"block in visibleBlocks\"\n :key=\"block.id\"\n :style=\"getBlockWrapperStyle(block)\"\n >\n <component\n :is=\"getBlockComponent(block)\"\n :block=\"block\"\n :viewport=\"viewport\"\n />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ButtonBlock from \"./blocks/ButtonBlock.vue\";\nimport CustomBlock from \"./blocks/CustomBlock.vue\";\nimport DividerBlock from \"./blocks/DividerBlock.vue\";\nimport HtmlBlock from \"./blocks/HtmlBlock.vue\";\nimport ImageBlock from \"./blocks/ImageBlock.vue\";\nimport MenuBlock from \"./blocks/MenuBlock.vue\";\nimport PreviewSectionBlock from \"./blocks/PreviewSectionBlock.vue\";\nimport SocialIconsBlock from \"./blocks/SocialIconsBlock.vue\";\nimport SpacerBlock from \"./blocks/SpacerBlock.vue\";\nimport TableBlock from \"./blocks/TableBlock.vue\";\nimport TitleBlock from \"./blocks/TitleBlock.vue\";\nimport ParagraphBlock from \"./blocks/ParagraphBlock.vue\";\nimport VideoBlock from \"./blocks/VideoBlock.vue\";\nimport WrapperBlock from \"./blocks/WrapperBlock.vue\";\nimport {\n BLOCK_REGISTRY_KEY,\n CONDITION_PREVIEW_KEY,\n EDITOR_KEY,\n MERGE_TAG_SAMPLE_MODE_KEY,\n USE_MERGE_TAG_SAMPLES_KEY,\n} from \"../keys\";\nimport {\n resolveBlockComponent,\n getBlockWrapperStyle,\n getDocumentStyle,\n} from \"../utils/blockComponentResolver\";\nimport {\n EMAIL_FRAME_WIDTH_TRANSITION,\n EMAIL_GUTTER,\n getEmailFrameWidth,\n} from \"../utils/emailFrameWidth\";\nimport {\n resolveContentDirection,\n type Block,\n type TemplateSettings,\n type ViewportSize,\n} from \"@templatical/types\";\nimport { computed, inject, provide, type Component } from \"vue\";\n\nconst props = withDefaults(\n defineProps<{\n blocks: Block[];\n /**\n * Which viewport to render. Defaults to `desktop`, so the saved-blocks\n * surfaces — which have no viewport control — behave exactly as before.\n * The test-email dialog passes the user's choice so responsive blocks show\n * the variant a recipient on that device would receive.\n */\n viewport?: ViewportSize;\n /**\n * Whether the hand-toggled display-condition filter still applies here.\n * `false` where a resolver owns the preview: it has already evaluated every\n * condition against real data, so layering a manual hide on top would veto\n * the answer that was asked for.\n *\n * A prop rather than an injected `PREVIEW_RESOLUTION_KEY` read, because the\n * test-email dialog builds its *own* resolution instance (keyed to the\n * selected recipient) — injecting would consult the shared canvas instance\n * and get the wrong answer.\n */\n applyConditionFilter?: boolean;\n /**\n * Document settings for this surface. Test-email passes the composed\n * document so the mat is layout `backgroundColor` (`mj-body`). Saved-block\n * previews omit it and read the live editor template.\n */\n settings?: TemplateSettings;\n }>(),\n { viewport: \"desktop\", applyConditionFilter: true, settings: undefined },\n);\n\nconst blockRegistry = inject(BLOCK_REGISTRY_KEY);\nconst editor = inject(EDITOR_KEY, null);\nconst conditionPreview = inject(CONDITION_PREVIEW_KEY, null);\n\n/**\n * This canvas is only ever a preview — nothing here is editable — so it honours\n * the user's mode directly, with no `previewMode` gate of the kind `Canvas.vue`\n * needs. Re-provided rather than left to inherit, because a `BlockPreviewCanvas`\n * inside a dialog may sit under an editing `Canvas` that provides `false`.\n */\nconst mergeTagSampleMode = inject(MERGE_TAG_SAMPLE_MODE_KEY, null);\nprovide(\n USE_MERGE_TAG_SAMPLES_KEY,\n computed(() => mergeTagSampleMode?.value ?? false),\n);\n\n/**\n * Blocks a display condition currently excludes, so a preview never shows\n * content the recipient won't get. The canvas does the same via\n * `v-show=\"!conditionPreview?.isHidden(block.id)\"`.\n *\n * A no-op for the saved-blocks browser: entries there carry their *stored* ids,\n * which aren't in the current template, so nothing is tracked as hidden. It\n * bites where it should — the save dialog and the test-email preview, both of\n * which show blocks that are live on the canvas.\n *\n * Skipped entirely when `applyConditionFilter` is false — see the prop.\n */\nconst visibleBlocks = computed(() =>\n props.applyConditionFilter\n ? props.blocks.filter((block) => !conditionPreview?.isHidden(block.id))\n : props.blocks,\n);\n\nconst previewSettings = computed(\n () => props.settings ?? editor?.content.value.settings,\n);\n\n/**\n * Frame width, from the one helper the canvas and the scaled preview rows also\n * use — so all three agree by construction rather than by three constants that\n * happen to match. A template with a custom body width now previews at that\n * width instead of a flat 600.\n */\nconst frameWidth = computed(() =>\n getEmailFrameWidth(previewSettings.value, props.viewport),\n);\n\n/**\n * The same document-level style the canvas applies, so a previewed block\n * renders identically to the canvas one: without it the font falls back to the\n * editor UI's and the link rules hit their unset defaults, dropping the\n * underline and the link colour.\n *\n * Read from the *current* template even in the saved-blocks browser, where the\n * previewed content came from elsewhere — a saved block stores only `Block[]`,\n * and the current settings are what it will actually look like once inserted.\n */\nconst documentStyle = computed(() =>\n previewSettings.value ? getDocumentStyle(previewSettings.value) : {},\n);\n\n/**\n * The email's own language, for the browser's spellchecker and hyphenation —\n * the same binding the editing canvas carries, so a preview is checked by the\n * same rules as the block it mirrors.\n *\n * From `settings.locale`, never `config.locale`: the chrome's language says\n * nothing about the content's. Read from the *current* template for the same\n * reason `documentStyle` is — a saved block stores only `Block[]`. Undefined\n * rather than `\"\"`, which would declare \"unknown language\" and suppress\n * spellcheck instead of falling back.\n */\nconst contentLang = computed(\n () => previewSettings.value?.locale?.trim() || undefined,\n);\nconst contentDir = computed(() =>\n resolveContentDirection(previewSettings.value ?? { locale: \"en\" }),\n);\n\n/**\n * The email's body background — `mj-body background-color` when sent, and the\n * `.tpl-canvas-bg` layer on the editing canvas.\n *\n * Deliberately NOT part of `getDocumentStyle`: the canvas applies that helper\n * to `.tpl-canvas`, which must stay transparent so the invertible background\n * layer beneath it shows through. A background there would double-paint and\n * defeat the dark-mode preview.\n *\n * Truthiness, not `??`: the colour pickers clear to an empty string to mean\n * \"unset\", which as an inline style renders the frame transparent rather than\n * falling back to the neutral preview surface.\n */\nconst emailBackground = computed(\n () => previewSettings.value?.backgroundColor || \"var(--tpl-canvas-bg)\",\n);\n\n/**\n * Width the stage asks for: the content column plus a full gutter on each side,\n * the same stage the canvas builds. It is an ask rather than a fixed size —\n * paired with `max-width: 100%` below, so a container with less room hands over\n * what it has and shows a narrower band instead of overflowing.\n *\n * It has to be a specified width, not `100%`: `TplModal`'s wrapper is\n * shrink-to-fit, so a percentage there resolves against a container whose size\n * the stage is itself supposed to influence, and the stage collapses to its\n * `min-width` — no gutters, on the one surface this exists for.\n */\nconst stageWidth = computed(() => frameWidth.value + EMAIL_GUTTER * 2);\n\nconst previewComponentMap: Record<string, Component> = {\n section: PreviewSectionBlock,\n title: TitleBlock,\n paragraph: ParagraphBlock,\n image: ImageBlock,\n video: VideoBlock,\n button: ButtonBlock,\n divider: DividerBlock,\n social: SocialIconsBlock,\n menu: MenuBlock,\n table: TableBlock,\n spacer: SpacerBlock,\n html: HtmlBlock,\n custom: CustomBlock,\n wrapper: WrapperBlock,\n};\n\nfunction getBlockComponent(block: Block): Component | null {\n return resolveBlockComponent(block, blockRegistry, previewComponentMap);\n}\n</script>\n\n<template>\n <!-- STAGE — the email body, holding the background and a gutter of it on\n each side of the content column, the same shape `Canvas.vue` builds.\n `max-width: 100%` is what makes it fit anywhere: a roomy surface shows\n the full band, a dialog shows as much as it has, and a container sized to\n the content column shows none. `min-width` keeps it from squeezing the\n column, so a cramped surface clips exactly as it did when the frame\n carried the width itself. -->\n <div\n data-testid=\"block-preview-stage\"\n class=\"tpl:pointer-events-none tpl:mx-auto tpl:flex tpl:select-none tpl:justify-center tpl:rounded-lg\"\n :style=\"{\n width: `${stageWidth}px`,\n minWidth: `${frameWidth}px`,\n maxWidth: '100%',\n backgroundColor: emailBackground,\n boxShadow: 'var(--tpl-shadow-sm)',\n }\"\n >\n <!-- CONTENT COLUMN — the blocks at their true email width. Keeps the\n testid: this is the element whose width *is* the email width, which is\n what every viewport assertion measures. -->\n <div\n data-testid=\"block-preview-canvas\"\n :lang=\"contentLang\"\n :dir=\"contentDir\"\n :style=\"{\n width: `${frameWidth}px`,\n transition: EMAIL_FRAME_WIDTH_TRANSITION,\n ...documentStyle,\n }\"\n >\n <div\n v-for=\"block in visibleBlocks\"\n :key=\"block.id\"\n :style=\"getBlockWrapperStyle(block)\"\n >\n <component\n :is=\"getBlockComponent(block)\"\n :block=\"block\"\n :viewport=\"viewport\"\n />\n </div>\n </div>\n </div>\n</template>\n"],"mappings":"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"}