@templatical/editor 0.39.4 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/dist/{AiChatSidebar-5qqrS6uy.js → AiChatSidebar-a8TPBAl2.js} +3 -3
  2. package/dist/{AiFeatureMenu-BBO_Ojlp.js → AiFeatureMenu-CbgDjLqk.js} +3 -3
  3. package/dist/{BlockIssueBadge-D5oGxOQP.js → BlockIssueBadge-D8KsGWY6.js} +2 -2
  4. package/dist/BlockPreviewCanvas-XNV83YGg.js +133 -0
  5. package/dist/{CloudHeaderExtras-Cg6uF-yQ.js → CloudHeaderExtras-C-tbLyfE.js} +2 -2
  6. package/dist/{CloudPanels-D1Gg4qrG.js → CloudPanels-DnWDrgnQ.js} +4 -4
  7. package/dist/{CollaboratorBar-Cmn0LccS.js → CollaboratorBar-DUmeCkyD.js} +2 -2
  8. package/dist/{CommentsPanel-twNhYUqZ.js → CommentsPanel-9k1q-79y.js} +1 -1
  9. package/dist/{CommentsSidebar-DDO0Qx8U.js → CommentsSidebar-Bc7nORmD.js} +2 -2
  10. package/dist/{CountdownBlock-DSvbf3qU.js → CountdownBlock-C6R-hn7D.js} +1 -1
  11. package/dist/{CountdownToolbar-nvHxu8Gu.js → CountdownToolbar-DkC-qSgq.js} +4 -4
  12. package/dist/{DesignReferenceSidebar-C8ohNhOd.js → DesignReferenceSidebar-OoiYJAKS.js} +3 -3
  13. package/dist/{IssuesPanel-Ck0EGoV5.js → IssuesPanel-Dnns3O9z.js} +3 -3
  14. package/dist/{LogicTagInsertButton-D8IwH-9Z.js → LogicTagInsertButton-BimKobaG.js} +67 -67
  15. package/dist/{MergeTagInput-QI-5KG2R.js → MergeTagInput-DqpVzhy7.js} +1 -1
  16. package/dist/{MergeTagModeToggle-D793Bj_E.js → MergeTagModeToggle-BkIiAgpQ.js} +4 -4
  17. package/dist/{ParagraphEditor-D6FRxr8Y.js → ParagraphEditor-D67Cqh-T.js} +19 -19
  18. package/dist/{RestoreVersionDialog--b0qfNaK.js → RestoreVersionDialog-BaKDuPCX.js} +2 -2
  19. package/dist/{RichTextEditorContent-BC5UTVnb.js → RichTextEditorContent-AEtfKvLz.js} +5 -5
  20. package/dist/{SaveBlockDialog-C0BdEGeL.js → SaveBlockDialog-BxkI52fN.js} +8 -8
  21. package/dist/{SavedBlocksBrowserModal-BzDgXtr4.js → SavedBlocksBrowserModal-C4_25Kvn.js} +6 -6
  22. package/dist/{SavedBlocksPanels-DN-bDZzy.js → SavedBlocksPanels-DQ0w9G1O.js} +1 -1
  23. package/dist/{SavedBlocksPickBar-pEi9Et8Q.js → SavedBlocksPickBar-CtH-sfxh.js} +2 -2
  24. package/dist/{TemplateScoringPanel-B1wcfE0w.js → TemplateScoringPanel-Cs0TGtRF.js} +3 -3
  25. package/dist/{TemplateSettings-C_5leDdF.js → TemplateSettings-BD1WNP4C.js} +7 -7
  26. package/dist/{TestEmailModal-maM8SLBV.js → TestEmailModal-DZi58FU9.js} +70 -65
  27. package/dist/{TestEmailPanel-8iAZYpCK.js → TestEmailPanel-D__9Wvgz.js} +1 -1
  28. package/dist/{TitleEditor-L26QXwna.js → TitleEditor-v5p89Djs.js} +9 -9
  29. package/dist/{ToggleSwitch-JvQ_CmI1.js → ToggleSwitch-CJfQ8u57.js} +1 -1
  30. package/dist/{Toolbar-B2kDLFhn.js → Toolbar-C7SjilzH.js} +540 -525
  31. package/dist/{TplModal-DVMS_nAn.js → TplModal-B8uLyoXE.js} +3 -3
  32. package/dist/{VersionHistoryMenu-BVQityes.js → VersionHistoryMenu-b0A8mS2_.js} +2 -2
  33. package/dist/{VersionHistoryPanels-D8f8KvKX.js → VersionHistoryPanels-DfNrRT6y.js} +1 -1
  34. package/dist/{VersionPreviewBanner-BaMSgA1O.js → VersionPreviewBanner-xB9r83r0.js} +1 -1
  35. package/dist/WrapperBlock-yGmKw0T-.js +34 -0
  36. package/dist/{blockTypeIcons-CdXugKyV.js → blockTypeIcons-B0Bq1WT1.js} +1 -1
  37. package/dist/bundle-stats.json +6 -6
  38. package/dist/{ca-Bqeygp1_.js → ca-Ckgw9yd0.js} +1 -0
  39. package/dist/cdn/chunks/{AiChatSidebar-ctfIU4i0.js → AiChatSidebar-mKImUXi6.js} +7 -7
  40. package/dist/cdn/chunks/{AiChatSidebar-ctfIU4i0.js.map → AiChatSidebar-mKImUXi6.js.map} +1 -1
  41. package/dist/cdn/chunks/{AiFeatureMenu-ByygdH_9.js → AiFeatureMenu-23HCL517.js} +4 -4
  42. package/dist/cdn/chunks/{AiFeatureMenu-ByygdH_9.js.map → AiFeatureMenu-23HCL517.js.map} +1 -1
  43. package/dist/cdn/chunks/{BlockIssueBadge-9hHpaXb9.js → BlockIssueBadge-DS1pUf5g.js} +3 -3
  44. package/dist/cdn/chunks/{BlockIssueBadge-9hHpaXb9.js.map → BlockIssueBadge-DS1pUf5g.js.map} +1 -1
  45. package/dist/cdn/chunks/BlockPreviewCanvas-DObWyQfh.js +135 -0
  46. package/dist/cdn/chunks/BlockPreviewCanvas-DObWyQfh.js.map +1 -0
  47. package/dist/cdn/chunks/{CloudHeaderExtras-BxsMpvVr.js → CloudHeaderExtras-DOB_uWpt.js} +3 -3
  48. package/dist/cdn/chunks/{CloudHeaderExtras-BxsMpvVr.js.map → CloudHeaderExtras-DOB_uWpt.js.map} +1 -1
  49. package/dist/cdn/chunks/{CloudPanels-DmxmqAS_.js → CloudPanels-DcAn5QW7.js} +5 -5
  50. package/dist/cdn/chunks/{CloudPanels-DmxmqAS_.js.map → CloudPanels-DcAn5QW7.js.map} +1 -1
  51. package/dist/cdn/chunks/{CollaboratorBar-B8ttqAqX.js → CollaboratorBar-C0M8c2Vv.js} +3 -3
  52. package/dist/cdn/chunks/{CollaboratorBar-B8ttqAqX.js.map → CollaboratorBar-C0M8c2Vv.js.map} +1 -1
  53. package/dist/cdn/chunks/{CommentsPanel-C8ibhaiK.js → CommentsPanel-BtAGZfF6.js} +2 -2
  54. package/dist/cdn/chunks/{CommentsPanel-C8ibhaiK.js.map → CommentsPanel-BtAGZfF6.js.map} +1 -1
  55. package/dist/cdn/chunks/{CommentsSidebar-CybWfZ3V.js → CommentsSidebar-Ws07MXYj.js} +3 -3
  56. package/dist/cdn/chunks/{CommentsSidebar-CybWfZ3V.js.map → CommentsSidebar-Ws07MXYj.js.map} +1 -1
  57. package/dist/cdn/chunks/{CountdownBlock-DdC8Lg5F.js → CountdownBlock-sVDjKkRw.js} +2 -2
  58. package/dist/cdn/chunks/{CountdownBlock-DdC8Lg5F.js.map → CountdownBlock-sVDjKkRw.js.map} +1 -1
  59. package/dist/cdn/chunks/{CountdownToolbar-DRESXiVD.js → CountdownToolbar-Bu93WiS8.js} +5 -5
  60. package/dist/cdn/chunks/{CountdownToolbar-DRESXiVD.js.map → CountdownToolbar-Bu93WiS8.js.map} +1 -1
  61. package/dist/cdn/chunks/{DesignReferenceSidebar-CtaoY-hl.js → DesignReferenceSidebar-BlSdh5B7.js} +4 -4
  62. package/dist/cdn/chunks/{DesignReferenceSidebar-CtaoY-hl.js.map → DesignReferenceSidebar-BlSdh5B7.js.map} +1 -1
  63. package/dist/cdn/chunks/{IssuesPanel-C6RlIxoi.js → IssuesPanel-CKkv9z9g.js} +4 -4
  64. package/dist/cdn/chunks/{IssuesPanel-C6RlIxoi.js.map → IssuesPanel-CKkv9z9g.js.map} +1 -1
  65. package/dist/cdn/chunks/{LogicTagInsertButton-DpyPozop.js → LogicTagInsertButton-CHc1yZ9v.js} +165 -165
  66. package/dist/cdn/chunks/{LogicTagInsertButton-DpyPozop.js.map → LogicTagInsertButton-CHc1yZ9v.js.map} +1 -1
  67. package/dist/cdn/chunks/{MergeTagInput-ERJr7bP_.js → MergeTagInput--qTYfCWk.js} +2 -2
  68. package/dist/cdn/chunks/{MergeTagInput-ERJr7bP_.js.map → MergeTagInput--qTYfCWk.js.map} +1 -1
  69. package/dist/cdn/chunks/{MergeTagModeToggle-n3nvSNeQ.js → MergeTagModeToggle-CdWIGo3Q.js} +5 -5
  70. package/dist/cdn/chunks/{MergeTagModeToggle-n3nvSNeQ.js.map → MergeTagModeToggle-CdWIGo3Q.js.map} +1 -1
  71. package/dist/cdn/chunks/{ParagraphEditor-R2ph_UOo.js → ParagraphEditor-BilbVtrG.js} +17 -17
  72. package/dist/cdn/chunks/{ParagraphEditor-R2ph_UOo.js.map → ParagraphEditor-BilbVtrG.js.map} +1 -1
  73. package/dist/cdn/chunks/{RestoreVersionDialog-C-dwbb7T.js → RestoreVersionDialog-Q-a44Vjv.js} +3 -3
  74. package/dist/cdn/chunks/{RestoreVersionDialog-C-dwbb7T.js.map → RestoreVersionDialog-Q-a44Vjv.js.map} +1 -1
  75. package/dist/cdn/chunks/{RichTextEditorContent-Ch5zeyZ7.js → RichTextEditorContent-Fzuu9pLP.js} +6 -6
  76. package/dist/cdn/chunks/{RichTextEditorContent-Ch5zeyZ7.js.map → RichTextEditorContent-Fzuu9pLP.js.map} +1 -1
  77. package/dist/cdn/chunks/{SaveBlockDialog-C_BPjVv6.js → SaveBlockDialog-DeW_M6kh.js} +9 -9
  78. package/dist/cdn/chunks/{SaveBlockDialog-C_BPjVv6.js.map → SaveBlockDialog-DeW_M6kh.js.map} +1 -1
  79. package/dist/cdn/chunks/{SavedBlocksBrowserModal-CrrGEfFb.js → SavedBlocksBrowserModal-BzQWibKG.js} +6 -6
  80. package/dist/cdn/chunks/{SavedBlocksBrowserModal-CrrGEfFb.js.map → SavedBlocksBrowserModal-BzQWibKG.js.map} +1 -1
  81. package/dist/cdn/chunks/{SavedBlocksPanels-DfTaMPAr.js → SavedBlocksPanels-Ce1RePjk.js} +2 -2
  82. package/dist/cdn/chunks/{SavedBlocksPanels-DfTaMPAr.js.map → SavedBlocksPanels-Ce1RePjk.js.map} +1 -1
  83. package/dist/cdn/chunks/{SavedBlocksPickBar-DziwHYSu.js → SavedBlocksPickBar-DIDl6xfy.js} +3 -3
  84. package/dist/cdn/chunks/{SavedBlocksPickBar-DziwHYSu.js.map → SavedBlocksPickBar-DIDl6xfy.js.map} +1 -1
  85. package/dist/cdn/chunks/{TemplateScoringPanel-CR6RG6dZ.js → TemplateScoringPanel-d_Ppowsq.js} +49 -49
  86. package/dist/cdn/chunks/{TemplateScoringPanel-CR6RG6dZ.js.map → TemplateScoringPanel-d_Ppowsq.js.map} +1 -1
  87. package/dist/cdn/chunks/{TemplateSettings-DjXiiiNr.js → TemplateSettings-Dr5OJ0Gi.js} +8 -8
  88. package/dist/cdn/chunks/{TemplateSettings-DjXiiiNr.js.map → TemplateSettings-Dr5OJ0Gi.js.map} +1 -1
  89. package/dist/cdn/chunks/{TestEmailModal-DId9Og-N.js → TestEmailModal-CWTmaJuT.js} +56 -51
  90. package/dist/cdn/chunks/TestEmailModal-CWTmaJuT.js.map +1 -0
  91. package/dist/cdn/chunks/{TestEmailPanel-B8LwXmeX.js → TestEmailPanel-BdYsVHXA.js} +2 -2
  92. package/dist/cdn/chunks/{TestEmailPanel-B8LwXmeX.js.map → TestEmailPanel-BdYsVHXA.js.map} +1 -1
  93. package/dist/cdn/chunks/{TitleEditor-C7KMzX1e.js → TitleEditor-pJeeZ-PX.js} +9 -9
  94. package/dist/cdn/chunks/{TitleEditor-C7KMzX1e.js.map → TitleEditor-pJeeZ-PX.js.map} +1 -1
  95. package/dist/cdn/chunks/{ToggleSwitch-CDy8OfcB.js → ToggleSwitch-0dGCYnRY.js} +2 -2
  96. package/dist/cdn/chunks/{ToggleSwitch-CDy8OfcB.js.map → ToggleSwitch-0dGCYnRY.js.map} +1 -1
  97. package/dist/cdn/chunks/{Toolbar-DqFhWxgW.js → Toolbar-BsiHW9gY.js} +493 -478
  98. package/dist/cdn/chunks/{Toolbar-DqFhWxgW.js.map → Toolbar-BsiHW9gY.js.map} +1 -1
  99. package/dist/cdn/chunks/{TplModal-BKqDFLq3.js → TplModal-CEuGD7pt.js} +4 -4
  100. package/dist/cdn/chunks/{TplModal-BKqDFLq3.js.map → TplModal-CEuGD7pt.js.map} +1 -1
  101. package/dist/cdn/chunks/{VersionHistoryMenu-Dij1pTEb.js → VersionHistoryMenu-B3-hNu9c.js} +3 -3
  102. package/dist/cdn/chunks/{VersionHistoryMenu-Dij1pTEb.js.map → VersionHistoryMenu-B3-hNu9c.js.map} +1 -1
  103. package/dist/cdn/chunks/{VersionHistoryPanels-DcCFFDK6.js → VersionHistoryPanels-C1yck5gT.js} +2 -2
  104. package/dist/cdn/chunks/{VersionHistoryPanels-DcCFFDK6.js.map → VersionHistoryPanels-C1yck5gT.js.map} +1 -1
  105. package/dist/cdn/chunks/{VersionPreviewBanner-Df3FVlig.js → VersionPreviewBanner-PzVQSBJE.js} +2 -2
  106. package/dist/cdn/chunks/{VersionPreviewBanner-Df3FVlig.js.map → VersionPreviewBanner-PzVQSBJE.js.map} +1 -1
  107. package/dist/cdn/chunks/WrapperBlock-DGkbmj06.js +36 -0
  108. package/dist/cdn/chunks/WrapperBlock-DGkbmj06.js.map +1 -0
  109. package/dist/cdn/chunks/{ca-Bqeygp1_.js → ca-Ckgw9yd0.js} +2 -1
  110. package/dist/cdn/chunks/ca-Ckgw9yd0.js.map +1 -0
  111. package/dist/cdn/chunks/{cloud-eaXyxZ8l.js → cloud-CIT4yPp4.js} +2 -2
  112. package/dist/cdn/chunks/{cloud-eaXyxZ8l.js.map → cloud-CIT4yPp4.js.map} +1 -1
  113. package/dist/cdn/chunks/{createCloudRuntime-D5bXzcTe.js → createCloudRuntime-COUxbPvd.js} +49 -40
  114. package/dist/cdn/chunks/createCloudRuntime-COUxbPvd.js.map +1 -0
  115. package/dist/cdn/chunks/{de-CY6SlqBx.js → de-D4dweQw8.js} +2 -1
  116. package/dist/cdn/chunks/de-D4dweQw8.js.map +1 -0
  117. package/dist/{en-8V-2kDcp.js → cdn/chunks/en-VE7R7NyL.js} +3 -0
  118. package/dist/cdn/chunks/en-VE7R7NyL.js.map +1 -0
  119. package/dist/{es-Cmn1rT3l.js → cdn/chunks/es-B9OhP8H3.js} +3 -0
  120. package/dist/cdn/chunks/es-B9OhP8H3.js.map +1 -0
  121. package/dist/cdn/chunks/{extensions-Bhu8UEE5.js → extensions-CafoGF65.js} +5 -5
  122. package/dist/cdn/chunks/{extensions-Bhu8UEE5.js.map → extensions-CafoGF65.js.map} +1 -1
  123. package/dist/cdn/chunks/{fr-2yDa4zXM.js → fr-wrXhIi00.js} +2 -1
  124. package/dist/cdn/chunks/fr-wrXhIi00.js.map +1 -0
  125. package/dist/cdn/chunks/keys-DCWeHkSF.js +12 -0
  126. package/dist/cdn/chunks/keys-DCWeHkSF.js.map +1 -0
  127. package/dist/{nl-Bzk2zRI8.js → cdn/chunks/nl-DeFatKJe.js} +3 -0
  128. package/dist/cdn/chunks/nl-DeFatKJe.js.map +1 -0
  129. package/dist/cdn/chunks/preRenderCustomBlocks-Dpj-_cOj.js +21 -0
  130. package/dist/cdn/chunks/preRenderCustomBlocks-Dpj-_cOj.js.map +1 -0
  131. package/dist/cdn/chunks/{pt-BR-DqtSCTUi.js → pt-BR-Bh1J8ey6.js} +2 -1
  132. package/dist/cdn/chunks/pt-BR-Bh1J8ey6.js.map +1 -0
  133. package/dist/cdn/chunks/{socialIcons-9VrG8X3m.js → socialIcons-BvYNMn1G.js} +264 -258
  134. package/dist/cdn/chunks/socialIcons-BvYNMn1G.js.map +1 -0
  135. package/dist/cdn/chunks/{src-CqYYKcCI.js → src-CbGCES0u.js} +175 -168
  136. package/dist/cdn/chunks/src-CbGCES0u.js.map +1 -0
  137. package/dist/cdn/chunks/{src-CaNsA_WX.js → src-Cnc5E71L.js} +258 -247
  138. package/dist/cdn/chunks/src-Cnc5E71L.js.map +1 -0
  139. package/dist/cdn/chunks/{src-Dwgq7hf4.js → src-DveVYoWS.js} +281 -181
  140. package/dist/cdn/chunks/src-DveVYoWS.js.map +1 -0
  141. package/dist/cdn/chunks/{useCloudI18n-C09JcFS0.js → useCloudI18n-CrjWbpbu.js} +2 -2
  142. package/dist/cdn/chunks/{useCloudI18n-C09JcFS0.js.map → useCloudI18n-CrjWbpbu.js.map} +1 -1
  143. package/dist/cdn/chunks/{useEditorCore-CXYI14ux.js → useEditorCore-CQraU2s_.js} +421 -408
  144. package/dist/cdn/chunks/useEditorCore-CQraU2s_.js.map +1 -0
  145. package/dist/cdn/chunks/{useEditorRoot-DFx2fXJP.js → useEditorRoot-CshefZLP.js} +2 -2
  146. package/dist/cdn/chunks/{useEditorRoot-DFx2fXJP.js.map → useEditorRoot-CshefZLP.js.map} +1 -1
  147. package/dist/cdn/chunks/{useI18n-DTZ9sIcv.js → useI18n-CyO_Nmca.js} +2 -2
  148. package/dist/cdn/chunks/{useI18n-DTZ9sIcv.js.map → useI18n-CyO_Nmca.js.map} +1 -1
  149. package/dist/cdn/chunks/{useLogicTag-E2V0Xdcb.js → useLogicTag-DF7-l66G.js} +4 -4
  150. package/dist/cdn/chunks/{useLogicTag-E2V0Xdcb.js.map → useLogicTag-DF7-l66G.js.map} +1 -1
  151. package/dist/cdn/chunks/{useMergeTag-BE8oDoha.js → useMergeTag-DbIHw4NG.js} +4 -4
  152. package/dist/cdn/chunks/{useMergeTag-BE8oDoha.js.map → useMergeTag-DbIHw4NG.js.map} +1 -1
  153. package/dist/cdn/chunks/{usePopoverPosition-gB9q-ql7.js → usePopoverPosition-BJRvAb-h.js} +2 -2
  154. package/dist/cdn/chunks/{usePopoverPosition-gB9q-ql7.js.map → usePopoverPosition-BJRvAb-h.js.map} +1 -1
  155. package/dist/cdn/chunks/{useScrollToBlock-CtTXwmiU.js → useScrollToBlock-DgHZJvID.js} +2 -2
  156. package/dist/cdn/chunks/{useScrollToBlock-CtTXwmiU.js.map → useScrollToBlock-DgHZJvID.js.map} +1 -1
  157. package/dist/cdn/editor.css +1 -1
  158. package/dist/cdn/editor.js +484 -460
  159. package/dist/cdn/editor.js.map +1 -1
  160. package/dist/{cloud-C9xWZXhg.js → cloud-DsqqUfzh.js} +1 -1
  161. package/dist/{createCloudRuntime-BGd5--Bq.js → createCloudRuntime-iLflkYzP.js} +47 -38
  162. package/dist/{de-CY6SlqBx.js → de-D4dweQw8.js} +1 -0
  163. package/dist/{dist-tGkjkX-v.js → dist-DbUZvK04.js} +277 -176
  164. package/dist/{cdn/chunks/en-8V-2kDcp.js → en-VE7R7NyL.js} +1 -2
  165. package/dist/{cdn/chunks/es-Cmn1rT3l.js → es-B9OhP8H3.js} +1 -2
  166. package/dist/{extensions-DRN-elXT.js → extensions-DDhjuVKy.js} +4 -4
  167. package/dist/{fr-2yDa4zXM.js → fr-wrXhIi00.js} +1 -0
  168. package/dist/index.d.ts +65 -0
  169. package/dist/keys-CDqfZIRt.js +10 -0
  170. package/dist/{cdn/chunks/nl-Bzk2zRI8.js → nl-DeFatKJe.js} +1 -2
  171. package/dist/preRenderCustomBlocks-BBSqQgke.js +19 -0
  172. package/dist/{pt-BR-DqtSCTUi.js → pt-BR-Bh1J8ey6.js} +1 -0
  173. package/dist/{socialIcons-DkGcpEwC.js → socialIcons-O7PZCW2P.js} +245 -239
  174. package/dist/style.css +1 -1
  175. package/dist/templatical-editor.js +520 -496
  176. package/dist/{useCloudI18n-D1iedlP3.js → useCloudI18n-DpEsiLeR.js} +1 -1
  177. package/dist/{useEditorCore-BUVbQgwb.js → useEditorCore-Dt_VWNqX.js} +817 -804
  178. package/dist/{useEditorRoot-BOxn5EfP.js → useEditorRoot-CkB_5d0h.js} +1 -1
  179. package/dist/{useI18n-Ds_-druD.js → useI18n-B_CdcBwG.js} +1 -1
  180. package/dist/{useLogicTag-DoHfc08B.js → useLogicTag-D9pvgxQR.js} +3 -3
  181. package/dist/{useMergeTag-DXyum3kG.js → useMergeTag-BaVFPdlq.js} +5 -5
  182. package/dist/{usePopoverPosition-Du-Ah8E9.js → usePopoverPosition-DH7z3Ghm.js} +1 -1
  183. package/dist/{useScrollToBlock-DXQYPCnJ.js → useScrollToBlock-Dj4v3rxr.js} +1 -1
  184. package/package.json +7 -7
  185. package/dist/BlockPreviewCanvas-BMC16_QU.js +0 -131
  186. package/dist/cdn/chunks/BlockPreviewCanvas-DeS7Sa--.js +0 -133
  187. package/dist/cdn/chunks/BlockPreviewCanvas-DeS7Sa--.js.map +0 -1
  188. package/dist/cdn/chunks/TestEmailModal-DId9Og-N.js.map +0 -1
  189. package/dist/cdn/chunks/ca-Bqeygp1_.js.map +0 -1
  190. package/dist/cdn/chunks/createCloudRuntime-D5bXzcTe.js.map +0 -1
  191. package/dist/cdn/chunks/de-CY6SlqBx.js.map +0 -1
  192. package/dist/cdn/chunks/emailFrameWidth-BmFCN2dp.js +0 -8
  193. package/dist/cdn/chunks/emailFrameWidth-BmFCN2dp.js.map +0 -1
  194. package/dist/cdn/chunks/en-8V-2kDcp.js.map +0 -1
  195. package/dist/cdn/chunks/es-Cmn1rT3l.js.map +0 -1
  196. package/dist/cdn/chunks/fr-2yDa4zXM.js.map +0 -1
  197. package/dist/cdn/chunks/keys-dJbD1QPs.js +0 -12
  198. package/dist/cdn/chunks/keys-dJbD1QPs.js.map +0 -1
  199. package/dist/cdn/chunks/nl-Bzk2zRI8.js.map +0 -1
  200. package/dist/cdn/chunks/preRenderCustomBlocks-Bdpiiw4A.js +0 -23
  201. package/dist/cdn/chunks/preRenderCustomBlocks-Bdpiiw4A.js.map +0 -1
  202. package/dist/cdn/chunks/pt-BR-DqtSCTUi.js.map +0 -1
  203. package/dist/cdn/chunks/socialIcons-9VrG8X3m.js.map +0 -1
  204. package/dist/cdn/chunks/src-CaNsA_WX.js.map +0 -1
  205. package/dist/cdn/chunks/src-CqYYKcCI.js.map +0 -1
  206. package/dist/cdn/chunks/src-Dwgq7hf4.js.map +0 -1
  207. package/dist/cdn/chunks/useEditorCore-CXYI14ux.js.map +0 -1
  208. package/dist/emailFrameWidth-BmFCN2dp.js +0 -6
  209. package/dist/keys-BdoSgsz9.js +0 -10
  210. package/dist/preRenderCustomBlocks-DFXH54Zr.js +0 -21
@@ -1,5 +1,5 @@
1
1
  import { E as e } from "./draggable-IB4x6w2O.js";
2
- import { _ as t } from "./keys-dJbD1QPs.js";
2
+ import { _ as t } from "./keys-DCWeHkSF.js";
3
3
  //#region src/composables/useEditorRoot.ts
4
4
  function n() {
5
5
  return e(t, document) ?? document;
@@ -7,4 +7,4 @@ function n() {
7
7
  //#endregion
8
8
  export { n as t };
9
9
 
10
- //# sourceMappingURL=useEditorRoot-DFx2fXJP.js.map
10
+ //# sourceMappingURL=useEditorRoot-CshefZLP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useEditorRoot-DFx2fXJP.js","names":[],"sources":["../../../src/composables/useEditorRoot.ts"],"sourcesContent":["import { inject } from \"vue\";\nimport { EDITOR_ROOT_KEY } from \"../keys\";\n\n/**\n * Returns the editor's effective DOM root — `Document` when mounted in light\n * DOM, `ShadowRoot` when mounted with `shadowDom: true`.\n *\n * Use this instead of reaching for `document` directly when the code is\n * shadow-DOM-aware (focus trap, selection, popover mount, etc.). Both\n * `Document` and `ShadowRoot` expose the same subset of APIs the editor\n * needs (`activeElement`, `getSelection?`, `querySelector`, `appendChild`),\n * so call sites usually don't need to branch.\n *\n * Falls back to `document` if no provider is in scope — keeps headless /\n * test-utility usage working without explicit wiring.\n *\n * Internal — not exported from the package entry.\n */\nexport function useEditorRoot(): Document | ShadowRoot {\n // When called outside a Vue setup() context (e.g. direct composable\n // invocation in unit tests), Vue's inject() warns and returns undefined\n // regardless of the default arg. Coalesce explicitly so callers always\n // get a usable root — keeps test ergonomics simple and matches the\n // \"headless fallback to document\" semantics this composable promises.\n const root = inject(EDITOR_ROOT_KEY, document);\n return root ?? document;\n}\n"],"mappings":";;;AAkBA,SAAgB,IAAuC;CAOrD,OADa,EAAO,GAAiB,QAC9B,KAAQ;AACjB"}
1
+ {"version":3,"file":"useEditorRoot-CshefZLP.js","names":[],"sources":["../../../src/composables/useEditorRoot.ts"],"sourcesContent":["import { inject } from \"vue\";\nimport { EDITOR_ROOT_KEY } from \"../keys\";\n\n/**\n * Returns the editor's effective DOM root — `Document` when mounted in light\n * DOM, `ShadowRoot` when mounted with `shadowDom: true`.\n *\n * Use this instead of reaching for `document` directly when the code is\n * shadow-DOM-aware (focus trap, selection, popover mount, etc.). Both\n * `Document` and `ShadowRoot` expose the same subset of APIs the editor\n * needs (`activeElement`, `getSelection?`, `querySelector`, `appendChild`),\n * so call sites usually don't need to branch.\n *\n * Falls back to `document` if no provider is in scope — keeps headless /\n * test-utility usage working without explicit wiring.\n *\n * Internal — not exported from the package entry.\n */\nexport function useEditorRoot(): Document | ShadowRoot {\n // When called outside a Vue setup() context (e.g. direct composable\n // invocation in unit tests), Vue's inject() warns and returns undefined\n // regardless of the default arg. Coalesce explicitly so callers always\n // get a usable root — keeps test ergonomics simple and matches the\n // \"headless fallback to document\" semantics this composable promises.\n const root = inject(EDITOR_ROOT_KEY, document);\n return root ?? document;\n}\n"],"mappings":";;;AAkBA,SAAgB,IAAuC;CAOrD,OADa,EAAO,GAAiB,QAC9B,KAAQ;AACjB"}
@@ -1,5 +1,5 @@
1
1
  import { E as e, q as t } from "./draggable-IB4x6w2O.js";
2
- import { q as n } from "./keys-dJbD1QPs.js";
2
+ import { Y as n } from "./keys-DCWeHkSF.js";
3
3
  //#region src/composables/useI18n.ts
4
4
  function r(r) {
5
5
  let i = r ?? e(n, null);
@@ -16,4 +16,4 @@ function r(r) {
16
16
  //#endregion
17
17
  export { r as t };
18
18
 
19
- //# sourceMappingURL=useI18n-DTZ9sIcv.js.map
19
+ //# sourceMappingURL=useI18n-CyO_Nmca.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useI18n-DTZ9sIcv.js","names":[],"sources":["../../../src/composables/useI18n.ts"],"sourcesContent":["import type { Translations } from \"../i18n\";\nimport { type Ref, inject, isRef } from \"vue\";\nimport { TRANSLATIONS_KEY } from \"../keys\";\n\nexport interface UseI18nReturn {\n /** Current translations object */\n t: Translations;\n /** Format a string with placeholders */\n format: (template: string, values: Record<string, string | number>) => string;\n}\n\n/**\n * Composable for internationalization.\n * Provides access to the current locale's translations.\n *\n * @param translationsOverride - Optional translations to use instead of injected value\n */\nexport function useI18n(translationsOverride?: Translations): UseI18nReturn {\n const injected =\n translationsOverride ??\n (inject(TRANSLATIONS_KEY, null) as Translations | Ref<Translations> | null);\n\n if (!injected) {\n throw new Error(\n \"useI18n() requires a translations provider. Ensure the component renders inside the editor, below Editor.vue.\",\n );\n }\n\n const t: Translations = isRef(injected) ? injected.value : injected;\n\n /**\n * Format a string with placeholders.\n * e.g., format('{minutes}m ago', { minutes: 5 }) -> '5m ago'\n */\n function format(\n template: string,\n values: Record<string, string | number>,\n ): string {\n return template.replace(/\\{(\\w+)\\}/g, (_, key) => {\n return key in values ? String(values[key]) : `{${key}}`;\n });\n }\n\n return {\n t,\n format,\n };\n}\n"],"mappings":";;;AAiBA,SAAgB,EAAQ,GAAoD;CAC1E,IAAM,IACJ,KACC,EAAO,GAAkB,IAAI;CAEhC,IAAI,CAAC,GACH,MAAU,MACR,+GACF;CAGF,IAAM,IAAkB,EAAM,CAAQ,IAAI,EAAS,QAAQ;CAM3D,SAAS,EACP,GACA,GACQ;EACR,OAAO,EAAS,QAAQ,eAAe,GAAG,MACjC,KAAO,IAAS,OAAO,EAAO,EAAI,IAAI,IAAI,EAAI,EACtD;CACH;CAEA,OAAO;EACL;EACA;CACF;AACF"}
1
+ {"version":3,"file":"useI18n-CyO_Nmca.js","names":[],"sources":["../../../src/composables/useI18n.ts"],"sourcesContent":["import type { Translations } from \"../i18n\";\nimport { type Ref, inject, isRef } from \"vue\";\nimport { TRANSLATIONS_KEY } from \"../keys\";\n\nexport interface UseI18nReturn {\n /** Current translations object */\n t: Translations;\n /** Format a string with placeholders */\n format: (template: string, values: Record<string, string | number>) => string;\n}\n\n/**\n * Composable for internationalization.\n * Provides access to the current locale's translations.\n *\n * @param translationsOverride - Optional translations to use instead of injected value\n */\nexport function useI18n(translationsOverride?: Translations): UseI18nReturn {\n const injected =\n translationsOverride ??\n (inject(TRANSLATIONS_KEY, null) as Translations | Ref<Translations> | null);\n\n if (!injected) {\n throw new Error(\n \"useI18n() requires a translations provider. Ensure the component renders inside the editor, below Editor.vue.\",\n );\n }\n\n const t: Translations = isRef(injected) ? injected.value : injected;\n\n /**\n * Format a string with placeholders.\n * e.g., format('{minutes}m ago', { minutes: 5 }) -> '5m ago'\n */\n function format(\n template: string,\n values: Record<string, string | number>,\n ): string {\n return template.replace(/\\{(\\w+)\\}/g, (_, key) => {\n return key in values ? String(values[key]) : `{${key}}`;\n });\n }\n\n return {\n t,\n format,\n };\n}\n"],"mappings":";;;AAiBA,SAAgB,EAAQ,GAAoD;CAC1E,IAAM,IACJ,KACC,EAAO,GAAkB,IAAI;CAEhC,IAAI,CAAC,GACH,MAAU,MACR,+GACF;CAGF,IAAM,IAAkB,EAAM,CAAQ,IAAI,EAAS,QAAQ;CAM3D,SAAS,EACP,GACA,GACQ;EACR,OAAO,EAAS,QAAQ,eAAe,GAAG,MACjC,KAAO,IAAS,OAAO,EAAO,EAAI,IAAI,IAAI,EAAI,EACtD;CACH;CAEA,OAAO;EACL;EACA;CACF;AACF"}
@@ -1,9 +1,9 @@
1
1
  import { E as e, Q as t } from "./draggable-IB4x6w2O.js";
2
- import { r as n } from "./src-Dwgq7hf4.js";
3
- import { C as r, E as i, F as a, N as o, T as s, w as c } from "./keys-dJbD1QPs.js";
2
+ import { r as n } from "./src-DveVYoWS.js";
3
+ import { D as r, E as i, I as a, P as o, T as s, w as c } from "./keys-DCWeHkSF.js";
4
4
  //#region src/composables/useLogicTag.ts
5
5
  function l() {
6
- let l = e(c, []), u = e(r, []), d = e(o, n.liquid), f = e(a, null), p = e(s, null), m = e(i, null) ?? t(!1), h = !!f || l.length > 0 || u.length > 0, g = l.length > 0 || u.length > 0;
6
+ let l = e(s, []), u = e(c, []), d = e(o, n.liquid), f = e(a, null), p = e(i, null), m = e(r, null) ?? t(!1), h = !!f || l.length > 0 || u.length > 0, g = l.length > 0 || u.length > 0;
7
7
  async function _() {
8
8
  if (f) {
9
9
  m.value = !0;
@@ -35,4 +35,4 @@ function l() {
35
35
  //#endregion
36
36
  export { l as t };
37
37
 
38
- //# sourceMappingURL=useLogicTag-E2V0Xdcb.js.map
38
+ //# sourceMappingURL=useLogicTag-DF7-l66G.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLogicTag-E2V0Xdcb.js","names":[],"sources":["../../../src/composables/useLogicTag.ts"],"sourcesContent":["import type { LogicPair, LogicTag, SyntaxPreset } from \"@templatical/types\";\nimport { SYNTAX_PRESETS } from \"@templatical/types\";\nimport { inject, ref, type Ref } from \"vue\";\nimport {\n LOGIC_PAIRS_KEY,\n LOGIC_TAG_PICKER_KEY,\n LOGIC_TAG_REQUESTING_KEY,\n LOGIC_TAGS_KEY,\n MERGE_TAG_SYNTAX_KEY,\n ON_REQUEST_LOGIC_TAG_KEY,\n} from \"../keys\";\nimport type { LogicTagPickerResult } from \"./useLogicTagPicker\";\n\nexport interface UseLogicTagReturn {\n /** Configured standalone logic tags. */\n logicTags: LogicTag[];\n /** Configured open/close logic pairs. */\n logicPairs: LogicPair[];\n /** Resolved syntax preset — shared with merge tags; drives keyword badges. */\n syntax: SyntaxPreset;\n /**\n * Whether the \"Insert logic\" affordance should show. True when at least one\n * logic tag or pair is configured.\n */\n canInsertLogicTag: boolean;\n /** Whether a logic pick is in progress. */\n isRequesting: Ref<boolean>;\n /**\n * Open the built-in logic picker. Resolves with the chosen tag/pair, or null\n * when nothing is configured, the picker is unavailable (headless), or the\n * user cancels.\n */\n requestLogicTag: () => Promise<LogicTagPickerResult | null>;\n}\n\n/**\n * Composable for the standalone logic-tag feature — separate from merge tags.\n * Exposes configured logic tags/pairs and opens the built-in logic picker.\n */\nexport function useLogicTag(): UseLogicTagReturn {\n const logicTags = inject(LOGIC_TAGS_KEY, []);\n const logicPairs = inject(LOGIC_PAIRS_KEY, []);\n const syntax = inject(MERGE_TAG_SYNTAX_KEY, SYNTAX_PRESETS.liquid);\n const onRequest = inject(ON_REQUEST_LOGIC_TAG_KEY, null);\n // Picker may be null in headless contexts (tests, non-editor consumers).\n const picker = inject(LOGIC_TAG_PICKER_KEY, null);\n\n // Shared per editor — same reason as merge tags. See\n // LOGIC_TAG_REQUESTING_KEY.\n const isRequesting = inject(LOGIC_TAG_REQUESTING_KEY, null) ?? ref(false);\n\n // Show the affordance when a consumer callback is set OR static config\n // exists — mirrors useMergeTag's canRequestMergeTag.\n const canInsertLogicTag =\n !!onRequest || logicTags.length > 0 || logicPairs.length > 0;\n\n const hasStaticLogic = logicTags.length > 0 || logicPairs.length > 0;\n\n /**\n * Request a logic tag/pair from the user. Precedence:\n * 1. `logic.onRequest` callback (consumer-owned UX)\n * 2. Built-in picker over `logic.tags` / `logic.pairs`\n * 3. null (nothing configured / headless)\n */\n async function requestLogicTag(): Promise<LogicTagPickerResult | null> {\n if (onRequest) {\n isRequesting.value = true;\n try {\n return await onRequest();\n } finally {\n isRequesting.value = false;\n }\n }\n if (picker && hasStaticLogic) {\n isRequesting.value = true;\n try {\n return await picker.open(logicTags, logicPairs);\n } finally {\n isRequesting.value = false;\n }\n }\n return null;\n }\n\n return {\n logicTags,\n logicPairs,\n syntax,\n canInsertLogicTag,\n isRequesting,\n requestLogicTag,\n };\n}\n"],"mappings":";;;;AAuCA,SAAgB,IAAiC;CAC/C,IAAM,IAAY,EAAO,GAAgB,CAAC,CAAC,GACrC,IAAa,EAAO,GAAiB,CAAC,CAAC,GACvC,IAAS,EAAO,GAAsB,EAAe,MAAM,GAC3D,IAAY,EAAO,GAA0B,IAAI,GAEjD,IAAS,EAAO,GAAsB,IAAI,GAI1C,IAAe,EAAO,GAA0B,IAAI,KAAK,EAAI,EAAK,GAIlE,IACJ,CAAC,CAAC,KAAa,EAAU,SAAS,KAAK,EAAW,SAAS,GAEvD,IAAiB,EAAU,SAAS,KAAK,EAAW,SAAS;CAQnE,eAAe,IAAwD;EACrE,IAAI,GAAW;GACb,EAAa,QAAQ;GACrB,IAAI;IACF,OAAO,MAAM,EAAU;GACzB,UAAU;IACR,EAAa,QAAQ;GACvB;EACF;EACA,IAAI,KAAU,GAAgB;GAC5B,EAAa,QAAQ;GACrB,IAAI;IACF,OAAO,MAAM,EAAO,KAAK,GAAW,CAAU;GAChD,UAAU;IACR,EAAa,QAAQ;GACvB;EACF;EACA,OAAO;CACT;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"useLogicTag-DF7-l66G.js","names":[],"sources":["../../../src/composables/useLogicTag.ts"],"sourcesContent":["import type { LogicPair, LogicTag, SyntaxPreset } from \"@templatical/types\";\nimport { SYNTAX_PRESETS } from \"@templatical/types\";\nimport { inject, ref, type Ref } from \"vue\";\nimport {\n LOGIC_PAIRS_KEY,\n LOGIC_TAG_PICKER_KEY,\n LOGIC_TAG_REQUESTING_KEY,\n LOGIC_TAGS_KEY,\n MERGE_TAG_SYNTAX_KEY,\n ON_REQUEST_LOGIC_TAG_KEY,\n} from \"../keys\";\nimport type { LogicTagPickerResult } from \"./useLogicTagPicker\";\n\nexport interface UseLogicTagReturn {\n /** Configured standalone logic tags. */\n logicTags: LogicTag[];\n /** Configured open/close logic pairs. */\n logicPairs: LogicPair[];\n /** Resolved syntax preset — shared with merge tags; drives keyword badges. */\n syntax: SyntaxPreset;\n /**\n * Whether the \"Insert logic\" affordance should show. True when at least one\n * logic tag or pair is configured.\n */\n canInsertLogicTag: boolean;\n /** Whether a logic pick is in progress. */\n isRequesting: Ref<boolean>;\n /**\n * Open the built-in logic picker. Resolves with the chosen tag/pair, or null\n * when nothing is configured, the picker is unavailable (headless), or the\n * user cancels.\n */\n requestLogicTag: () => Promise<LogicTagPickerResult | null>;\n}\n\n/**\n * Composable for the standalone logic-tag feature — separate from merge tags.\n * Exposes configured logic tags/pairs and opens the built-in logic picker.\n */\nexport function useLogicTag(): UseLogicTagReturn {\n const logicTags = inject(LOGIC_TAGS_KEY, []);\n const logicPairs = inject(LOGIC_PAIRS_KEY, []);\n const syntax = inject(MERGE_TAG_SYNTAX_KEY, SYNTAX_PRESETS.liquid);\n const onRequest = inject(ON_REQUEST_LOGIC_TAG_KEY, null);\n // Picker may be null in headless contexts (tests, non-editor consumers).\n const picker = inject(LOGIC_TAG_PICKER_KEY, null);\n\n // Shared per editor — same reason as merge tags. See\n // LOGIC_TAG_REQUESTING_KEY.\n const isRequesting = inject(LOGIC_TAG_REQUESTING_KEY, null) ?? ref(false);\n\n // Show the affordance when a consumer callback is set OR static config\n // exists — mirrors useMergeTag's canRequestMergeTag.\n const canInsertLogicTag =\n !!onRequest || logicTags.length > 0 || logicPairs.length > 0;\n\n const hasStaticLogic = logicTags.length > 0 || logicPairs.length > 0;\n\n /**\n * Request a logic tag/pair from the user. Precedence:\n * 1. `logic.onRequest` callback (consumer-owned UX)\n * 2. Built-in picker over `logic.tags` / `logic.pairs`\n * 3. null (nothing configured / headless)\n */\n async function requestLogicTag(): Promise<LogicTagPickerResult | null> {\n if (onRequest) {\n isRequesting.value = true;\n try {\n return await onRequest();\n } finally {\n isRequesting.value = false;\n }\n }\n if (picker && hasStaticLogic) {\n isRequesting.value = true;\n try {\n return await picker.open(logicTags, logicPairs);\n } finally {\n isRequesting.value = false;\n }\n }\n return null;\n }\n\n return {\n logicTags,\n logicPairs,\n syntax,\n canInsertLogicTag,\n isRequesting,\n requestLogicTag,\n };\n}\n"],"mappings":";;;;AAuCA,SAAgB,IAAiC;CAC/C,IAAM,IAAY,EAAO,GAAgB,CAAC,CAAC,GACrC,IAAa,EAAO,GAAiB,CAAC,CAAC,GACvC,IAAS,EAAO,GAAsB,EAAe,MAAM,GAC3D,IAAY,EAAO,GAA0B,IAAI,GAEjD,IAAS,EAAO,GAAsB,IAAI,GAI1C,IAAe,EAAO,GAA0B,IAAI,KAAK,EAAI,EAAK,GAIlE,IACJ,CAAC,CAAC,KAAa,EAAU,SAAS,KAAK,EAAW,SAAS,GAEvD,IAAiB,EAAU,SAAS,KAAK,EAAW,SAAS;CAQnE,eAAe,IAAwD;EACrE,IAAI,GAAW;GACb,EAAa,QAAQ;GACrB,IAAI;IACF,OAAO,MAAM,EAAU;GACzB,UAAU;IACR,EAAa,QAAQ;GACvB;EACF;EACA,IAAI,KAAU,GAAgB;GAC5B,EAAa,QAAQ;GACrB,IAAI;IACF,OAAO,MAAM,EAAO,KAAK,GAAW,CAAU;GAChD,UAAU;IACR,EAAa,QAAQ;GACvB;EACF;EACA,OAAO;CACT;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
@@ -1,9 +1,9 @@
1
1
  import { E as e, Q as t, f as n } from "./draggable-IB4x6w2O.js";
2
- import { f as r, o as i, r as a } from "./src-Dwgq7hf4.js";
3
- import { A as o, D as s, L as c, M as l, N as u, O as d, P as f, k as p, q as m } from "./keys-dJbD1QPs.js";
2
+ import { f as r, o as i, r as a } from "./src-DveVYoWS.js";
3
+ import { A as o, F as s, N as c, O as l, P as u, R as d, Y as f, j as p, k as m } from "./keys-DCWeHkSF.js";
4
4
  //#region src/composables/useMergeTag.ts
5
5
  function h() {
6
- let h = e(s, f), g = e(u, a.liquid), _ = e(c, null), v = e(d, !0), y = e(p, null), b = e(l, !0), x = e(m, null)?.mergeTag.unknownLabel ?? "Merge tag", S = e(o, null) ?? t(!1);
6
+ let h = e(l, s), g = e(u, a.liquid), _ = e(d, null), v = e(m, !0), y = e(o, null), b = e(c, !0), x = e(f, null)?.mergeTag.unknownLabel ?? "Merge tag", S = e(p, null) ?? t(!1);
7
7
  function C(e) {
8
8
  return r(e, g);
9
9
  }
@@ -57,4 +57,4 @@ function h() {
57
57
  //#endregion
58
58
  export { h as t };
59
59
 
60
- //# sourceMappingURL=useMergeTag-BE8oDoha.js.map
60
+ //# sourceMappingURL=useMergeTag-DbIHw4NG.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useMergeTag-BE8oDoha.js","names":[],"sources":["../../../src/composables/useMergeTag.ts"],"sourcesContent":["import type {\n MergeTag,\n MergeTagRequestContext,\n SyntaxPreset,\n} from \"@templatical/types\";\nimport {\n isMergeTagValue as checkIsMergeTagValue,\n getMergeTagLabel as resolveMergeTagLabel,\n SYNTAX_PRESETS,\n} from \"@templatical/types\";\nimport {\n computed,\n inject,\n ref,\n type ComputedRef,\n type Ref,\n type ShallowRef,\n} from \"vue\";\nimport {\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n MERGE_TAG_SYNTAX_KEY,\n MERGE_TAG_AUTOCOMPLETE_KEY,\n MERGE_TAG_PICKER_KEY,\n MERGE_TAG_SHOW_RAW_VALUE_KEY,\n MERGE_TAG_REQUESTING_KEY,\n ON_REQUEST_MERGE_TAG_KEY,\n TRANSLATIONS_KEY,\n} from \"../keys\";\n\nexport interface UseMergeTagReturn {\n /**\n * The configured merge tags. A ref, so `editor.setMergeTags()` reaches\n * everything reading it — never destructure the array out of it.\n */\n mergeTags: ShallowRef<MergeTag[]>;\n /** Whether a merge tag request is in progress */\n isRequesting: Ref<boolean>;\n /**\n * Whether the \"Insert merge tag\" button should be shown. True when\n * either `onRequestMergeTag` is provided or `mergeTags.tags` is\n * non-empty (the built-in picker then handles the click).\n */\n canRequestMergeTag: ComputedRef<boolean>;\n /** Whether typing-based autocomplete is enabled by configuration */\n autocomplete: boolean;\n /** The resolved syntax preset for merge tags */\n syntax: SyntaxPreset;\n /** Check if a value matches the configured merge tag syntax */\n isMergeTagValue: (value: string) => boolean;\n /** Get the human-readable label for a merge tag value */\n getMergeTagLabel: (value: string) => string;\n /**\n * The configured tag whose `value` is exactly `value`, or `undefined` when\n * the token matches nothing. Unlike `getMergeTagLabel`, absence is reported\n * rather than falling back to the raw token — callers deciding whether a\n * chip can be re-picked need to tell the two apart.\n */\n findMergeTag: (value: string) => MergeTag | undefined;\n /**\n * Whether activating a tag carrying `value` should open the chooser rather\n * than a raw text input.\n *\n * True when the consumer owns the chooser (`onRequest` decides for itself\n * what an unresolvable token means), or when the token resolves against\n * `tags` so the built-in picker has something to preselect. False otherwise,\n * which is the one case where editing the token as text is still the only\n * way to repair it.\n *\n * The single home for that rule: the canvas chip and a sidebar field chip\n * must not be able to answer it differently.\n */\n canRepickMergeTag: (value: string) => boolean;\n /**\n * What a tag renders as on screen.\n *\n * A declared tag shows its label. An undeclared token normally shows itself —\n * the editor makes a tag out of anything syntax-shaped, so the token is\n * usually the only thing identifying it. When the consumer hid raw tokens it\n * falls back to `storedLabel` (the label captured on the node when the tag\n * was inserted) and then to a neutral placeholder, so an opaque identifier\n * never reaches the screen.\n *\n * The single home for that chain: the canvas chip, its accessible name and a\n * sidebar field chip must all say the same thing.\n */\n getMergeTagDisplayLabel: (value: string, storedLabel?: string) => string;\n /**\n * Whether a tag's tooltip may reveal the raw token behind its label.\n * `false` when the consumer set `mergeTags.showRawValue: false`.\n */\n showRawValue: boolean;\n /**\n * Request a merge tag from the user. Precedence: when\n * `onRequestMergeTag` is set it owns the UX; otherwise the built-in\n * picker opens with the configured `mergeTags.tags`; otherwise null.\n *\n * `context` says whether this is an insertion or a replacement, and carries\n * the tag being replaced when one resolves.\n */\n requestMergeTag: (\n context?: MergeTagRequestContext,\n ) => Promise<MergeTag | null>;\n}\n\n/**\n * Composable for merge tag functionality.\n * Provides utilities for detecting, displaying, and requesting merge tags.\n */\nexport function useMergeTag(): UseMergeTagReturn {\n const mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\n const syntax = inject(MERGE_TAG_SYNTAX_KEY, SYNTAX_PRESETS.liquid);\n const onRequestMergeTag = inject(ON_REQUEST_MERGE_TAG_KEY, null);\n const autocomplete = inject(MERGE_TAG_AUTOCOMPLETE_KEY, true);\n // Picker may be null in headless contexts (tests, non-editor consumers).\n // requestMergeTag() returns null in that case rather than throwing.\n const picker = inject(MERGE_TAG_PICKER_KEY, null);\n const showRawValue = inject(MERGE_TAG_SHOW_RAW_VALUE_KEY, true);\n // Injected directly rather than through `useI18n()`, which throws without a\n // provider — this composable is used headlessly too. The binding name is one\n // `i18n-key-usage.test.ts` recognises as a translations holder; an unlisted\n // name makes every key read through it look dead to that guard.\n const injectedTranslations = inject(TRANSLATIONS_KEY, null);\n const unknownLabel =\n injectedTranslations?.mergeTag.unknownLabel ?? \"Merge tag\";\n\n // Shared per editor so every host that can open the picker is visible to\n // useRichTextEditor's click-outside guard. See MERGE_TAG_REQUESTING_KEY.\n const isRequesting = inject(MERGE_TAG_REQUESTING_KEY, null) ?? ref(false);\n\n function isMergeTagValue(value: string): boolean {\n return checkIsMergeTagValue(value, syntax);\n }\n\n function getMergeTagLabel(value: string): string {\n return resolveMergeTagLabel(value, mergeTags.value);\n }\n\n function findMergeTag(value: string): MergeTag | undefined {\n return mergeTags.value.find((tag) => tag.value === value);\n }\n\n function canRepickMergeTag(value: string): boolean {\n return !!onRequestMergeTag || findMergeTag(value) !== undefined;\n }\n\n function getMergeTagDisplayLabel(\n value: string,\n storedLabel?: string,\n ): string {\n const declared = findMergeTag(value);\n if (declared) return declared.label;\n // Before the token, not after it. A consumer whose picker mints a tag\n // returns one that is in no `tags` array, and its label is written onto\n // the node — reaching for the token first renders a raw identifier the\n // instant the author picks a field. This costs nothing for a tag the\n // editor made itself: the input rule, the paste rule, normalization and\n // `parseHTML` all derive an undeclared tag's stored label from\n // `getMergeTagLabel`, which returns the token, so the two agree already.\n if (storedLabel?.trim()) return storedLabel.trim();\n return showRawValue ? value : unknownLabel;\n }\n\n /**\n * Request a merge tag from the user. Precedence:\n * 1. `onRequestMergeTag` callback (consumer-owned UX)\n * 2. Built-in picker over `mergeTags.tags`\n * 3. null (nothing configured)\n */\n async function requestMergeTag(\n context?: MergeTagRequestContext,\n ): Promise<MergeTag | null> {\n if (onRequestMergeTag) {\n isRequesting.value = true;\n try {\n return await onRequestMergeTag(context);\n } finally {\n isRequesting.value = false;\n }\n }\n if (mergeTags.value.length > 0 && picker) {\n isRequesting.value = true;\n try {\n return await picker.open(mergeTags.value, {\n current: context?.current,\n });\n } finally {\n isRequesting.value = false;\n }\n }\n return null;\n }\n\n // Computed, not a snapshot: `setMergeTags` can take the list from empty to\n // populated, and a plain boolean captured here would leave the \"Insert merge\n // tag\" affordance hidden for the rest of the session.\n const canRequestMergeTag = computed(\n () => !!onRequestMergeTag || mergeTags.value.length > 0,\n );\n\n return {\n mergeTags,\n isRequesting,\n canRequestMergeTag,\n autocomplete,\n syntax,\n isMergeTagValue,\n getMergeTagLabel,\n findMergeTag,\n canRepickMergeTag,\n getMergeTagDisplayLabel,\n showRawValue,\n requestMergeTag,\n };\n}\n"],"mappings":";;;;AA6GA,SAAgB,IAAiC;CAC/C,IAAM,IAAY,EAAO,GAAgB,CAAa,GAChD,IAAS,EAAO,GAAsB,EAAe,MAAM,GAC3D,IAAoB,EAAO,GAA0B,IAAI,GACzD,IAAe,EAAO,GAA4B,EAAI,GAGtD,IAAS,EAAO,GAAsB,IAAI,GAC1C,IAAe,EAAO,GAA8B,EAAI,GAMxD,IADuB,EAAO,GAAkB,IAEpD,CAAA,EAAsB,SAAS,gBAAgB,aAI3C,IAAe,EAAO,GAA0B,IAAI,KAAK,EAAI,EAAK;CAExE,SAAS,EAAgB,GAAwB;EAC/C,OAAO,EAAqB,GAAO,CAAM;CAC3C;CAEA,SAAS,EAAiB,GAAuB;EAC/C,OAAO,EAAqB,GAAO,EAAU,KAAK;CACpD;CAEA,SAAS,EAAa,GAAqC;EACzD,OAAO,EAAU,MAAM,MAAM,MAAQ,EAAI,UAAU,CAAK;CAC1D;CAEA,SAAS,EAAkB,GAAwB;EACjD,OAAO,CAAC,CAAC,KAAqB,EAAa,CAAK,MAAM,KAAA;CACxD;CAEA,SAAS,EACP,GACA,GACQ;EACR,IAAM,IAAW,EAAa,CAAK;EAUnC,OATI,IAAiB,EAAS,QAQ1B,GAAa,KAAK,IAAU,EAAY,KAAK,IAC1C,IAAe,IAAQ;CAChC;CAQA,eAAe,EACb,GAC0B;EAC1B,IAAI,GAAmB;GACrB,EAAa,QAAQ;GACrB,IAAI;IACF,OAAO,MAAM,EAAkB,CAAO;GACxC,UAAU;IACR,EAAa,QAAQ;GACvB;EACF;EACA,IAAI,EAAU,MAAM,SAAS,KAAK,GAAQ;GACxC,EAAa,QAAQ;GACrB,IAAI;IACF,OAAO,MAAM,EAAO,KAAK,EAAU,OAAO,EACxC,SAAS,GAAS,QACpB,CAAC;GACH,UAAU;IACR,EAAa,QAAQ;GACvB;EACF;EACA,OAAO;CACT;CASA,OAAO;EACL;EACA;EACA,oBAPyB,QACnB,CAAC,CAAC,KAAqB,EAAU,MAAM,SAAS,CAMtD;EACA;EACA;EACA,iBAAA;EACA,kBAAA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"useMergeTag-DbIHw4NG.js","names":[],"sources":["../../../src/composables/useMergeTag.ts"],"sourcesContent":["import type {\n MergeTag,\n MergeTagRequestContext,\n SyntaxPreset,\n} from \"@templatical/types\";\nimport {\n isMergeTagValue as checkIsMergeTagValue,\n getMergeTagLabel as resolveMergeTagLabel,\n SYNTAX_PRESETS,\n} from \"@templatical/types\";\nimport {\n computed,\n inject,\n ref,\n type ComputedRef,\n type Ref,\n type ShallowRef,\n} from \"vue\";\nimport {\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n MERGE_TAG_SYNTAX_KEY,\n MERGE_TAG_AUTOCOMPLETE_KEY,\n MERGE_TAG_PICKER_KEY,\n MERGE_TAG_SHOW_RAW_VALUE_KEY,\n MERGE_TAG_REQUESTING_KEY,\n ON_REQUEST_MERGE_TAG_KEY,\n TRANSLATIONS_KEY,\n} from \"../keys\";\n\nexport interface UseMergeTagReturn {\n /**\n * The configured merge tags. A ref, so `editor.setMergeTags()` reaches\n * everything reading it — never destructure the array out of it.\n */\n mergeTags: ShallowRef<MergeTag[]>;\n /** Whether a merge tag request is in progress */\n isRequesting: Ref<boolean>;\n /**\n * Whether the \"Insert merge tag\" button should be shown. True when\n * either `onRequestMergeTag` is provided or `mergeTags.tags` is\n * non-empty (the built-in picker then handles the click).\n */\n canRequestMergeTag: ComputedRef<boolean>;\n /** Whether typing-based autocomplete is enabled by configuration */\n autocomplete: boolean;\n /** The resolved syntax preset for merge tags */\n syntax: SyntaxPreset;\n /** Check if a value matches the configured merge tag syntax */\n isMergeTagValue: (value: string) => boolean;\n /** Get the human-readable label for a merge tag value */\n getMergeTagLabel: (value: string) => string;\n /**\n * The configured tag whose `value` is exactly `value`, or `undefined` when\n * the token matches nothing. Unlike `getMergeTagLabel`, absence is reported\n * rather than falling back to the raw token — callers deciding whether a\n * chip can be re-picked need to tell the two apart.\n */\n findMergeTag: (value: string) => MergeTag | undefined;\n /**\n * Whether activating a tag carrying `value` should open the chooser rather\n * than a raw text input.\n *\n * True when the consumer owns the chooser (`onRequest` decides for itself\n * what an unresolvable token means), or when the token resolves against\n * `tags` so the built-in picker has something to preselect. False otherwise,\n * which is the one case where editing the token as text is still the only\n * way to repair it.\n *\n * The single home for that rule: the canvas chip and a sidebar field chip\n * must not be able to answer it differently.\n */\n canRepickMergeTag: (value: string) => boolean;\n /**\n * What a tag renders as on screen.\n *\n * A declared tag shows its label. An undeclared token normally shows itself —\n * the editor makes a tag out of anything syntax-shaped, so the token is\n * usually the only thing identifying it. When the consumer hid raw tokens it\n * falls back to `storedLabel` (the label captured on the node when the tag\n * was inserted) and then to a neutral placeholder, so an opaque identifier\n * never reaches the screen.\n *\n * The single home for that chain: the canvas chip, its accessible name and a\n * sidebar field chip must all say the same thing.\n */\n getMergeTagDisplayLabel: (value: string, storedLabel?: string) => string;\n /**\n * Whether a tag's tooltip may reveal the raw token behind its label.\n * `false` when the consumer set `mergeTags.showRawValue: false`.\n */\n showRawValue: boolean;\n /**\n * Request a merge tag from the user. Precedence: when\n * `onRequestMergeTag` is set it owns the UX; otherwise the built-in\n * picker opens with the configured `mergeTags.tags`; otherwise null.\n *\n * `context` says whether this is an insertion or a replacement, and carries\n * the tag being replaced when one resolves.\n */\n requestMergeTag: (\n context?: MergeTagRequestContext,\n ) => Promise<MergeTag | null>;\n}\n\n/**\n * Composable for merge tag functionality.\n * Provides utilities for detecting, displaying, and requesting merge tags.\n */\nexport function useMergeTag(): UseMergeTagReturn {\n const mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\n const syntax = inject(MERGE_TAG_SYNTAX_KEY, SYNTAX_PRESETS.liquid);\n const onRequestMergeTag = inject(ON_REQUEST_MERGE_TAG_KEY, null);\n const autocomplete = inject(MERGE_TAG_AUTOCOMPLETE_KEY, true);\n // Picker may be null in headless contexts (tests, non-editor consumers).\n // requestMergeTag() returns null in that case rather than throwing.\n const picker = inject(MERGE_TAG_PICKER_KEY, null);\n const showRawValue = inject(MERGE_TAG_SHOW_RAW_VALUE_KEY, true);\n // Injected directly rather than through `useI18n()`, which throws without a\n // provider — this composable is used headlessly too. The binding name is one\n // `i18n-key-usage.test.ts` recognises as a translations holder; an unlisted\n // name makes every key read through it look dead to that guard.\n const injectedTranslations = inject(TRANSLATIONS_KEY, null);\n const unknownLabel =\n injectedTranslations?.mergeTag.unknownLabel ?? \"Merge tag\";\n\n // Shared per editor so every host that can open the picker is visible to\n // useRichTextEditor's click-outside guard. See MERGE_TAG_REQUESTING_KEY.\n const isRequesting = inject(MERGE_TAG_REQUESTING_KEY, null) ?? ref(false);\n\n function isMergeTagValue(value: string): boolean {\n return checkIsMergeTagValue(value, syntax);\n }\n\n function getMergeTagLabel(value: string): string {\n return resolveMergeTagLabel(value, mergeTags.value);\n }\n\n function findMergeTag(value: string): MergeTag | undefined {\n return mergeTags.value.find((tag) => tag.value === value);\n }\n\n function canRepickMergeTag(value: string): boolean {\n return !!onRequestMergeTag || findMergeTag(value) !== undefined;\n }\n\n function getMergeTagDisplayLabel(\n value: string,\n storedLabel?: string,\n ): string {\n const declared = findMergeTag(value);\n if (declared) return declared.label;\n // Before the token, not after it. A consumer whose picker mints a tag\n // returns one that is in no `tags` array, and its label is written onto\n // the node — reaching for the token first renders a raw identifier the\n // instant the author picks a field. This costs nothing for a tag the\n // editor made itself: the input rule, the paste rule, normalization and\n // `parseHTML` all derive an undeclared tag's stored label from\n // `getMergeTagLabel`, which returns the token, so the two agree already.\n if (storedLabel?.trim()) return storedLabel.trim();\n return showRawValue ? value : unknownLabel;\n }\n\n /**\n * Request a merge tag from the user. Precedence:\n * 1. `onRequestMergeTag` callback (consumer-owned UX)\n * 2. Built-in picker over `mergeTags.tags`\n * 3. null (nothing configured)\n */\n async function requestMergeTag(\n context?: MergeTagRequestContext,\n ): Promise<MergeTag | null> {\n if (onRequestMergeTag) {\n isRequesting.value = true;\n try {\n return await onRequestMergeTag(context);\n } finally {\n isRequesting.value = false;\n }\n }\n if (mergeTags.value.length > 0 && picker) {\n isRequesting.value = true;\n try {\n return await picker.open(mergeTags.value, {\n current: context?.current,\n });\n } finally {\n isRequesting.value = false;\n }\n }\n return null;\n }\n\n // Computed, not a snapshot: `setMergeTags` can take the list from empty to\n // populated, and a plain boolean captured here would leave the \"Insert merge\n // tag\" affordance hidden for the rest of the session.\n const canRequestMergeTag = computed(\n () => !!onRequestMergeTag || mergeTags.value.length > 0,\n );\n\n return {\n mergeTags,\n isRequesting,\n canRequestMergeTag,\n autocomplete,\n syntax,\n isMergeTagValue,\n getMergeTagLabel,\n findMergeTag,\n canRepickMergeTag,\n getMergeTagDisplayLabel,\n showRawValue,\n requestMergeTag,\n };\n}\n"],"mappings":";;;;AA6GA,SAAgB,IAAiC;CAC/C,IAAM,IAAY,EAAO,GAAgB,CAAa,GAChD,IAAS,EAAO,GAAsB,EAAe,MAAM,GAC3D,IAAoB,EAAO,GAA0B,IAAI,GACzD,IAAe,EAAO,GAA4B,EAAI,GAGtD,IAAS,EAAO,GAAsB,IAAI,GAC1C,IAAe,EAAO,GAA8B,EAAI,GAMxD,IADuB,EAAO,GAAkB,IAEpD,CAAA,EAAsB,SAAS,gBAAgB,aAI3C,IAAe,EAAO,GAA0B,IAAI,KAAK,EAAI,EAAK;CAExE,SAAS,EAAgB,GAAwB;EAC/C,OAAO,EAAqB,GAAO,CAAM;CAC3C;CAEA,SAAS,EAAiB,GAAuB;EAC/C,OAAO,EAAqB,GAAO,EAAU,KAAK;CACpD;CAEA,SAAS,EAAa,GAAqC;EACzD,OAAO,EAAU,MAAM,MAAM,MAAQ,EAAI,UAAU,CAAK;CAC1D;CAEA,SAAS,EAAkB,GAAwB;EACjD,OAAO,CAAC,CAAC,KAAqB,EAAa,CAAK,MAAM,KAAA;CACxD;CAEA,SAAS,EACP,GACA,GACQ;EACR,IAAM,IAAW,EAAa,CAAK;EAUnC,OATI,IAAiB,EAAS,QAQ1B,GAAa,KAAK,IAAU,EAAY,KAAK,IAC1C,IAAe,IAAQ;CAChC;CAQA,eAAe,EACb,GAC0B;EAC1B,IAAI,GAAmB;GACrB,EAAa,QAAQ;GACrB,IAAI;IACF,OAAO,MAAM,EAAkB,CAAO;GACxC,UAAU;IACR,EAAa,QAAQ;GACvB;EACF;EACA,IAAI,EAAU,MAAM,SAAS,KAAK,GAAQ;GACxC,EAAa,QAAQ;GACrB,IAAI;IACF,OAAO,MAAM,EAAO,KAAK,EAAU,OAAO,EACxC,SAAS,GAAS,QACpB,CAAC;GACH,UAAU;IACR,EAAa,QAAQ;GACvB;EACF;EACA,OAAO;CACT;CASA,OAAO;EACL;EACA;EACA,oBAPyB,QACnB,CAAC,CAAC,KAAqB,EAAU,MAAM,SAAS,CAMtD;EACA;EACA;EACA,iBAAA;EACA,kBAAA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { E as e, Q as t } from "./draggable-IB4x6w2O.js";
2
- import { z as n } from "./keys-dJbD1QPs.js";
2
+ import { B as n } from "./keys-DCWeHkSF.js";
3
3
  //#region src/utils/resolveColorsConfig.ts
4
4
  var r = {
5
5
  presets: [],
@@ -58,4 +58,4 @@ function l() {
58
58
  //#endregion
59
59
  export { r as a, o as i, c as n, a as o, s as r, l as t };
60
60
 
61
- //# sourceMappingURL=usePopoverPosition-gB9q-ql7.js.map
61
+ //# sourceMappingURL=usePopoverPosition-BJRvAb-h.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"usePopoverPosition-gB9q-ql7.js","names":[],"sources":["../../../src/utils/resolveColorsConfig.ts","../../../src/utils/color.ts","../../../src/composables/usePopoverRoot.ts","../../../src/composables/usePopoverPosition.ts"],"sourcesContent":["import type { ColorsConfig } from \"@templatical/types\";\n\n/**\n * Normalized color-picker configuration handed to the provide/inject layer and\n * to `ColorPicker`. `presets` defaults to an empty array and `allowCustom` to\n * `true`, so consumers never branch on `undefined`.\n *\n * `allowCustomIgnored` is a validation signal, not a rendered value: it is\n * `true` when `allowCustom: false` was requested but forced back to `true`\n * because there were no presets to fall back on. This util stays pure — it\n * never logs; the consumer that owns the config surface emits the warning\n * (today that is `useEditorCore` for the editor-level config), the same split\n * `resolvePaletteBlocks` / `Sidebar.vue` use.\n */\nexport interface ResolvedColors {\n presets: string[];\n allowCustom: boolean;\n allowCustomIgnored: boolean;\n /**\n * Preset entries dropped because they are not a valid `#rgb` / `#rrggbb` hex\n * string (see the validity rule on {@link resolveColorsConfig}). Collected —\n * not logged — so the config-owning consumer can warn once listing them,\n * exactly as `allowCustomIgnored` is surfaced. Reflects THIS resolution's\n * `colors.presets` input only: when a `fallback`'s already-resolved (already\n * filtered) presets are inherited, its invalids are never re-reported here.\n */\n invalidPresets: string[];\n}\n\n/**\n * The unconfigured baseline: no presets, free-form entry allowed — i.e. the\n * picker behaves exactly as it did before the `colors` option existed. Used as\n * the inject default and as the fallback for the top-level resolution.\n */\nexport const DEFAULT_RESOLVED_COLORS: ResolvedColors = {\n presets: [],\n allowCustom: true,\n allowCustomIgnored: false,\n invalidPresets: [],\n};\n\n/**\n * A valid preset is a `#rgb` or `#rrggbb` hex string. 4-/8-digit alpha hex is\n * deliberately rejected: the wheel (vanilla-colorful) is RGB-only,\n * `normalizeColorToHex` drops alpha on the DOM round-trip so a selected alpha\n * preset would never read back as selected, and alpha degrades unpredictably\n * across email clients.\n */\nconst VALID_PRESET_HEX = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;\n\n/**\n * Resolve a `ColorsConfig` against an already-resolved `fallback`, applying\n * precedence per property (`input` → `fallback` → default) plus the shared\n * validation rule.\n *\n * The editor-level call passes no `fallback` (it defaults to\n * {@link DEFAULT_RESOLVED_COLORS}) and its result is provided via `COLORS_KEY`.\n * The `fallback` parameter is the nested-resolution seam: a narrower config can\n * be resolved against a broader already-resolved one, inheriting whichever\n * property it does not set.\n *\n * Validation: entries in `colors.presets` that aren't valid hex\n * ({@link VALID_PRESET_HEX}) are dropped from `presets` and collected into\n * `invalidPresets` for the caller to warn about. Separately, `allowCustom:\n * false` with no presets anywhere in the chain is ignored — forced back to\n * `true`, with `allowCustomIgnored` set so the caller can warn — because\n * hiding the wheel and hex input without a preset grid would leave the picker\n * unable to set a color. Filtering runs BEFORE that guard, so an all-invalid\n * list with `allowCustom: false` cascades into the forced-true path. This\n * mirrors how `paletteBlocks` is resolved: `resolvePaletteBlocks` collects the\n * offending entries and the consumer warns; this util stays pure the same way.\n */\nexport function resolveColorsConfig(\n colors: ColorsConfig | undefined,\n fallback: ResolvedColors = DEFAULT_RESOLVED_COLORS,\n): ResolvedColors {\n // Validate only presets this resolution actually supplies. When it inherits\n // `fallback.presets`, those were already resolved (already filtered), so\n // re-validating would double-report an upstream invalid entry.\n let presets: string[];\n let invalidPresets: string[];\n if (colors?.presets === undefined) {\n presets = fallback.presets;\n invalidPresets = [];\n } else {\n presets = [];\n invalidPresets = [];\n for (const entry of colors.presets) {\n if (VALID_PRESET_HEX.test(entry)) {\n presets.push(entry);\n } else {\n invalidPresets.push(entry);\n }\n }\n }\n\n const requestedAllowCustom = colors?.allowCustom ?? fallback.allowCustom;\n\n const allowCustomIgnored = !requestedAllowCustom && presets.length === 0;\n const allowCustom = allowCustomIgnored ? true : requestedAllowCustom;\n\n return { presets, allowCustom, allowCustomIgnored, invalidPresets };\n}\n","/**\n * Normalize a browser-serialized `rgb()/rgba()` color to `#rrggbb`. The browser\n * serializes an inline `style=\"color:#hex\"` to `rgb(...)`, so reading a stored\n * color back via `element.style.color` (e.g. a TipTap textStyle/highlight mark,\n * or a saved link color) surfaces `rgb(...)` — mismatching the hex used\n * everywhere else, and unparseable by the hex-only picker (`vanilla-colorful`)\n * and the native `<input type=\"color\">`. Non-rgb input (already hex, a keyword,\n * or empty) is returned unchanged.\n */\nexport function normalizeColorToHex(value: string): string {\n const m = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i.exec(value.trim());\n if (!m) return value;\n const toHex = (n: string) => Number(n).toString(16).padStart(2, \"0\");\n return `#${toHex(m[1])}${toHex(m[2])}${toHex(m[3])}`;\n}\n\n/**\n * Canonicalize a hex color to the lowercase 6-digit form used for preset\n * membership tests. Runs {@link normalizeColorToHex} first (so a\n * browser-serialized `rgb(...)` round-trip collapses to hex), then expands a\n * 3-digit shorthand (`#abc` → `#aabbcc`) and lowercases it. Non-hex input (a\n * keyword, or empty) is returned unchanged after that rgb normalization —\n * the caller decides whether that counts as a member.\n *\n * Kept separate from `normalizeColorToHex` (which is left untouched) because a\n * configured preset may be `#abc` while the browser round-trips the selected\n * value to `#aabbcc`, and a factory default may be `#FFFFFF` while the preset\n * is `#ffffff` — bare equality misses both. Preset-selection display\n * (`ColorPicker`) and the off-palette defaults audit (`collectOffPaletteDefaults`)\n * both compare through this one function so the two membership tests can't drift.\n */\nexport function canonicalizeHexColor(value: string): string {\n const hex = normalizeColorToHex(value);\n const short = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(hex);\n if (short) {\n return `#${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`.toLowerCase();\n }\n if (/^#[0-9a-f]{6}$/i.test(hex)) {\n return hex.toLowerCase();\n }\n return hex;\n}\n","import { inject, ref, type Ref } from \"vue\";\nimport { POPOVER_ROOT_KEY } from \"../keys\";\n\n/**\n * Returns the editor's shared popover mount ref — the `<div\n * class=\"tpl-popover-root\" />` rendered at the top level of `Editor.vue`.\n * Every teleport target (RichTextLinkDialog, TitleEditor\n * toolbar, ParagraphToolbar, TplModal) injects this and teleports to\n * `popoverRoot.value` rather than `to=\"body\"`, so popups stay inside the\n * editor's effective DOM root (shadow-aware).\n *\n * Falls back to a never-resolving `ref(null)` when no provider is in scope.\n * Components must guard with `v-if=\"popoverRoot\"` before teleporting —\n * with the fallback, isolated component tests that don't mount the editor\n * shell simply render nothing rather than blow up.\n *\n * Internal — not exported from the package entry.\n */\nexport function usePopoverRoot(): Ref<HTMLElement | null> {\n return inject(POPOVER_ROOT_KEY, ref<HTMLElement | null>(null));\n}\n","import { usePopoverRoot } from \"./usePopoverRoot\";\n\n/**\n * Coordinate helper for popovers that teleport into the shared popover root\n * (`.tpl-popover-root`, `position: relative`) and position themselves with\n * `position: absolute`.\n *\n * Callers compute a target point in **viewport** space — from\n * `getBoundingClientRect()`, `useElementBounding`, or a TipTap caret rect —\n * and `toLocal` converts it to coordinates **local to the popover root** by\n * subtracting the root's own viewport rect.\n *\n * Why this exists: a `position: fixed` popover resolves its coordinates\n * against the nearest ancestor that establishes a containing block — and any\n * `transform` / `filter` / `will-change` on an ancestor of the editor (a\n * consumer's scroll-parallax wrapper, route-transition, reveal animation…)\n * does exactly that, even while its computed `transform` reads `none` (a\n * running/animated transform still promotes the element). The fixed popover\n * would then be offset by that ancestor's position. Anchoring `absolute`\n * inside the (positioned) popover root instead makes the placement immune:\n * both points are read in viewport space, so the subtraction cancels the\n * ancestor offset, and the popover tracks the editor if the ancestor moves.\n *\n * Read `toLocal` inside a `computed` for a reactive result (recomputes with\n * its viewport-coordinate dependencies), or call it once when a popover opens.\n * Falls back to the viewport coordinates unchanged when no popover root is in\n * scope (isolated component tests / headless callers).\n *\n * Internal — not exported from the package entry.\n */\nexport function usePopoverPosition(): {\n toLocal: (viewport: { top: number; left: number }) => {\n top: number;\n left: number;\n };\n} {\n const popoverRoot = usePopoverRoot();\n function toLocal(viewport: { top: number; left: number }): {\n top: number;\n left: number;\n } {\n const rect = popoverRoot.value?.getBoundingClientRect();\n if (!rect) return { top: viewport.top, left: viewport.left };\n return { top: viewport.top - rect.top, left: viewport.left - rect.left };\n }\n return { toLocal };\n}\n"],"mappings":";;;AAkCA,IAAa,IAA0C;CACrD,SAAS,CAAC;CACV,aAAa;CACb,oBAAoB;CACpB,gBAAgB,CAAC;AACnB,GASM,IAAmB;AAwBzB,SAAgB,EACd,GACA,IAA2B,GACX;CAIhB,IAAI,GACA;CACJ,IAAI,GAAQ,YAAY,KAAA,GAEtB,AADA,IAAU,EAAS,SACnB,IAAiB,CAAC;MACb;EAEL,AADA,IAAU,CAAC,GACX,IAAiB,CAAC;EAClB,KAAK,IAAM,KAAS,EAAO,SACzB,AAAI,EAAiB,KAAK,CAAK,IAC7B,EAAQ,KAAK,CAAK,IAElB,EAAe,KAAK,CAAK;CAG/B;CAEA,IAAM,IAAuB,GAAQ,eAAe,EAAS,aAEvD,IAAqB,CAAC,KAAwB,EAAQ,WAAW;CAGvE,OAAO;EAAE;EAAS,aAFE,IAAqB,KAAO;EAEjB;EAAoB;CAAe;AACpE;;;AC7FA,SAAgB,EAAoB,GAAuB;CACzD,IAAM,IAAI,4CAA4C,KAAK,EAAM,KAAK,CAAC;CACvE,IAAI,CAAC,GAAG,OAAO;CACf,IAAM,KAAS,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG;CACnE,OAAO,IAAI,EAAM,EAAE,EAAE,IAAI,EAAM,EAAE,EAAE,IAAI,EAAM,EAAE,EAAE;AACnD;AAiBA,SAAgB,EAAqB,GAAuB;CAC1D,IAAM,IAAM,EAAoB,CAAK,GAC/B,IAAQ,qCAAqC,KAAK,CAAG;CAO3D,OANI,IACK,IAAI,EAAM,KAAK,EAAM,KAAK,EAAM,KAAK,EAAM,KAAK,EAAM,KAAK,EAAM,KAAK,YAAY,IAEvF,kBAAkB,KAAK,CAAG,IACrB,EAAI,YAAY,IAElB;AACT;;;ACvBA,SAAgB,IAA0C;CACxD,OAAO,EAAO,GAAkB,EAAwB,IAAI,CAAC;AAC/D;;;ACUA,SAAgB,IAKd;CACA,IAAM,IAAc,EAAe;CACnC,SAAS,EAAQ,GAGf;EACA,IAAM,IAAO,EAAY,OAAO,sBAAsB;EAEtD,OADK,IACE;GAAE,KAAK,EAAS,MAAM,EAAK;GAAK,MAAM,EAAS,OAAO,EAAK;EAAK,IADrD;GAAE,KAAK,EAAS;GAAK,MAAM,EAAS;EAAK;CAE7D;CACA,OAAO,EAAE,WAAQ;AACnB"}
1
+ {"version":3,"file":"usePopoverPosition-BJRvAb-h.js","names":[],"sources":["../../../src/utils/resolveColorsConfig.ts","../../../src/utils/color.ts","../../../src/composables/usePopoverRoot.ts","../../../src/composables/usePopoverPosition.ts"],"sourcesContent":["import type { ColorsConfig } from \"@templatical/types\";\n\n/**\n * Normalized color-picker configuration handed to the provide/inject layer and\n * to `ColorPicker`. `presets` defaults to an empty array and `allowCustom` to\n * `true`, so consumers never branch on `undefined`.\n *\n * `allowCustomIgnored` is a validation signal, not a rendered value: it is\n * `true` when `allowCustom: false` was requested but forced back to `true`\n * because there were no presets to fall back on. This util stays pure — it\n * never logs; the consumer that owns the config surface emits the warning\n * (today that is `useEditorCore` for the editor-level config), the same split\n * `resolvePaletteBlocks` / `Sidebar.vue` use.\n */\nexport interface ResolvedColors {\n presets: string[];\n allowCustom: boolean;\n allowCustomIgnored: boolean;\n /**\n * Preset entries dropped because they are not a valid `#rgb` / `#rrggbb` hex\n * string (see the validity rule on {@link resolveColorsConfig}). Collected —\n * not logged — so the config-owning consumer can warn once listing them,\n * exactly as `allowCustomIgnored` is surfaced. Reflects THIS resolution's\n * `colors.presets` input only: when a `fallback`'s already-resolved (already\n * filtered) presets are inherited, its invalids are never re-reported here.\n */\n invalidPresets: string[];\n}\n\n/**\n * The unconfigured baseline: no presets, free-form entry allowed — i.e. the\n * picker behaves exactly as it did before the `colors` option existed. Used as\n * the inject default and as the fallback for the top-level resolution.\n */\nexport const DEFAULT_RESOLVED_COLORS: ResolvedColors = {\n presets: [],\n allowCustom: true,\n allowCustomIgnored: false,\n invalidPresets: [],\n};\n\n/**\n * A valid preset is a `#rgb` or `#rrggbb` hex string. 4-/8-digit alpha hex is\n * deliberately rejected: the wheel (vanilla-colorful) is RGB-only,\n * `normalizeColorToHex` drops alpha on the DOM round-trip so a selected alpha\n * preset would never read back as selected, and alpha degrades unpredictably\n * across email clients.\n */\nconst VALID_PRESET_HEX = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;\n\n/**\n * Resolve a `ColorsConfig` against an already-resolved `fallback`, applying\n * precedence per property (`input` → `fallback` → default) plus the shared\n * validation rule.\n *\n * The editor-level call passes no `fallback` (it defaults to\n * {@link DEFAULT_RESOLVED_COLORS}) and its result is provided via `COLORS_KEY`.\n * The `fallback` parameter is the nested-resolution seam: a narrower config can\n * be resolved against a broader already-resolved one, inheriting whichever\n * property it does not set.\n *\n * Validation: entries in `colors.presets` that aren't valid hex\n * ({@link VALID_PRESET_HEX}) are dropped from `presets` and collected into\n * `invalidPresets` for the caller to warn about. Separately, `allowCustom:\n * false` with no presets anywhere in the chain is ignored — forced back to\n * `true`, with `allowCustomIgnored` set so the caller can warn — because\n * hiding the wheel and hex input without a preset grid would leave the picker\n * unable to set a color. Filtering runs BEFORE that guard, so an all-invalid\n * list with `allowCustom: false` cascades into the forced-true path. This\n * mirrors how `paletteBlocks` is resolved: `resolvePaletteBlocks` collects the\n * offending entries and the consumer warns; this util stays pure the same way.\n */\nexport function resolveColorsConfig(\n colors: ColorsConfig | undefined,\n fallback: ResolvedColors = DEFAULT_RESOLVED_COLORS,\n): ResolvedColors {\n // Validate only presets this resolution actually supplies. When it inherits\n // `fallback.presets`, those were already resolved (already filtered), so\n // re-validating would double-report an upstream invalid entry.\n let presets: string[];\n let invalidPresets: string[];\n if (colors?.presets === undefined) {\n presets = fallback.presets;\n invalidPresets = [];\n } else {\n presets = [];\n invalidPresets = [];\n for (const entry of colors.presets) {\n if (VALID_PRESET_HEX.test(entry)) {\n presets.push(entry);\n } else {\n invalidPresets.push(entry);\n }\n }\n }\n\n const requestedAllowCustom = colors?.allowCustom ?? fallback.allowCustom;\n\n const allowCustomIgnored = !requestedAllowCustom && presets.length === 0;\n const allowCustom = allowCustomIgnored ? true : requestedAllowCustom;\n\n return { presets, allowCustom, allowCustomIgnored, invalidPresets };\n}\n","/**\n * Normalize a browser-serialized `rgb()/rgba()` color to `#rrggbb`. The browser\n * serializes an inline `style=\"color:#hex\"` to `rgb(...)`, so reading a stored\n * color back via `element.style.color` (e.g. a TipTap textStyle/highlight mark,\n * or a saved link color) surfaces `rgb(...)` — mismatching the hex used\n * everywhere else, and unparseable by the hex-only picker (`vanilla-colorful`)\n * and the native `<input type=\"color\">`. Non-rgb input (already hex, a keyword,\n * or empty) is returned unchanged.\n */\nexport function normalizeColorToHex(value: string): string {\n const m = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i.exec(value.trim());\n if (!m) return value;\n const toHex = (n: string) => Number(n).toString(16).padStart(2, \"0\");\n return `#${toHex(m[1])}${toHex(m[2])}${toHex(m[3])}`;\n}\n\n/**\n * Canonicalize a hex color to the lowercase 6-digit form used for preset\n * membership tests. Runs {@link normalizeColorToHex} first (so a\n * browser-serialized `rgb(...)` round-trip collapses to hex), then expands a\n * 3-digit shorthand (`#abc` → `#aabbcc`) and lowercases it. Non-hex input (a\n * keyword, or empty) is returned unchanged after that rgb normalization —\n * the caller decides whether that counts as a member.\n *\n * Kept separate from `normalizeColorToHex` (which is left untouched) because a\n * configured preset may be `#abc` while the browser round-trips the selected\n * value to `#aabbcc`, and a factory default may be `#FFFFFF` while the preset\n * is `#ffffff` — bare equality misses both. Preset-selection display\n * (`ColorPicker`) and the off-palette defaults audit (`collectOffPaletteDefaults`)\n * both compare through this one function so the two membership tests can't drift.\n */\nexport function canonicalizeHexColor(value: string): string {\n const hex = normalizeColorToHex(value);\n const short = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(hex);\n if (short) {\n return `#${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`.toLowerCase();\n }\n if (/^#[0-9a-f]{6}$/i.test(hex)) {\n return hex.toLowerCase();\n }\n return hex;\n}\n","import { inject, ref, type Ref } from \"vue\";\nimport { POPOVER_ROOT_KEY } from \"../keys\";\n\n/**\n * Returns the editor's shared popover mount ref — the `<div\n * class=\"tpl-popover-root\" />` rendered at the top level of `Editor.vue`.\n * Every teleport target (RichTextLinkDialog, TitleEditor\n * toolbar, ParagraphToolbar, TplModal) injects this and teleports to\n * `popoverRoot.value` rather than `to=\"body\"`, so popups stay inside the\n * editor's effective DOM root (shadow-aware).\n *\n * Falls back to a never-resolving `ref(null)` when no provider is in scope.\n * Components must guard with `v-if=\"popoverRoot\"` before teleporting —\n * with the fallback, isolated component tests that don't mount the editor\n * shell simply render nothing rather than blow up.\n *\n * Internal — not exported from the package entry.\n */\nexport function usePopoverRoot(): Ref<HTMLElement | null> {\n return inject(POPOVER_ROOT_KEY, ref<HTMLElement | null>(null));\n}\n","import { usePopoverRoot } from \"./usePopoverRoot\";\n\n/**\n * Coordinate helper for popovers that teleport into the shared popover root\n * (`.tpl-popover-root`, `position: relative`) and position themselves with\n * `position: absolute`.\n *\n * Callers compute a target point in **viewport** space — from\n * `getBoundingClientRect()`, `useElementBounding`, or a TipTap caret rect —\n * and `toLocal` converts it to coordinates **local to the popover root** by\n * subtracting the root's own viewport rect.\n *\n * Why this exists: a `position: fixed` popover resolves its coordinates\n * against the nearest ancestor that establishes a containing block — and any\n * `transform` / `filter` / `will-change` on an ancestor of the editor (a\n * consumer's scroll-parallax wrapper, route-transition, reveal animation…)\n * does exactly that, even while its computed `transform` reads `none` (a\n * running/animated transform still promotes the element). The fixed popover\n * would then be offset by that ancestor's position. Anchoring `absolute`\n * inside the (positioned) popover root instead makes the placement immune:\n * both points are read in viewport space, so the subtraction cancels the\n * ancestor offset, and the popover tracks the editor if the ancestor moves.\n *\n * Read `toLocal` inside a `computed` for a reactive result (recomputes with\n * its viewport-coordinate dependencies), or call it once when a popover opens.\n * Falls back to the viewport coordinates unchanged when no popover root is in\n * scope (isolated component tests / headless callers).\n *\n * Internal — not exported from the package entry.\n */\nexport function usePopoverPosition(): {\n toLocal: (viewport: { top: number; left: number }) => {\n top: number;\n left: number;\n };\n} {\n const popoverRoot = usePopoverRoot();\n function toLocal(viewport: { top: number; left: number }): {\n top: number;\n left: number;\n } {\n const rect = popoverRoot.value?.getBoundingClientRect();\n if (!rect) return { top: viewport.top, left: viewport.left };\n return { top: viewport.top - rect.top, left: viewport.left - rect.left };\n }\n return { toLocal };\n}\n"],"mappings":";;;AAkCA,IAAa,IAA0C;CACrD,SAAS,CAAC;CACV,aAAa;CACb,oBAAoB;CACpB,gBAAgB,CAAC;AACnB,GASM,IAAmB;AAwBzB,SAAgB,EACd,GACA,IAA2B,GACX;CAIhB,IAAI,GACA;CACJ,IAAI,GAAQ,YAAY,KAAA,GAEtB,AADA,IAAU,EAAS,SACnB,IAAiB,CAAC;MACb;EAEL,AADA,IAAU,CAAC,GACX,IAAiB,CAAC;EAClB,KAAK,IAAM,KAAS,EAAO,SACzB,AAAI,EAAiB,KAAK,CAAK,IAC7B,EAAQ,KAAK,CAAK,IAElB,EAAe,KAAK,CAAK;CAG/B;CAEA,IAAM,IAAuB,GAAQ,eAAe,EAAS,aAEvD,IAAqB,CAAC,KAAwB,EAAQ,WAAW;CAGvE,OAAO;EAAE;EAAS,aAFE,IAAqB,KAAO;EAEjB;EAAoB;CAAe;AACpE;;;AC7FA,SAAgB,EAAoB,GAAuB;CACzD,IAAM,IAAI,4CAA4C,KAAK,EAAM,KAAK,CAAC;CACvE,IAAI,CAAC,GAAG,OAAO;CACf,IAAM,KAAS,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG;CACnE,OAAO,IAAI,EAAM,EAAE,EAAE,IAAI,EAAM,EAAE,EAAE,IAAI,EAAM,EAAE,EAAE;AACnD;AAiBA,SAAgB,EAAqB,GAAuB;CAC1D,IAAM,IAAM,EAAoB,CAAK,GAC/B,IAAQ,qCAAqC,KAAK,CAAG;CAO3D,OANI,IACK,IAAI,EAAM,KAAK,EAAM,KAAK,EAAM,KAAK,EAAM,KAAK,EAAM,KAAK,EAAM,KAAK,YAAY,IAEvF,kBAAkB,KAAK,CAAG,IACrB,EAAI,YAAY,IAElB;AACT;;;ACvBA,SAAgB,IAA0C;CACxD,OAAO,EAAO,GAAkB,EAAwB,IAAI,CAAC;AAC/D;;;ACUA,SAAgB,IAKd;CACA,IAAM,IAAc,EAAe;CACnC,SAAS,EAAQ,GAGf;EACA,IAAM,IAAO,EAAY,OAAO,sBAAsB;EAEtD,OADK,IACE;GAAE,KAAK,EAAS,MAAM,EAAK;GAAK,MAAM,EAAS,OAAO,EAAK;EAAK,IADrD;GAAE,KAAK,EAAS;GAAK,MAAM,EAAS;EAAK;CAE7D;CACA,OAAO,EAAE,WAAQ;AACnB"}
@@ -1,5 +1,5 @@
1
1
  import { k as e } from "./draggable-IB4x6w2O.js";
2
- import { t } from "./useEditorRoot-DFx2fXJP.js";
2
+ import { t } from "./useEditorRoot-CshefZLP.js";
3
3
  //#region src/composables/useScrollToBlock.ts
4
4
  function n() {
5
5
  let n = t();
@@ -19,4 +19,4 @@ function r() {
19
19
  //#endregion
20
20
  export { n as t };
21
21
 
22
- //# sourceMappingURL=useScrollToBlock-CtTXwmiU.js.map
22
+ //# sourceMappingURL=useScrollToBlock-DgHZJvID.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useScrollToBlock-CtTXwmiU.js","names":[],"sources":["../../../src/composables/useScrollToBlock.ts"],"sourcesContent":["import { nextTick } from \"vue\";\nimport { useEditorRoot } from \"./useEditorRoot\";\n\n/**\n * Returns a function that brings a block into view on the canvas.\n *\n * Selecting a block is not by itself visible: on a long template the selected\n * block can sit far below the fold while the canvas stays exactly where it was,\n * so an insert or a jump reads as \"nothing happened\". This is what makes the\n * outcome visible at the user's position.\n *\n * Queries through `useEditorRoot()` rather than `document` — in the default\n * shadow-DOM mount the blocks live in the shadow tree, where a document-level\n * query matches nothing.\n *\n * Scrolling is deferred one tick so a block inserted in the same call has\n * rendered by the time it is looked up. `block: \"nearest\"` leaves an\n * already-visible block alone instead of yanking it to the top.\n */\nexport function useScrollToBlock(): (blockId: string) => void {\n const root = useEditorRoot();\n\n return (blockId: string) => {\n void nextTick(() => {\n const target = root.querySelector(`[data-block-id=\"${blockId}\"]`);\n if (!target) return;\n target.scrollIntoView({\n block: \"nearest\",\n behavior: prefersReducedMotion() ? \"auto\" : \"smooth\",\n });\n });\n };\n}\n\nfunction prefersReducedMotion(): boolean {\n // Absent in some embedding contexts; a throw here would break the insert\n // that asked for the scroll, so treat \"can't tell\" as motion allowed.\n if (typeof matchMedia !== \"function\") return false;\n return matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n"],"mappings":";;;AAmBA,SAAgB,IAA8C;CAC5D,IAAM,IAAO,EAAc;CAE3B,QAAQ,MAAoB;EAC1B,QAAoB;GAClB,IAAM,IAAS,EAAK,cAAc,mBAAmB,EAAQ,GAAG;GAC3D,KACL,EAAO,eAAe;IACpB,OAAO;IACP,UAAU,EAAqB,IAAI,SAAS;GAC9C,CAAC;EACH,CAAC;CACH;AACF;AAEA,SAAS,IAAgC;CAIvC,OADI,OAAO,cAAe,cACnB,WAAW,kCAAkC,CAAC,CAAC;AACxD"}
1
+ {"version":3,"file":"useScrollToBlock-DgHZJvID.js","names":[],"sources":["../../../src/composables/useScrollToBlock.ts"],"sourcesContent":["import { nextTick } from \"vue\";\nimport { useEditorRoot } from \"./useEditorRoot\";\n\n/**\n * Returns a function that brings a block into view on the canvas.\n *\n * Selecting a block is not by itself visible: on a long template the selected\n * block can sit far below the fold while the canvas stays exactly where it was,\n * so an insert or a jump reads as \"nothing happened\". This is what makes the\n * outcome visible at the user's position.\n *\n * Queries through `useEditorRoot()` rather than `document` — in the default\n * shadow-DOM mount the blocks live in the shadow tree, where a document-level\n * query matches nothing.\n *\n * Scrolling is deferred one tick so a block inserted in the same call has\n * rendered by the time it is looked up. `block: \"nearest\"` leaves an\n * already-visible block alone instead of yanking it to the top.\n */\nexport function useScrollToBlock(): (blockId: string) => void {\n const root = useEditorRoot();\n\n return (blockId: string) => {\n void nextTick(() => {\n const target = root.querySelector(`[data-block-id=\"${blockId}\"]`);\n if (!target) return;\n target.scrollIntoView({\n block: \"nearest\",\n behavior: prefersReducedMotion() ? \"auto\" : \"smooth\",\n });\n });\n };\n}\n\nfunction prefersReducedMotion(): boolean {\n // Absent in some embedding contexts; a throw here would break the insert\n // that asked for the scroll, so treat \"can't tell\" as motion allowed.\n if (typeof matchMedia !== \"function\") return false;\n return matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n"],"mappings":";;;AAmBA,SAAgB,IAA8C;CAC5D,IAAM,IAAO,EAAc;CAE3B,QAAQ,MAAoB;EAC1B,QAAoB;GAClB,IAAM,IAAS,EAAK,cAAc,mBAAmB,EAAQ,GAAG;GAC3D,KACL,EAAO,eAAe;IACpB,OAAO;IACP,UAAU,EAAqB,IAAI,SAAS;GAC9C,CAAC;EACH,CAAC;CACH;AACF;AAEA,SAAS,IAAgC;CAIvC,OADI,OAAO,cAAe,cACnB,WAAW,kCAAkC,CAAC,CAAC;AACxD"}