@templatical/editor 0.0.4 → 0.0.6
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.
- package/dist/AiChatSidebar-CNhSl_ty.js +228 -0
- package/dist/{AiFeatureMenu-K44aZa_P.js → AiFeatureMenu-BFVsjUJY.js} +23 -23
- package/dist/CloudEditor-Bz5Xkxej.js +1082 -0
- package/dist/{CollaboratorBar-BuCEcdbB.js → CollaboratorBar-D2Gu5Xj2.js} +3 -3
- package/dist/{CommentsSidebar-2lcqMfIP.js → CommentsSidebar-CTeEAZTj.js} +131 -131
- package/dist/{DesignReferenceSidebar-CNMu4Zrx.js → DesignReferenceSidebar-u2tKSQK0.js} +52 -52
- package/dist/{LoadingTrack-vK8W2PJf.js → LoadingTrack--aUassFH.js} +1 -1
- package/dist/{ModuleBrowserModal-CvQ0xyQf.js → ModuleBrowserModal-DNxODPlX.js} +58 -58
- package/dist/{ModulePreviewCanvas-Be2B3Y07.js → ModulePreviewCanvas-DnGe1Y-2.js} +32 -32
- package/dist/ParagraphEditor-CYrzYJO5.js +688 -0
- package/dist/{RichTextEditorContent-CHJlh7HJ.js → RichTextEditorContent-BeqlWlWB.js} +2 -2
- package/dist/{SaveModuleDialog-BaaeH5Xm.js → SaveModuleDialog-Kde6X13X.js} +25 -25
- package/dist/{SnapshotHistory-BPfjiuu1.js → SnapshotHistory-B3EfIcLW.js} +7 -7
- package/dist/TemplateScoringPanel-D2vCRGgx.js +254 -0
- package/dist/{TestEmailModal-DIAlB3e_.js → TestEmailModal-Egk0DFDf.js} +3 -3
- package/dist/{TitleEditor-D9DPjQkX.js → TitleEditor-DwUpo4gF.js} +11 -11
- package/dist/{TplModal-CmTSvCY-.js → TplModal-BCruYWks.js} +4 -4
- package/dist/{_plugin-vue_export-helper-B1-bu7yR.js → _plugin-vue_export-helper-5TQrnOhO.js} +2 -2
- package/dist/{blockTypeIcons-D1RTWOkx.js → blockTypeIcons-rW4BUUNC.js} +2 -2
- package/dist/cdn/chunks/{AiFeatureMenu-lxVm1RjH.js → AiFeatureMenu-Dcbshcfu.js} +16 -16
- package/dist/cdn/chunks/AiFeatureMenu-Dcbshcfu.js.map +1 -0
- package/dist/cdn/chunks/CloudEditor-Bca3RyBW.js +1056 -0
- package/dist/cdn/chunks/CloudEditor-Bca3RyBW.js.map +1 -0
- package/dist/cdn/chunks/{CollaboratorBar-D2PKtlOw.js → CollaboratorBar-sToKJfHi.js} +4 -4
- package/dist/cdn/chunks/{CollaboratorBar-D2PKtlOw.js.map → CollaboratorBar-sToKJfHi.js.map} +1 -1
- package/dist/cdn/chunks/{ModuleBrowserModal-CxDXzkKS.js → ModuleBrowserModal-BNhwXbWw.js} +52 -52
- package/dist/cdn/chunks/ModuleBrowserModal-BNhwXbWw.js.map +1 -0
- package/dist/cdn/chunks/{ModulePreviewCanvas-DEfHampA.js → ModulePreviewCanvas-DylUylPU.js} +3 -3
- package/dist/cdn/chunks/{ModulePreviewCanvas-DEfHampA.js.map → ModulePreviewCanvas-DylUylPU.js.map} +1 -1
- package/dist/cdn/chunks/ParagraphEditor-BBw90y_p.js +539 -0
- package/dist/cdn/chunks/ParagraphEditor-BBw90y_p.js.map +1 -0
- package/dist/cdn/chunks/{RichTextEditorContent-DWUzizsC.js → RichTextEditorContent-DvyIO3nR.js} +5 -5
- package/dist/cdn/chunks/{RichTextEditorContent-DWUzizsC.js.map → RichTextEditorContent-DvyIO3nR.js.map} +1 -1
- package/dist/cdn/chunks/{SaveModuleDialog-DVna2xUl.js → SaveModuleDialog-DvbSHvhF.js} +24 -24
- package/dist/cdn/chunks/SaveModuleDialog-DvbSHvhF.js.map +1 -0
- package/dist/cdn/chunks/{TitleEditor-DDf_OcHS.js → TitleEditor-tS3mgoVr.js} +10 -10
- package/dist/cdn/chunks/{TitleEditor-DDf_OcHS.js.map → TitleEditor-tS3mgoVr.js.map} +1 -1
- package/dist/cdn/chunks/{blockTypeIcons-BnobReQm.js → blockTypeIcons-DbnbyEQE.js} +3 -3
- package/dist/cdn/chunks/{blockTypeIcons-BnobReQm.js.map → blockTypeIcons-DbnbyEQE.js.map} +1 -1
- package/dist/cdn/chunks/{de-BvYD17KT.js → de-CgUR_S5I.js} +1 -1
- package/dist/cdn/chunks/{de-BvYD17KT.js.map → de-CgUR_S5I.js.map} +1 -1
- package/dist/cdn/chunks/{de-BB3dgVOc.js → de-D8oDPhBD.js} +1 -1
- package/dist/cdn/chunks/de-D8oDPhBD.js.map +1 -0
- package/dist/cdn/chunks/{dist-B878xb_62.js → dist-BUmN5e4r.js} +15 -12
- package/dist/cdn/chunks/dist-BUmN5e4r.js.map +1 -0
- package/dist/cdn/chunks/{draggable-BQNU47zu.js → draggable-m78lz0gI.js} +1591 -1563
- package/dist/cdn/chunks/draggable-m78lz0gI.js.map +1 -0
- package/dist/cdn/chunks/{emojiData-BVEJHcNH.js → emojiData-CNNgvDqx.js} +1 -1
- package/dist/cdn/chunks/{emojiData-BVEJHcNH.js.map → emojiData-CNNgvDqx.js.map} +1 -1
- package/dist/cdn/chunks/{en-CpotcOPr.js → en-BBmfBDqY.js} +1 -1
- package/dist/cdn/chunks/{en-CpotcOPr.js.map → en-BBmfBDqY.js.map} +1 -1
- package/dist/cdn/chunks/{en-DeDcpnoS.js → en-HseRPPeK.js} +1 -1
- package/dist/cdn/chunks/en-HseRPPeK.js.map +1 -0
- package/dist/cdn/chunks/{extensions-B_kcV0tK.js → extensions-ClpY3m0W.js} +31 -31
- package/dist/cdn/chunks/{extensions-B_kcV0tK.js.map → extensions-ClpY3m0W.js.map} +1 -1
- package/dist/cdn/chunks/{features-ofOGnSC0.js → features-B5dGxWLi.js} +1645 -1608
- package/dist/cdn/chunks/features-B5dGxWLi.js.map +1 -0
- package/dist/cdn/chunks/{icons-bIb7PBOE.js → icons-hflTyPmb.js} +8 -8
- package/dist/cdn/chunks/icons-hflTyPmb.js.map +1 -0
- package/dist/cdn/chunks/{liquid.browser-C1VIYISn.js → liquid.browser-BxyRVCKv.js} +24 -17
- package/dist/cdn/chunks/liquid.browser-BxyRVCKv.js.map +1 -0
- package/dist/cdn/chunks/{media-library-BIYzV2Y2.js → media-library-Dgy-V-JA.js} +547 -543
- package/dist/cdn/chunks/{media-library-BIYzV2Y2.js.map → media-library-Dgy-V-JA.js.map} +1 -1
- package/dist/cdn/chunks/{pusher-DJPhQnE8.js → pusher-D-m2WSdL.js} +10 -7
- package/dist/cdn/chunks/pusher-D-m2WSdL.js.map +1 -0
- package/dist/cdn/chunks/readableTextColor-Cd_cgWO_.js.map +1 -1
- package/dist/cdn/chunks/{rolldown-runtime-DPITmOBR.js → rolldown-runtime-BNuo_Jkg.js} +1 -1
- package/dist/cdn/chunks/{src-BuW9oYtm.js → src-TDwMmqm0.js} +7 -7
- package/dist/cdn/chunks/{src-BuW9oYtm.js.map → src-TDwMmqm0.js.map} +1 -1
- package/dist/cdn/chunks/{styleConstants-1KwsBMxJ.js → styleConstants-DFe3I4Op.js} +6 -6
- package/dist/cdn/chunks/{styleConstants-1KwsBMxJ.js.map → styleConstants-DFe3I4Op.js.map} +1 -1
- package/dist/cdn/chunks/{styles-DQFExz-T.js → styles-hCOCOR6K.js} +1229 -1101
- package/dist/cdn/chunks/styles-hCOCOR6K.js.map +1 -0
- package/dist/cdn/chunks/{tiptap-DplY-S-k.js → tiptap-C28NLMX8.js} +1531 -1309
- package/dist/cdn/chunks/tiptap-C28NLMX8.js.map +1 -0
- package/dist/cdn/editor.css +1 -1
- package/dist/cdn/editor.js +112 -141
- package/dist/cdn/editor.js.map +1 -1
- package/dist/{check-B7kDuZmP.js → check-B5S-C0bz.js} +1 -1
- package/dist/{chevron-down-DJLW2Q9Z.js → chevron-down-CjsV1T0W.js} +1 -1
- package/dist/{circle-alert-E2vYPs5r.js → circle-alert-CVTmJHKW.js} +1 -1
- package/dist/{clock-lWIIQA3C.js → clock-CAjdSHBy.js} +1 -1
- package/dist/{dist-CG-vEqSU.js → dist-Ac4o1O4a.js} +2 -2
- package/dist/{dist-BkIys9zn.js → dist-B4LTlrAn.js} +6 -6
- package/dist/{dist-ChAGLpWo.js → dist-BTtKPcd2.js} +2 -2
- package/dist/{dist-C1BIRHCQ.js → dist-CBr-qhie.js} +2 -2
- package/dist/{dist-DmOE-Ubp.js → dist-COOFiBFV.js} +2 -2
- package/dist/{dist-4LiM9FDd.js → dist-COguaIvm.js} +2 -2
- package/dist/{dist-Bu7veieH.js → dist-Crqkuf-w.js} +2 -2
- package/dist/{dist-DkypH7qG.js → dist-DEJZ9iAU.js} +2 -2
- package/dist/{dist-D_HQYSY-.js → dist-DHYuVJ_7.js} +2 -2
- package/dist/{dist-C_ymrGFi.js → dist-DJrDTuRr.js} +973 -958
- package/dist/{dist-DysAFIPy.js → dist-DPM-DFvh.js} +142 -114
- package/dist/{dist-DrvKRSU6.js → dist-DfqLGwSF.js} +2 -2
- package/dist/dist-DmVOCJjI.js +5 -0
- package/dist/{extensions-DEjfEFhD.js → extensions-C6xp_B7K.js} +3 -3
- package/dist/{image-up-X4xIq4ea.js → image-up-vZa1Txr-.js} +1 -1
- package/dist/index.d.ts +223 -0
- package/dist/{liquid.browser-BemTg3sZ.js → liquid.browser-C02owkex.js} +20 -15
- package/dist/{loader-circle-BTQQxC3l.js → loader-circle-DilFjHSk.js} +1 -1
- package/dist/{message-circle-Blgm6V_h.js → message-circle-Dpcnc2oa.js} +1 -1
- package/dist/{refresh-cw-Bb4PEeW1.js → refresh-cw-4r7rkHHX.js} +1 -1
- package/dist/rolldown-runtime-gEudmnaM.js +23 -0
- package/dist/{scan-line-7lZPfOdm.js → scan-line-684IxPQ0.js} +1 -1
- package/dist/{send-C0ltAQrv.js → send-ChDw64yL.js} +1 -1
- package/dist/{shield-check-f-qv4RKs.js → shield-check-9dhLdyST.js} +1 -1
- package/dist/{sparkles-KhBCGlqB.js → sparkles-Co9fkDcv.js} +1 -1
- package/dist/{styleConstants-D4SOZGBV.js → styleConstants-RV3eYwkD.js} +6 -6
- package/dist/styles-nvxFh6L6.js +3557 -0
- package/dist/templatical-editor.css +1 -1
- package/dist/templatical-editor.js +111 -141
- package/dist/templatical-editor.umd.cjs +63 -73
- package/dist/{trash-2-OwjZ-guZ.js → trash-2-CZkMtjeC.js} +1 -1
- package/dist/{triangle-alert-DOSRIUYZ.js → triangle-alert-Dvt51agD.js} +1 -1
- package/dist/{useEditorCore-CjwRMl7K.js → useEditorCore-ColJh1ST.js} +1183 -1182
- package/dist/{x-CGlq2XQe.js → x-CU2XZOkQ.js} +1 -1
- package/package.json +52 -49
- package/dist/AiChatSidebar-CjfhTZwo.js +0 -214
- package/dist/CloudEditor-DFyuRxUV.js +0 -926
- package/dist/ParagraphEditor-CcMPnbDr.js +0 -652
- package/dist/TemplateScoringPanel-D58A23Vq.js +0 -249
- package/dist/cdn/chunks/AiChatSidebar-CmPTbTFG.js +0 -2
- package/dist/cdn/chunks/AiFeatureMenu-lxVm1RjH.js.map +0 -1
- package/dist/cdn/chunks/CloudEditor-Bmp5IlWi.js +0 -900
- package/dist/cdn/chunks/CloudEditor-Bmp5IlWi.js.map +0 -1
- package/dist/cdn/chunks/CommentsSidebar-BOelj4Ca.js +0 -2
- package/dist/cdn/chunks/DesignReferenceSidebar-Bf6rg0A7.js +0 -2
- package/dist/cdn/chunks/ModuleBrowserModal-CxDXzkKS.js.map +0 -1
- package/dist/cdn/chunks/ParagraphEditor-DHdu6lb3.js +0 -503
- package/dist/cdn/chunks/ParagraphEditor-DHdu6lb3.js.map +0 -1
- package/dist/cdn/chunks/SaveModuleDialog-DVna2xUl.js.map +0 -1
- package/dist/cdn/chunks/SnapshotHistory-BFF2SsTN.js +0 -2
- package/dist/cdn/chunks/TemplateScoringPanel-gi8wc_m7.js +0 -2
- package/dist/cdn/chunks/TestEmailModal-Qtd6aC-6.js +0 -2
- package/dist/cdn/chunks/de-BB3dgVOc.js.map +0 -1
- package/dist/cdn/chunks/dist-B6AUkMyh.js +0 -2
- package/dist/cdn/chunks/dist-B878xb_62.js.map +0 -1
- package/dist/cdn/chunks/dist-Bf1Op9A1.js +0 -2
- package/dist/cdn/chunks/dist-BkETaOfw.js +0 -2
- package/dist/cdn/chunks/dist-CJcMnY7o.js +0 -2
- package/dist/cdn/chunks/dist-CWsl6S1K.js +0 -2
- package/dist/cdn/chunks/dist-CllLxIMQ.js +0 -2
- package/dist/cdn/chunks/dist-Cs0wFwdw.js +0 -2
- package/dist/cdn/chunks/dist-DLWHlekl.js +0 -2
- package/dist/cdn/chunks/dist-DS3_HVpX.js +0 -2
- package/dist/cdn/chunks/dist-DTXopj1a.js +0 -2
- package/dist/cdn/chunks/dist-DnwLoNLm.js +0 -2
- package/dist/cdn/chunks/draggable-BQNU47zu.js.map +0 -1
- package/dist/cdn/chunks/en-DeDcpnoS.js.map +0 -1
- package/dist/cdn/chunks/features-ofOGnSC0.js.map +0 -1
- package/dist/cdn/chunks/icons-bIb7PBOE.js.map +0 -1
- package/dist/cdn/chunks/liquid.browser-C1VIYISn.js.map +0 -1
- package/dist/cdn/chunks/pusher-DJPhQnE8.js.map +0 -1
- package/dist/cdn/chunks/styles-DQFExz-T.js.map +0 -1
- package/dist/cdn/chunks/tiptap-DplY-S-k.js.map +0 -1
- package/dist/dist-Dxnd0GRf.js +0 -5
- package/dist/styles-CgLaxDfu.js +0 -3428
- /package/dist/{de-D7TLGIPA.js → de-Dh8ON-dm.js} +0 -0
- /package/dist/{emojiData-BfWQS72m.js → emojiData-Qc8mH_zW.js} +0 -0
- /package/dist/{en-DvtiEMwP.js → en-C7IShRSD.js} +0 -0
- /package/dist/{formatRelativeTime-DX3FgqN9.js → formatRelativeTime-D8f6NR7i.js} +0 -0
- /package/dist/{readableTextColor-LDlmVEUv.js → readableTextColor-B809bF5J.js} +0 -0
- /package/dist/{useMergeTag-BZ3X0bNr.js → useMergeTag-CSXcnFBc.js} +0 -0
package/dist/cdn/editor.js
CHANGED
|
@@ -1,33 +1,20 @@
|
|
|
1
|
-
import { $ as e, H as t, M as n, N as r, S as i, U as a, _ as o, at as s, b as c, c as l, ct as u, g as
|
|
2
|
-
import { $ as
|
|
3
|
-
import { S as
|
|
4
|
-
import { a as
|
|
5
|
-
import { t as
|
|
1
|
+
import { $ as e, H as t, M as n, N as r, S as i, U as a, _ as o, at as s, b as c, c as l, ct as u, g as d, j as f, lt as p, m, n as h, r as g, st as _, w as v, y } from "./chunks/draggable-m78lz0gI.js";
|
|
2
|
+
import { $ as b, J as x, Mn as S, k as C, on as w } from "./chunks/features-B5dGxWLi.js";
|
|
3
|
+
import { S as ee } from "./chunks/icons-hflTyPmb.js";
|
|
4
|
+
import { a as T, i as E, n as D, o as O, r as k, s as A, t as j } from "./chunks/styles-hCOCOR6K.js";
|
|
5
|
+
import { t as M } from "./chunks/_rolldown_dynamic_import_helper-DMEI4TQ3.js";
|
|
6
6
|
//#region src/Editor.vue?vue&type=script&setup=true&lang.ts
|
|
7
|
-
var
|
|
7
|
+
var N = ["data-tpl-theme"], P = {
|
|
8
8
|
class: "tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4 tpl:shadow-[var(--tpl-shadow-md)] tpl:border-b tpl:border-[var(--tpl-border)]",
|
|
9
9
|
style: {
|
|
10
10
|
"background-color": "color-mix(in srgb, var(--tpl-bg) 80%, transparent)",
|
|
11
11
|
"backdrop-filter": "blur(12px)",
|
|
12
12
|
"-webkit-backdrop-filter": "blur(12px)"
|
|
13
13
|
}
|
|
14
|
-
},
|
|
14
|
+
}, F = { class: "tpl:flex tpl:items-center tpl:gap-2.5" }, I = {
|
|
15
15
|
class: "tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]",
|
|
16
16
|
style: { "letter-spacing": "-0.01em" }
|
|
17
|
-
},
|
|
18
|
-
class: "tpl:pointer-events-auto tpl:flex tpl:items-center tpl:gap-1.5 tpl:rounded-tl-lg tpl:p-1",
|
|
19
|
-
style: {
|
|
20
|
-
"background-color": "color-mix(\n in srgb,\n var(--tpl-canvas-bg) 85%,\n transparent\n )",
|
|
21
|
-
"backdrop-filter": "blur(8px)",
|
|
22
|
-
"-webkit-backdrop-filter": "blur(8px)"
|
|
23
|
-
}
|
|
24
|
-
}, me = {
|
|
25
|
-
href: "https://github.com/templatical/sdk",
|
|
26
|
-
target: "_blank",
|
|
27
|
-
rel: "noopener noreferrer",
|
|
28
|
-
class: "tpl:transition-colors tpl:duration-150 hover:tpl:opacity-80 tpl:text-[var(--tpl-text-dim)]",
|
|
29
|
-
style: { "text-decoration": "none" }
|
|
30
|
-
}, he = ["aria-label"], ge = /* @__PURE__ */ _(/* @__PURE__ */ i({
|
|
17
|
+
}, L = { class: "tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, R = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, z = { class: "tpl:flex tpl:justify-center tpl:p-8" }, B = ["aria-label"], V = /* @__PURE__ */ b(/* @__PURE__ */ i({
|
|
31
18
|
__name: "Editor",
|
|
32
19
|
props: {
|
|
33
20
|
config: {},
|
|
@@ -35,83 +22,83 @@ var V = ["data-tpl-theme"], H = {
|
|
|
35
22
|
fontsManager: {}
|
|
36
23
|
},
|
|
37
24
|
setup(e, { expose: i }) {
|
|
38
|
-
let
|
|
39
|
-
content:
|
|
40
|
-
templateDefaults:
|
|
41
|
-
}),
|
|
42
|
-
editor:
|
|
25
|
+
let g = e, v = w({
|
|
26
|
+
content: g.config.content,
|
|
27
|
+
templateDefaults: g.config.templateDefaults
|
|
28
|
+
}), b = C({
|
|
29
|
+
editor: v,
|
|
43
30
|
config: {
|
|
44
|
-
uiTheme:
|
|
45
|
-
theme:
|
|
46
|
-
blockDefaults:
|
|
47
|
-
customBlocks:
|
|
48
|
-
mergeTags:
|
|
49
|
-
displayConditions:
|
|
50
|
-
onRequestMedia:
|
|
51
|
-
onSave:
|
|
31
|
+
uiTheme: g.config.uiTheme,
|
|
32
|
+
theme: g.config.theme,
|
|
33
|
+
blockDefaults: g.config.blockDefaults,
|
|
34
|
+
customBlocks: g.config.customBlocks,
|
|
35
|
+
mergeTags: g.config.mergeTags,
|
|
36
|
+
displayConditions: g.config.displayConditions,
|
|
37
|
+
onRequestMedia: g.config.onRequestMedia,
|
|
38
|
+
onSave: g.config.onSave ? () => g.config.onSave(JSON.parse(JSON.stringify(v.state.content))) : void 0
|
|
52
39
|
},
|
|
53
|
-
translations:
|
|
54
|
-
fontsManager:
|
|
55
|
-
autoSaveOptions:
|
|
40
|
+
translations: g.translations,
|
|
41
|
+
fontsManager: g.fontsManager,
|
|
42
|
+
autoSaveOptions: g.config.onChange ? { onChange: () => g.config.onChange(JSON.parse(JSON.stringify(v.state.content))) } : null
|
|
56
43
|
});
|
|
57
|
-
return
|
|
58
|
-
await
|
|
44
|
+
return f(async () => {
|
|
45
|
+
await g.fontsManager.loadCustomFonts();
|
|
59
46
|
}), n(() => {
|
|
60
|
-
|
|
47
|
+
g.fontsManager.cleanupFontLinks(), b.destroy();
|
|
61
48
|
}), i({
|
|
62
|
-
getContent: () =>
|
|
63
|
-
setContent: (e) =>
|
|
64
|
-
setTheme: (e) =>
|
|
49
|
+
getContent: () => v.content.value,
|
|
50
|
+
setContent: (e) => v.setContent(e),
|
|
51
|
+
setTheme: (e) => v.setUiTheme(e)
|
|
65
52
|
}), (e, n) => (r(), o("div", {
|
|
66
|
-
class:
|
|
67
|
-
"data-tpl-theme": s(
|
|
68
|
-
style: u(s(
|
|
53
|
+
class: _(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": s(v).state.darkMode }]),
|
|
54
|
+
"data-tpl-theme": s(b).resolvedTheme.value,
|
|
55
|
+
style: u(s(b).themeStyles.value)
|
|
69
56
|
}, [
|
|
70
|
-
|
|
71
|
-
|
|
57
|
+
m("header", P, [
|
|
58
|
+
m("div", F, [n[5] ||= m("img", {
|
|
72
59
|
width: "24",
|
|
73
60
|
height: "24",
|
|
74
61
|
src: "https://templatical.com/logo.svg",
|
|
75
62
|
alt: "Templatical"
|
|
76
|
-
}, null, -1),
|
|
77
|
-
|
|
78
|
-
c(
|
|
79
|
-
viewport: s(
|
|
80
|
-
onChange: s(
|
|
63
|
+
}, null, -1), m("span", I, p(s(b).t.header.title), 1)]),
|
|
64
|
+
m("div", L, [
|
|
65
|
+
c(E, {
|
|
66
|
+
viewport: s(v).state.viewport,
|
|
67
|
+
onChange: s(v).setViewport
|
|
81
68
|
}, null, 8, ["viewport", "onChange"]),
|
|
82
|
-
c(
|
|
83
|
-
"dark-mode": s(
|
|
84
|
-
onChange: s(
|
|
69
|
+
c(D, {
|
|
70
|
+
"dark-mode": s(v).state.darkMode,
|
|
71
|
+
onChange: s(v).setDarkMode
|
|
85
72
|
}, null, 8, ["dark-mode", "onChange"]),
|
|
86
|
-
c(
|
|
87
|
-
"preview-mode": s(
|
|
88
|
-
onChange: s(
|
|
73
|
+
c(k, {
|
|
74
|
+
"preview-mode": s(v).state.previewMode,
|
|
75
|
+
onChange: s(v).setPreviewMode
|
|
89
76
|
}, null, 8, ["preview-mode", "onChange"])
|
|
90
77
|
]),
|
|
91
|
-
n[6] ||=
|
|
78
|
+
n[6] ||= m("div", { class: "tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, null, -1)
|
|
92
79
|
]),
|
|
93
|
-
a(c(
|
|
94
|
-
|
|
95
|
-
class:
|
|
80
|
+
a(c(O, null, null, 512), [[l, !s(v).state.previewMode]]),
|
|
81
|
+
m("div", {
|
|
82
|
+
class: _(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto tpl:bg-[var(--tpl-canvas-bg)]", [s(v).state.previewMode ? "tpl:left-0 tpl:right-0" : "tpl:left-12 tpl:right-[320px]", "tpl:top-14"]]),
|
|
96
83
|
style: { transition: "all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)" }
|
|
97
|
-
}, [
|
|
98
|
-
default: t(() => [s(
|
|
84
|
+
}, [m("div", R, [c(h, { name: "tpl-restore-btn" }, {
|
|
85
|
+
default: t(() => [s(b).conditionPreview.hasHiddenBlocks.value ? (r(), o("button", {
|
|
99
86
|
key: 0,
|
|
100
87
|
class: "tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80 tpl:bg-[var(--tpl-warning-light)] tpl:text-[var(--tpl-warning)] tpl:border-[var(--tpl-warning)]",
|
|
101
88
|
style: { "backdrop-filter": "blur(8px)" },
|
|
102
|
-
onClick: n[0] ||= (e) => s(
|
|
103
|
-
}, [c(s(
|
|
89
|
+
onClick: n[0] ||= (e) => s(b).conditionPreview.reset()
|
|
90
|
+
}, [c(s(ee), {
|
|
104
91
|
size: 13,
|
|
105
92
|
"stroke-width": 2
|
|
106
|
-
}),
|
|
93
|
+
}), y(" " + p(s(b).t.blockSettings.restoreHiddenBlocks), 1)])) : d("", !0)]),
|
|
107
94
|
_: 1
|
|
108
|
-
})]),
|
|
109
|
-
viewport: s(
|
|
110
|
-
content: s(
|
|
111
|
-
"selected-block-id": s(
|
|
112
|
-
"dark-mode": s(
|
|
113
|
-
"preview-mode": s(
|
|
114
|
-
onSelectBlock: s(
|
|
95
|
+
})]), m("div", z, [c(A, {
|
|
96
|
+
viewport: s(v).state.viewport,
|
|
97
|
+
content: s(v).content.value,
|
|
98
|
+
"selected-block-id": s(v).state.selectedBlockId,
|
|
99
|
+
"dark-mode": s(v).state.darkMode,
|
|
100
|
+
"preview-mode": s(v).state.previewMode,
|
|
101
|
+
onSelectBlock: s(v).selectBlock
|
|
115
102
|
}, null, 8, [
|
|
116
103
|
"viewport",
|
|
117
104
|
"content",
|
|
@@ -120,142 +107,126 @@ var V = ["data-tpl-theme"], H = {
|
|
|
120
107
|
"preview-mode",
|
|
121
108
|
"onSelectBlock"
|
|
122
109
|
])])], 2),
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
n[7] ||= f("a", {
|
|
126
|
-
href: "https://templatical.com",
|
|
127
|
-
target: "_blank",
|
|
128
|
-
rel: "noopener noreferrer",
|
|
129
|
-
class: "tpl:inline-flex tpl:items-center tpl:gap-1 tpl:font-medium tpl:transition-colors tpl:duration-150 hover:tpl:opacity-80 tpl:text-[var(--tpl-text-muted)]",
|
|
130
|
-
style: { "text-decoration": "none" }
|
|
131
|
-
}, [f("img", {
|
|
132
|
-
width: "14",
|
|
133
|
-
height: "14",
|
|
134
|
-
src: "https://templatical.com/logo.svg",
|
|
135
|
-
alt: ""
|
|
136
|
-
}), g(" Templatical ")], -1),
|
|
137
|
-
n[8] ||= f("span", { class: "tpl:text-[var(--tpl-border)]" }, "·", -1),
|
|
138
|
-
f("a", me, d(s(_).t.footer.openSource), 1)
|
|
139
|
-
])], 2),
|
|
140
|
-
f("div", {
|
|
110
|
+
c(j, { "position-class": [s(v).state.previewMode ? "tpl:left-0 tpl:right-0" : "tpl:left-12 tpl:right-[320px]"] }, null, 8, ["position-class"]),
|
|
111
|
+
m("div", {
|
|
141
112
|
class: "tpl-sr-only",
|
|
142
113
|
role: "status",
|
|
143
114
|
"aria-live": "polite",
|
|
144
115
|
"aria-atomic": "true",
|
|
145
|
-
"aria-label": s(
|
|
146
|
-
},
|
|
147
|
-
a(c(
|
|
148
|
-
"selected-block": s(
|
|
149
|
-
settings: s(
|
|
150
|
-
onUpdateBlock: n[1] ||= (e) => s(
|
|
116
|
+
"aria-label": s(b).t.landmarks.reorderAnnouncements
|
|
117
|
+
}, p(s(b).keyboardReorder.announcement.value), 9, B),
|
|
118
|
+
a(c(T, {
|
|
119
|
+
"selected-block": s(v).selectedBlock.value,
|
|
120
|
+
settings: s(v).content.value.settings,
|
|
121
|
+
onUpdateBlock: n[1] ||= (e) => s(v).updateBlock(s(v).state.selectedBlockId, e),
|
|
151
122
|
onDeleteBlock: n[2] ||= () => {
|
|
152
|
-
s(
|
|
123
|
+
s(v).state.selectedBlockId && s(b).blockActions.deleteBlock(s(v).state.selectedBlockId);
|
|
153
124
|
},
|
|
154
125
|
onDuplicateBlock: n[3] ||= () => {
|
|
155
|
-
s(
|
|
126
|
+
s(v).selectedBlock.value && s(b).blockActions.duplicateBlock(s(v).selectedBlock.value);
|
|
156
127
|
},
|
|
157
|
-
onUpdateSettings: n[4] ||= (e) => s(
|
|
158
|
-
}, null, 8, ["selected-block", "settings"]), [[l, !s(
|
|
159
|
-
], 14,
|
|
128
|
+
onUpdateSettings: n[4] ||= (e) => s(v).updateSettings(e)
|
|
129
|
+
}, null, 8, ["selected-block", "settings"]), [[l, !s(v).state.previewMode]])
|
|
130
|
+
], 14, N));
|
|
160
131
|
}
|
|
161
|
-
}), [["__scopeId", "data-v-
|
|
162
|
-
function
|
|
132
|
+
}), [["__scopeId", "data-v-8c8f0453"]]), H = ["en", "de"];
|
|
133
|
+
function U(e) {
|
|
163
134
|
return e.split("-")[0].toLowerCase();
|
|
164
135
|
}
|
|
165
|
-
async function
|
|
166
|
-
let t =
|
|
167
|
-
return (await
|
|
168
|
-
"./locales/de.ts": () => import("./chunks/de-
|
|
169
|
-
"./locales/en.ts": () => import("./chunks/en-
|
|
136
|
+
async function W(e) {
|
|
137
|
+
let t = U(e), n = H.includes(t) ? t : "en";
|
|
138
|
+
return (await M(/* @__PURE__ */ Object.assign({
|
|
139
|
+
"./locales/de.ts": () => import("./chunks/de-D8oDPhBD.js"),
|
|
140
|
+
"./locales/en.ts": () => import("./chunks/en-HseRPPeK.js")
|
|
170
141
|
}), `./locales/${n}.ts`, 3)).default;
|
|
171
142
|
}
|
|
172
143
|
//#endregion
|
|
173
144
|
//#region src/index.ts
|
|
174
|
-
var
|
|
175
|
-
async function
|
|
145
|
+
var G = null, K = e(null);
|
|
146
|
+
async function q(e) {
|
|
176
147
|
let t = typeof e.container == "string" ? document.querySelector(e.container) : e.container;
|
|
177
148
|
if (!t) throw Error(`[Templatical] Container element not found: ${e.container}`);
|
|
178
|
-
|
|
179
|
-
let n = await
|
|
180
|
-
|
|
181
|
-
return () =>
|
|
149
|
+
G && Z();
|
|
150
|
+
let n = await W(e.locale ?? "en"), r = x(e.fonts);
|
|
151
|
+
G = g({ setup() {
|
|
152
|
+
return () => v(V, {
|
|
182
153
|
config: e,
|
|
183
154
|
translations: n,
|
|
184
155
|
fontsManager: r,
|
|
185
|
-
ref:
|
|
156
|
+
ref: K
|
|
186
157
|
});
|
|
187
|
-
} }),
|
|
158
|
+
} }), G.mount(t);
|
|
188
159
|
let i = {
|
|
189
160
|
getContent() {
|
|
190
|
-
return JSON.parse(JSON.stringify(
|
|
161
|
+
return JSON.parse(JSON.stringify(K.value ? K.value.getContent() : e.content));
|
|
191
162
|
},
|
|
192
163
|
setContent(t) {
|
|
193
|
-
|
|
164
|
+
K.value && K.value.setContent(t), e.content = t;
|
|
194
165
|
},
|
|
195
166
|
setTheme(e) {
|
|
196
|
-
|
|
167
|
+
K.value && K.value.setTheme(e);
|
|
197
168
|
},
|
|
198
169
|
unmount: Z
|
|
199
170
|
};
|
|
200
171
|
return $(i), i;
|
|
201
172
|
}
|
|
202
|
-
var
|
|
203
|
-
async function
|
|
173
|
+
var J = null, Y = e(null);
|
|
174
|
+
async function X(e) {
|
|
204
175
|
let t = typeof e.container == "string" ? document.querySelector(e.container) : e.container;
|
|
205
176
|
if (!t) throw Error(`[Templatical] Container element not found: ${e.container}`);
|
|
206
|
-
|
|
207
|
-
let { default: n } = await import("./chunks/CloudEditor-
|
|
177
|
+
J && Q();
|
|
178
|
+
let { default: n } = await import("./chunks/CloudEditor-Bca3RyBW.js"), r = await W(e.locale ?? "en"), i = x(e.fonts);
|
|
208
179
|
await new Promise((a, o) => {
|
|
209
180
|
let s = setTimeout(() => {
|
|
210
181
|
o(/* @__PURE__ */ Error("[Templatical] Cloud editor initialization timed out"));
|
|
211
|
-
},
|
|
212
|
-
|
|
213
|
-
return () =>
|
|
182
|
+
}, S);
|
|
183
|
+
J = g({ setup() {
|
|
184
|
+
return () => v(n, {
|
|
214
185
|
config: e,
|
|
215
186
|
translations: r,
|
|
216
187
|
fontsManager: i,
|
|
217
|
-
ref:
|
|
188
|
+
ref: Y,
|
|
218
189
|
onReady: () => {
|
|
219
190
|
clearTimeout(s), a();
|
|
220
191
|
}
|
|
221
192
|
});
|
|
222
|
-
} }),
|
|
193
|
+
} }), J.mount(t);
|
|
223
194
|
});
|
|
224
195
|
let a = {
|
|
225
196
|
getContent() {
|
|
226
|
-
return JSON.parse(JSON.stringify(
|
|
197
|
+
return JSON.parse(JSON.stringify(Y.value ? Y.value.getContent() : e.content));
|
|
227
198
|
},
|
|
228
199
|
setContent(e) {
|
|
229
|
-
|
|
200
|
+
Y.value && Y.value.setContent(e);
|
|
230
201
|
},
|
|
231
202
|
setTheme(e) {
|
|
232
|
-
|
|
203
|
+
Y.value && Y.value.setTheme(e);
|
|
233
204
|
},
|
|
234
205
|
unmount: Q,
|
|
235
206
|
create(e) {
|
|
236
|
-
return
|
|
207
|
+
return Y.value ? Y.value.create(e) : Promise.reject(/* @__PURE__ */ Error("[Templatical] Cloud editor not ready"));
|
|
237
208
|
},
|
|
238
209
|
load(e) {
|
|
239
|
-
return
|
|
210
|
+
return Y.value ? Y.value.load(e) : Promise.reject(/* @__PURE__ */ Error("[Templatical] Cloud editor not ready"));
|
|
240
211
|
},
|
|
241
212
|
save() {
|
|
242
|
-
return
|
|
213
|
+
return Y.value ? Y.value.save() : Promise.reject(/* @__PURE__ */ Error("[Templatical] Cloud editor not ready"));
|
|
243
214
|
}
|
|
244
215
|
};
|
|
245
216
|
return $(a), a;
|
|
246
217
|
}
|
|
247
218
|
function Z() {
|
|
248
|
-
|
|
219
|
+
G && (G.unmount(), G = null, K.value = null);
|
|
249
220
|
}
|
|
250
221
|
function Q() {
|
|
251
|
-
|
|
222
|
+
J && (J.unmount(), J = null, Y.value = null);
|
|
252
223
|
}
|
|
253
224
|
function $(e) {
|
|
254
|
-
import("./chunks/dist-
|
|
225
|
+
import("./chunks/dist-BUmN5e4r.js").then((t) => {
|
|
255
226
|
e.toMjml = () => t.renderToMjml(e.getContent());
|
|
256
227
|
}).catch(() => {});
|
|
257
228
|
}
|
|
258
229
|
//#endregion
|
|
259
|
-
export {
|
|
230
|
+
export { q as init, X as initCloud, Z as unmount, x as useFonts };
|
|
260
231
|
|
|
261
232
|
//# sourceMappingURL=editor.js.map
|
package/dist/cdn/editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.js","names":[],"sources":["../../src/Editor.vue","../../src/Editor.vue","../../src/i18n/index.ts","../../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onMounted, onUnmounted } from \"vue\";\nimport type { TemplaticalEditorConfig } from \"./index\";\nimport { useEditor } from \"@templatical/core\";\nimport type { TemplateContent, UiTheme } from \"@templatical/types\";\nimport { useEditorCore } from \"./composables/useEditorCore\";\nimport type { Translations } from \"./i18n\";\nimport type { UseFontsReturn } from \"./composables/useFonts\";\n\nimport { RotateCcw } from \"@lucide/vue\";\nimport Canvas from \"./components/Canvas.vue\";\nimport Sidebar from \"./components/Sidebar.vue\";\nimport RightSidebar from \"./components/RightSidebar.vue\";\nimport ViewportToggle from \"./components/ViewportToggle.vue\";\nimport PreviewToggle from \"./components/PreviewToggle.vue\";\nimport DarkModeToggle from \"./components/DarkModeToggle.vue\";\nimport \"./styles/index.css\";\n\nconst props = defineProps<{\n config: TemplaticalEditorConfig;\n translations: Translations;\n fontsManager: UseFontsReturn;\n}>();\n\n// --- Core editor state ---\nconst editor = useEditor({\n content: props.config.content!,\n templateDefaults: props.config.templateDefaults,\n});\n\n// --- Shared editor core (composables, provides, plugins, keyboard) ---\nconst core = useEditorCore({\n editor,\n config: {\n uiTheme: props.config.uiTheme,\n theme: props.config.theme,\n blockDefaults: props.config.blockDefaults,\n customBlocks: props.config.customBlocks,\n mergeTags: props.config.mergeTags,\n displayConditions: props.config.displayConditions,\n onRequestMedia: props.config.onRequestMedia,\n onSave: props.config.onSave\n ? () =>\n props.config.onSave!(JSON.parse(JSON.stringify(editor.state.content)))\n : undefined,\n },\n translations: props.translations,\n fontsManager: props.fontsManager,\n autoSaveOptions: props.config.onChange\n ? {\n onChange: () =>\n props.config.onChange!(\n JSON.parse(JSON.stringify(editor.state.content)),\n ),\n }\n : null,\n});\n\n// --- Lifecycle ---\nonMounted(async () => {\n await props.fontsManager.loadCustomFonts();\n});\n\nonUnmounted(() => {\n props.fontsManager.cleanupFontLinks();\n core.destroy();\n});\n\n// --- Public API (accessed via template ref from init()) ---\ndefineExpose({\n getContent: () => editor.content.value,\n setContent: (content: TemplateContent) => editor.setContent(content),\n setTheme: (theme: UiTheme) => editor.setUiTheme(theme),\n});\n</script>\n\n<template>\n <div\n class=\"tpl tpl:relative tpl:h-full tpl:overflow-hidden\"\n :class=\"{ 'tpl:dark': editor.state.darkMode }\"\n :data-tpl-theme=\"core.resolvedTheme.value\"\n :style=\"core.themeStyles.value\"\n >\n <!-- Header — absolute, full width, above everything -->\n <header\n class=\"tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4 tpl:shadow-[var(--tpl-shadow-md)] tpl:border-b tpl:border-[var(--tpl-border)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-bg) 80%, transparent);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n \"\n >\n <!-- Left: Logo -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-2.5\">\n <img\n width=\"24\"\n height=\"24\"\n src=\"https://templatical.com/logo.svg\"\n alt=\"Templatical\"\n />\n <span\n class=\"tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n style=\"letter-spacing: -0.01em\"\n >\n {{ core.t.header.title }}\n </span>\n </div>\n\n <!-- Center: viewport + preview + dark mode -->\n <div class=\"tpl:flex tpl:items-center tpl:justify-center tpl:gap-10\">\n <ViewportToggle\n :viewport=\"editor.state.viewport\"\n @change=\"editor.setViewport\"\n />\n <DarkModeToggle\n :dark-mode=\"editor.state.darkMode\"\n @change=\"editor.setDarkMode\"\n />\n <PreviewToggle\n :preview-mode=\"editor.state.previewMode\"\n @change=\"editor.setPreviewMode\"\n />\n </div>\n\n <!-- Right: empty in OSS mode -->\n <div\n class=\"tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3\"\n ></div>\n </header>\n\n <!-- Left sidebar — absolute, below header -->\n <Sidebar v-show=\"!editor.state.previewMode\" />\n\n <!-- Canvas area — absolute, fills remaining space -->\n <div\n class=\"tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto tpl:bg-[var(--tpl-canvas-bg)]\"\n style=\"transition: all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)\"\n :class=\"[\n editor.state.previewMode\n ? 'tpl:left-0 tpl:right-0'\n : 'tpl:left-12 tpl:right-[320px]',\n 'tpl:top-14',\n ]\"\n >\n <!-- Restore hidden blocks button -->\n <div class=\"tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0\">\n <Transition name=\"tpl-restore-btn\">\n <button\n v-if=\"core.conditionPreview.hasHiddenBlocks.value\"\n class=\"tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80 tpl:bg-[var(--tpl-warning-light)] tpl:text-[var(--tpl-warning)] tpl:border-[var(--tpl-warning)]\"\n style=\"backdrop-filter: blur(8px)\"\n @click=\"core.conditionPreview.reset()\"\n >\n <RotateCcw :size=\"13\" :stroke-width=\"2\" />\n {{ core.t.blockSettings.restoreHiddenBlocks }}\n </button>\n </Transition>\n </div>\n <div class=\"tpl:flex tpl:justify-center tpl:p-8\">\n <Canvas\n :viewport=\"editor.state.viewport\"\n :content=\"editor.content.value\"\n :selected-block-id=\"editor.state.selectedBlockId\"\n :dark-mode=\"editor.state.darkMode\"\n :preview-mode=\"editor.state.previewMode\"\n @select-block=\"editor.selectBlock\"\n />\n </div>\n </div>\n\n <!-- Footer — OSS branding -->\n <footer\n class=\"tpl:pointer-events-none tpl:absolute tpl:bottom-0 tpl:z-50 tpl:flex tpl:h-8 tpl:items-center tpl:justify-end tpl:pr-4 tpl:text-[9px] tpl:opacity-90 tpl:transition-all tpl:duration-300 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"[\n editor.state.previewMode\n ? 'tpl:left-0 tpl:right-0'\n : 'tpl:left-12 tpl:right-[320px]',\n ]\"\n >\n <div\n class=\"tpl:pointer-events-auto tpl:flex tpl:items-center tpl:gap-1.5 tpl:rounded-tl-lg tpl:p-1\"\n style=\"\n background-color: color-mix(\n in srgb,\n var(--tpl-canvas-bg) 85%,\n transparent\n );\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n \"\n >\n <span>{{ core.t.footer.poweredBy }}</span>\n <a\n href=\"https://templatical.com\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"tpl:inline-flex tpl:items-center tpl:gap-1 tpl:font-medium tpl:transition-colors tpl:duration-150 hover:tpl:opacity-80 tpl:text-[var(--tpl-text-muted)]\"\n style=\"text-decoration: none\"\n >\n <img\n width=\"14\"\n height=\"14\"\n src=\"https://templatical.com/logo.svg\"\n alt=\"\"\n />\n Templatical\n </a>\n <span class=\"tpl:text-[var(--tpl-border)]\">·</span>\n <a\n href=\"https://github.com/templatical/sdk\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"tpl:transition-colors tpl:duration-150 hover:tpl:opacity-80 tpl:text-[var(--tpl-text-dim)]\"\n style=\"text-decoration: none\"\n >\n {{ core.t.footer.openSource }}\n </a>\n </div>\n </footer>\n\n <!-- Keyboard reorder announcement region (visually hidden, screen-reader live) -->\n <div\n class=\"tpl-sr-only\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n :aria-label=\"core.t.landmarks.reorderAnnouncements\"\n >\n {{ core.keyboardReorder.announcement.value }}\n </div>\n\n <!-- Right sidebar — persisted with v-show -->\n <RightSidebar\n v-show=\"!editor.state.previewMode\"\n :selected-block=\"editor.selectedBlock.value\"\n :settings=\"editor.content.value.settings\"\n @update-block=\"\n (updates) => editor.updateBlock(editor.state.selectedBlockId!, updates)\n \"\n @delete-block=\"\n () => {\n if (editor.state.selectedBlockId) {\n core.blockActions.deleteBlock(editor.state.selectedBlockId);\n }\n }\n \"\n @duplicate-block=\"\n () => {\n if (editor.selectedBlock.value) {\n core.blockActions.duplicateBlock(editor.selectedBlock.value);\n }\n }\n \"\n @update-settings=\"(updates) => editor.updateSettings(updates)\"\n />\n </div>\n</template>\n\n<style scoped>\n.tpl-restore-btn-enter-active {\n transition:\n opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-restore-btn-leave-active {\n transition:\n opacity 150ms ease-in,\n transform 150ms ease-in;\n}\n\n.tpl-restore-btn-enter-from,\n.tpl-restore-btn-leave-to {\n opacity: 0;\n transform: translateY(-8px) scale(0.9);\n}\n\n.tpl-restore-btn-enter-to,\n.tpl-restore-btn-leave-from {\n opacity: 1;\n transform: translateY(0) scale(1);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { onMounted, onUnmounted } from \"vue\";\nimport type { TemplaticalEditorConfig } from \"./index\";\nimport { useEditor } from \"@templatical/core\";\nimport type { TemplateContent, UiTheme } from \"@templatical/types\";\nimport { useEditorCore } from \"./composables/useEditorCore\";\nimport type { Translations } from \"./i18n\";\nimport type { UseFontsReturn } from \"./composables/useFonts\";\n\nimport { RotateCcw } from \"@lucide/vue\";\nimport Canvas from \"./components/Canvas.vue\";\nimport Sidebar from \"./components/Sidebar.vue\";\nimport RightSidebar from \"./components/RightSidebar.vue\";\nimport ViewportToggle from \"./components/ViewportToggle.vue\";\nimport PreviewToggle from \"./components/PreviewToggle.vue\";\nimport DarkModeToggle from \"./components/DarkModeToggle.vue\";\nimport \"./styles/index.css\";\n\nconst props = defineProps<{\n config: TemplaticalEditorConfig;\n translations: Translations;\n fontsManager: UseFontsReturn;\n}>();\n\n// --- Core editor state ---\nconst editor = useEditor({\n content: props.config.content!,\n templateDefaults: props.config.templateDefaults,\n});\n\n// --- Shared editor core (composables, provides, plugins, keyboard) ---\nconst core = useEditorCore({\n editor,\n config: {\n uiTheme: props.config.uiTheme,\n theme: props.config.theme,\n blockDefaults: props.config.blockDefaults,\n customBlocks: props.config.customBlocks,\n mergeTags: props.config.mergeTags,\n displayConditions: props.config.displayConditions,\n onRequestMedia: props.config.onRequestMedia,\n onSave: props.config.onSave\n ? () =>\n props.config.onSave!(JSON.parse(JSON.stringify(editor.state.content)))\n : undefined,\n },\n translations: props.translations,\n fontsManager: props.fontsManager,\n autoSaveOptions: props.config.onChange\n ? {\n onChange: () =>\n props.config.onChange!(\n JSON.parse(JSON.stringify(editor.state.content)),\n ),\n }\n : null,\n});\n\n// --- Lifecycle ---\nonMounted(async () => {\n await props.fontsManager.loadCustomFonts();\n});\n\nonUnmounted(() => {\n props.fontsManager.cleanupFontLinks();\n core.destroy();\n});\n\n// --- Public API (accessed via template ref from init()) ---\ndefineExpose({\n getContent: () => editor.content.value,\n setContent: (content: TemplateContent) => editor.setContent(content),\n setTheme: (theme: UiTheme) => editor.setUiTheme(theme),\n});\n</script>\n\n<template>\n <div\n class=\"tpl tpl:relative tpl:h-full tpl:overflow-hidden\"\n :class=\"{ 'tpl:dark': editor.state.darkMode }\"\n :data-tpl-theme=\"core.resolvedTheme.value\"\n :style=\"core.themeStyles.value\"\n >\n <!-- Header — absolute, full width, above everything -->\n <header\n class=\"tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4 tpl:shadow-[var(--tpl-shadow-md)] tpl:border-b tpl:border-[var(--tpl-border)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-bg) 80%, transparent);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n \"\n >\n <!-- Left: Logo -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-2.5\">\n <img\n width=\"24\"\n height=\"24\"\n src=\"https://templatical.com/logo.svg\"\n alt=\"Templatical\"\n />\n <span\n class=\"tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n style=\"letter-spacing: -0.01em\"\n >\n {{ core.t.header.title }}\n </span>\n </div>\n\n <!-- Center: viewport + preview + dark mode -->\n <div class=\"tpl:flex tpl:items-center tpl:justify-center tpl:gap-10\">\n <ViewportToggle\n :viewport=\"editor.state.viewport\"\n @change=\"editor.setViewport\"\n />\n <DarkModeToggle\n :dark-mode=\"editor.state.darkMode\"\n @change=\"editor.setDarkMode\"\n />\n <PreviewToggle\n :preview-mode=\"editor.state.previewMode\"\n @change=\"editor.setPreviewMode\"\n />\n </div>\n\n <!-- Right: empty in OSS mode -->\n <div\n class=\"tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3\"\n ></div>\n </header>\n\n <!-- Left sidebar — absolute, below header -->\n <Sidebar v-show=\"!editor.state.previewMode\" />\n\n <!-- Canvas area — absolute, fills remaining space -->\n <div\n class=\"tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto tpl:bg-[var(--tpl-canvas-bg)]\"\n style=\"transition: all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)\"\n :class=\"[\n editor.state.previewMode\n ? 'tpl:left-0 tpl:right-0'\n : 'tpl:left-12 tpl:right-[320px]',\n 'tpl:top-14',\n ]\"\n >\n <!-- Restore hidden blocks button -->\n <div class=\"tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0\">\n <Transition name=\"tpl-restore-btn\">\n <button\n v-if=\"core.conditionPreview.hasHiddenBlocks.value\"\n class=\"tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80 tpl:bg-[var(--tpl-warning-light)] tpl:text-[var(--tpl-warning)] tpl:border-[var(--tpl-warning)]\"\n style=\"backdrop-filter: blur(8px)\"\n @click=\"core.conditionPreview.reset()\"\n >\n <RotateCcw :size=\"13\" :stroke-width=\"2\" />\n {{ core.t.blockSettings.restoreHiddenBlocks }}\n </button>\n </Transition>\n </div>\n <div class=\"tpl:flex tpl:justify-center tpl:p-8\">\n <Canvas\n :viewport=\"editor.state.viewport\"\n :content=\"editor.content.value\"\n :selected-block-id=\"editor.state.selectedBlockId\"\n :dark-mode=\"editor.state.darkMode\"\n :preview-mode=\"editor.state.previewMode\"\n @select-block=\"editor.selectBlock\"\n />\n </div>\n </div>\n\n <!-- Footer — OSS branding -->\n <footer\n class=\"tpl:pointer-events-none tpl:absolute tpl:bottom-0 tpl:z-50 tpl:flex tpl:h-8 tpl:items-center tpl:justify-end tpl:pr-4 tpl:text-[9px] tpl:opacity-90 tpl:transition-all tpl:duration-300 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"[\n editor.state.previewMode\n ? 'tpl:left-0 tpl:right-0'\n : 'tpl:left-12 tpl:right-[320px]',\n ]\"\n >\n <div\n class=\"tpl:pointer-events-auto tpl:flex tpl:items-center tpl:gap-1.5 tpl:rounded-tl-lg tpl:p-1\"\n style=\"\n background-color: color-mix(\n in srgb,\n var(--tpl-canvas-bg) 85%,\n transparent\n );\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n \"\n >\n <span>{{ core.t.footer.poweredBy }}</span>\n <a\n href=\"https://templatical.com\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"tpl:inline-flex tpl:items-center tpl:gap-1 tpl:font-medium tpl:transition-colors tpl:duration-150 hover:tpl:opacity-80 tpl:text-[var(--tpl-text-muted)]\"\n style=\"text-decoration: none\"\n >\n <img\n width=\"14\"\n height=\"14\"\n src=\"https://templatical.com/logo.svg\"\n alt=\"\"\n />\n Templatical\n </a>\n <span class=\"tpl:text-[var(--tpl-border)]\">·</span>\n <a\n href=\"https://github.com/templatical/sdk\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"tpl:transition-colors tpl:duration-150 hover:tpl:opacity-80 tpl:text-[var(--tpl-text-dim)]\"\n style=\"text-decoration: none\"\n >\n {{ core.t.footer.openSource }}\n </a>\n </div>\n </footer>\n\n <!-- Keyboard reorder announcement region (visually hidden, screen-reader live) -->\n <div\n class=\"tpl-sr-only\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n :aria-label=\"core.t.landmarks.reorderAnnouncements\"\n >\n {{ core.keyboardReorder.announcement.value }}\n </div>\n\n <!-- Right sidebar — persisted with v-show -->\n <RightSidebar\n v-show=\"!editor.state.previewMode\"\n :selected-block=\"editor.selectedBlock.value\"\n :settings=\"editor.content.value.settings\"\n @update-block=\"\n (updates) => editor.updateBlock(editor.state.selectedBlockId!, updates)\n \"\n @delete-block=\"\n () => {\n if (editor.state.selectedBlockId) {\n core.blockActions.deleteBlock(editor.state.selectedBlockId);\n }\n }\n \"\n @duplicate-block=\"\n () => {\n if (editor.selectedBlock.value) {\n core.blockActions.duplicateBlock(editor.selectedBlock.value);\n }\n }\n \"\n @update-settings=\"(updates) => editor.updateSettings(updates)\"\n />\n </div>\n</template>\n\n<style scoped>\n.tpl-restore-btn-enter-active {\n transition:\n opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-restore-btn-leave-active {\n transition:\n opacity 150ms ease-in,\n transform 150ms ease-in;\n}\n\n.tpl-restore-btn-enter-from,\n.tpl-restore-btn-leave-to {\n opacity: 0;\n transform: translateY(-8px) scale(0.9);\n}\n\n.tpl-restore-btn-enter-to,\n.tpl-restore-btn-leave-from {\n opacity: 1;\n transform: translateY(0) scale(1);\n}\n</style>\n","import type en from \"./locales/en\";\n\nexport type Translations = typeof en;\nexport type TranslationKey = keyof Translations;\n\nconst supportedLocales = [\"en\", \"de\"];\n\n/**\n * Get the base language code from a locale string.\n * e.g., 'en-GB' -> 'en', 'de-DE' -> 'de'\n */\nexport function getBaseLocale(locale: string): string {\n return locale.split(\"-\")[0].toLowerCase();\n}\n\n/**\n * Load translations for a given locale.\n * Falls back to English if the locale is not supported.\n * Only loads the required locale file.\n */\nexport async function loadTranslations(locale: string): Promise<Translations> {\n const baseLocale = getBaseLocale(locale);\n const targetLocale = supportedLocales.includes(baseLocale)\n ? baseLocale\n : \"en\";\n\n const module = await import(`./locales/${targetLocale}.ts`);\n return module.default as Translations;\n}\n\n/**\n * Check if a locale is supported.\n */\nexport function isLocaleSupported(locale: string): boolean {\n return (\n supportedLocales.includes(locale) ||\n supportedLocales.includes(getBaseLocale(locale))\n );\n}\n\n/**\n * Get list of supported locales.\n */\nexport function getSupportedLocales(): string[] {\n return [...supportedLocales];\n}\n","import { createApp, h, ref, type App, type Ref } from \"vue\";\nimport { INIT_TIMEOUT_MS } from \"./constants/timeouts\";\nimport type {\n BlockDefaults,\n CustomBlockDefinition,\n DisplayConditionsConfig,\n FontsConfig,\n MediaResult,\n MergeTagsConfig,\n SaveResult,\n Template,\n TemplateContent,\n TemplateDefaults,\n ThemeOverrides,\n UiTheme,\n} from \"@templatical/types\";\nimport type { MediaRequestContext } from \"@templatical/media-library\";\n\nimport Editor from \"./Editor.vue\";\nimport { loadTranslations } from \"./i18n\";\nimport { useFonts } from \"./composables\";\n\n// ---------------------------------------------------------------------------\n// OSS config + return types\n// ---------------------------------------------------------------------------\n\nexport interface TemplaticalEditorConfig {\n container: string | HTMLElement;\n content?: TemplateContent;\n\n onChange?: (content: TemplateContent) => void;\n onSave?: (content: TemplateContent) => void;\n onError?: (error: Error) => void;\n\n onRequestMedia?: OnRequestMedia;\n\n mergeTags?: MergeTagsConfig;\n displayConditions?: DisplayConditionsConfig;\n customBlocks?: CustomBlockDefinition[];\n fonts?: FontsConfig;\n\n blockDefaults?: BlockDefaults;\n templateDefaults?: TemplateDefaults;\n\n theme?: ThemeOverrides;\n uiTheme?: UiTheme;\n locale?: string;\n}\n\n/** Function type for media browser requests, used by both OSS and Cloud editors. */\nexport type OnRequestMedia = (\n context?: MediaRequestContext,\n) => Promise<MediaResult | null>;\n\nexport interface TemplaticalEditor {\n getContent(): TemplateContent;\n setContent(content: TemplateContent): void;\n setTheme(theme: UiTheme): void;\n unmount(): void;\n toMjml?(): string;\n}\n\nexport interface TemplaticalCloudEditor extends TemplaticalEditor {\n create(content?: TemplateContent): Promise<Template>;\n load(templateId: string): Promise<Template>;\n save(): Promise<SaveResult>;\n}\n\n// ---------------------------------------------------------------------------\n// OSS init — sync\n// ---------------------------------------------------------------------------\n\nlet appInstance: App | null = null;\nconst editorRef: Ref<InstanceType<typeof Editor> | null> = ref(null);\n\nexport async function init(\n config: TemplaticalEditorConfig,\n): Promise<TemplaticalEditor> {\n const container =\n typeof config.container === \"string\"\n ? document.querySelector(config.container)\n : config.container;\n\n if (!container) {\n throw new Error(\n `[Templatical] Container element not found: ${config.container}`,\n );\n }\n\n if (appInstance) {\n unmount();\n }\n\n // Load translations before mounting so child components can use useI18n synchronously\n const translations = await loadTranslations(config.locale ?? \"en\");\n\n // Create fonts manager to pass to Editor\n const fontsManager = useFonts(config.fonts);\n\n appInstance = createApp({\n setup() {\n return () =>\n h(Editor, {\n config,\n translations,\n fontsManager,\n ref: editorRef,\n });\n },\n });\n\n appInstance.mount(container);\n\n const instance: TemplaticalEditor = {\n getContent() {\n if (editorRef.value) {\n return JSON.parse(JSON.stringify(editorRef.value.getContent()));\n }\n return JSON.parse(JSON.stringify(config.content));\n },\n setContent(content: TemplateContent) {\n if (editorRef.value) {\n editorRef.value.setContent(content);\n }\n config.content = content;\n },\n setTheme(theme: UiTheme) {\n if (editorRef.value) {\n editorRef.value.setTheme(theme);\n }\n },\n unmount,\n };\n\n // Try to detect @templatical/renderer for export methods\n attachRenderer(instance);\n\n return instance;\n}\n\n// ---------------------------------------------------------------------------\n// Cloud init — async, flat config, tree-shaken when not called\n// ---------------------------------------------------------------------------\n\nlet cloudAppInstance: App | null = null;\n\nconst cloudEditorRef: Ref<InstanceType<\n typeof import(\"./cloud/CloudEditor.vue\").default\n> | null> = ref(null);\n\nexport async function initCloud(\n config: import(\"./cloud/CloudEditor.vue\").TemplaticalCloudEditorConfig,\n): Promise<TemplaticalCloudEditor> {\n const container =\n typeof config.container === \"string\"\n ? document.querySelector(config.container)\n : config.container;\n\n if (!container) {\n throw new Error(\n `[Templatical] Container element not found: ${config.container}`,\n );\n }\n\n if (cloudAppInstance) {\n unmountCloud();\n }\n\n // Dynamic import — CloudEditor.vue is tree-shaken from the OSS bundle\n const { default: CloudEditor } = await import(\"./cloud/CloudEditor.vue\");\n\n // Load translations before mounting so child components can use useI18n synchronously\n const translations = await loadTranslations(config.locale ?? \"en\");\n\n // Create fonts manager to pass to CloudEditor\n const fontsManager = useFonts(config.fonts);\n\n // Promise that resolves when CloudEditor emits 'ready'\n const readyPromise = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(\"[Templatical] Cloud editor initialization timed out\"));\n }, INIT_TIMEOUT_MS);\n\n cloudAppInstance = createApp({\n setup() {\n return () =>\n h(CloudEditor, {\n config,\n translations,\n fontsManager,\n ref: cloudEditorRef,\n onReady: () => {\n clearTimeout(timeout);\n resolve();\n },\n });\n },\n });\n\n cloudAppInstance.mount(container);\n });\n\n await readyPromise;\n\n const instance: TemplaticalCloudEditor = {\n getContent() {\n if (cloudEditorRef.value) {\n return JSON.parse(JSON.stringify(cloudEditorRef.value.getContent()));\n }\n return JSON.parse(JSON.stringify(config.content));\n },\n setContent(content: TemplateContent) {\n if (cloudEditorRef.value) {\n cloudEditorRef.value.setContent(content);\n }\n },\n setTheme(theme: UiTheme) {\n if (cloudEditorRef.value) {\n cloudEditorRef.value.setTheme(theme);\n }\n },\n unmount: unmountCloud,\n create(content?: TemplateContent) {\n if (!cloudEditorRef.value) {\n return Promise.reject(\n new Error(\"[Templatical] Cloud editor not ready\"),\n );\n }\n return cloudEditorRef.value.create(content);\n },\n load(templateId: string) {\n if (!cloudEditorRef.value) {\n return Promise.reject(\n new Error(\"[Templatical] Cloud editor not ready\"),\n );\n }\n return cloudEditorRef.value.load(templateId);\n },\n save() {\n if (!cloudEditorRef.value) {\n return Promise.reject(\n new Error(\"[Templatical] Cloud editor not ready\"),\n );\n }\n return cloudEditorRef.value.save();\n },\n };\n\n // Try to detect @templatical/renderer for export methods\n attachRenderer(instance);\n\n return instance;\n}\n\n// ---------------------------------------------------------------------------\n// Unmount helpers\n// ---------------------------------------------------------------------------\n\nexport function unmount(): void {\n if (appInstance) {\n appInstance.unmount();\n appInstance = null;\n editorRef.value = null;\n }\n}\n\nfunction unmountCloud(): void {\n if (cloudAppInstance) {\n cloudAppInstance.unmount();\n cloudAppInstance = null;\n cloudEditorRef.value = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Renderer attachment (shared by OSS + Cloud)\n// ---------------------------------------------------------------------------\n\nfunction attachRenderer(instance: TemplaticalEditor): void {\n import(\"@templatical/renderer\")\n .then((renderer) => {\n instance.toMjml = () => renderer.renderToMjml(instance.getContent());\n })\n .catch(() => {\n // @templatical/renderer not installed — export methods not available\n });\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport type { TemplaticalCloudEditorConfig } from \"./cloud/CloudEditor.vue\";\nexport type {\n BlockDefaults,\n TemplateContent,\n TemplateDefaults,\n ThemeOverrides,\n UiTheme,\n MergeTagsConfig,\n DisplayConditionsConfig,\n CustomBlockDefinition,\n ViewportSize,\n CustomFont,\n FontsConfig,\n SaveResult,\n Template,\n} from \"@templatical/types\";\n\nexport type { UseFontsReturn, FontOption } from \"./composables/useFonts\";\nexport { useFonts } from \"./composables/useFonts\";\nexport type { EditorCapabilities } from \"./types/editor-capabilities\";\nexport {\n TRANSLATIONS_KEY,\n EDITOR_KEY,\n HISTORY_KEY,\n BLOCK_ACTIONS_KEY,\n CONDITION_PREVIEW_KEY,\n FONTS_MANAGER_KEY,\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n BLOCK_DEFAULTS_KEY,\n BLOCK_REGISTRY_KEY,\n CUSTOM_BLOCK_DEFINITIONS_KEY,\n MERGE_TAGS_KEY,\n MERGE_TAG_SYNTAX_KEY,\n ON_REQUEST_MERGE_TAG_KEY,\n ON_REQUEST_MEDIA_KEY,\n DISPLAY_CONDITIONS_KEY,\n ALLOW_CUSTOM_CONDITIONS_KEY,\n CAPABILITIES_KEY,\n} from \"./keys\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"editor.js","names":[],"sources":["../../src/Editor.vue","../../src/Editor.vue","../../src/i18n/index.ts","../../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onMounted, onUnmounted } from \"vue\";\nimport type { TemplaticalEditorConfig } from \"./index\";\nimport { useEditor } from \"@templatical/core\";\nimport type { TemplateContent, UiTheme } from \"@templatical/types\";\nimport { useEditorCore } from \"./composables/useEditorCore\";\nimport type { Translations } from \"./i18n\";\nimport type { UseFontsReturn } from \"./composables/useFonts\";\n\nimport { RotateCcw } from \"@lucide/vue\";\nimport Canvas from \"./components/Canvas.vue\";\nimport Sidebar from \"./components/Sidebar.vue\";\nimport RightSidebar from \"./components/RightSidebar.vue\";\nimport ViewportToggle from \"./components/ViewportToggle.vue\";\nimport PreviewToggle from \"./components/PreviewToggle.vue\";\nimport DarkModeToggle from \"./components/DarkModeToggle.vue\";\nimport EditorFooter from \"./components/EditorFooter.vue\";\nimport \"./styles/index.css\";\n\nconst props = defineProps<{\n config: TemplaticalEditorConfig;\n translations: Translations;\n fontsManager: UseFontsReturn;\n}>();\n\n// --- Core editor state ---\nconst editor = useEditor({\n content: props.config.content!,\n templateDefaults: props.config.templateDefaults,\n});\n\n// --- Shared editor core (composables, provides, plugins, keyboard) ---\nconst core = useEditorCore({\n editor,\n config: {\n uiTheme: props.config.uiTheme,\n theme: props.config.theme,\n blockDefaults: props.config.blockDefaults,\n customBlocks: props.config.customBlocks,\n mergeTags: props.config.mergeTags,\n displayConditions: props.config.displayConditions,\n onRequestMedia: props.config.onRequestMedia,\n onSave: props.config.onSave\n ? () =>\n props.config.onSave!(JSON.parse(JSON.stringify(editor.state.content)))\n : undefined,\n },\n translations: props.translations,\n fontsManager: props.fontsManager,\n autoSaveOptions: props.config.onChange\n ? {\n onChange: () =>\n props.config.onChange!(\n JSON.parse(JSON.stringify(editor.state.content)),\n ),\n }\n : null,\n});\n\n// --- Lifecycle ---\nonMounted(async () => {\n await props.fontsManager.loadCustomFonts();\n});\n\nonUnmounted(() => {\n props.fontsManager.cleanupFontLinks();\n core.destroy();\n});\n\n// --- Public API (accessed via template ref from init()) ---\ndefineExpose({\n getContent: () => editor.content.value,\n setContent: (content: TemplateContent) => editor.setContent(content),\n setTheme: (theme: UiTheme) => editor.setUiTheme(theme),\n});\n</script>\n\n<template>\n <div\n class=\"tpl tpl:relative tpl:h-full tpl:overflow-hidden\"\n :class=\"{ 'tpl:dark': editor.state.darkMode }\"\n :data-tpl-theme=\"core.resolvedTheme.value\"\n :style=\"core.themeStyles.value\"\n >\n <!-- Header — absolute, full width, above everything -->\n <header\n class=\"tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4 tpl:shadow-[var(--tpl-shadow-md)] tpl:border-b tpl:border-[var(--tpl-border)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-bg) 80%, transparent);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n \"\n >\n <!-- Left: Logo -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-2.5\">\n <img\n width=\"24\"\n height=\"24\"\n src=\"https://templatical.com/logo.svg\"\n alt=\"Templatical\"\n />\n <span\n class=\"tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n style=\"letter-spacing: -0.01em\"\n >\n {{ core.t.header.title }}\n </span>\n </div>\n\n <!-- Center: viewport + preview + dark mode -->\n <div class=\"tpl:flex tpl:items-center tpl:justify-center tpl:gap-10\">\n <ViewportToggle\n :viewport=\"editor.state.viewport\"\n @change=\"editor.setViewport\"\n />\n <DarkModeToggle\n :dark-mode=\"editor.state.darkMode\"\n @change=\"editor.setDarkMode\"\n />\n <PreviewToggle\n :preview-mode=\"editor.state.previewMode\"\n @change=\"editor.setPreviewMode\"\n />\n </div>\n\n <!-- Right: empty in OSS mode -->\n <div\n class=\"tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3\"\n ></div>\n </header>\n\n <!-- Left sidebar — absolute, below header -->\n <Sidebar v-show=\"!editor.state.previewMode\" />\n\n <!-- Canvas area — absolute, fills remaining space -->\n <div\n class=\"tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto tpl:bg-[var(--tpl-canvas-bg)]\"\n style=\"transition: all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)\"\n :class=\"[\n editor.state.previewMode\n ? 'tpl:left-0 tpl:right-0'\n : 'tpl:left-12 tpl:right-[320px]',\n 'tpl:top-14',\n ]\"\n >\n <!-- Restore hidden blocks button -->\n <div class=\"tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0\">\n <Transition name=\"tpl-restore-btn\">\n <button\n v-if=\"core.conditionPreview.hasHiddenBlocks.value\"\n class=\"tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80 tpl:bg-[var(--tpl-warning-light)] tpl:text-[var(--tpl-warning)] tpl:border-[var(--tpl-warning)]\"\n style=\"backdrop-filter: blur(8px)\"\n @click=\"core.conditionPreview.reset()\"\n >\n <RotateCcw :size=\"13\" :stroke-width=\"2\" />\n {{ core.t.blockSettings.restoreHiddenBlocks }}\n </button>\n </Transition>\n </div>\n <div class=\"tpl:flex tpl:justify-center tpl:p-8\">\n <Canvas\n :viewport=\"editor.state.viewport\"\n :content=\"editor.content.value\"\n :selected-block-id=\"editor.state.selectedBlockId\"\n :dark-mode=\"editor.state.darkMode\"\n :preview-mode=\"editor.state.previewMode\"\n @select-block=\"editor.selectBlock\"\n />\n </div>\n </div>\n\n <EditorFooter\n :position-class=\"[\n editor.state.previewMode\n ? 'tpl:left-0 tpl:right-0'\n : 'tpl:left-12 tpl:right-[320px]',\n ]\"\n />\n\n <!-- Keyboard reorder announcement region (visually hidden, screen-reader live) -->\n <div\n class=\"tpl-sr-only\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n :aria-label=\"core.t.landmarks.reorderAnnouncements\"\n >\n {{ core.keyboardReorder.announcement.value }}\n </div>\n\n <!-- Right sidebar — persisted with v-show -->\n <RightSidebar\n v-show=\"!editor.state.previewMode\"\n :selected-block=\"editor.selectedBlock.value\"\n :settings=\"editor.content.value.settings\"\n @update-block=\"\n (updates) => editor.updateBlock(editor.state.selectedBlockId!, updates)\n \"\n @delete-block=\"\n () => {\n if (editor.state.selectedBlockId) {\n core.blockActions.deleteBlock(editor.state.selectedBlockId);\n }\n }\n \"\n @duplicate-block=\"\n () => {\n if (editor.selectedBlock.value) {\n core.blockActions.duplicateBlock(editor.selectedBlock.value);\n }\n }\n \"\n @update-settings=\"(updates) => editor.updateSettings(updates)\"\n />\n </div>\n</template>\n\n<style scoped>\n.tpl-restore-btn-enter-active {\n transition:\n opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-restore-btn-leave-active {\n transition:\n opacity 150ms ease-in,\n transform 150ms ease-in;\n}\n\n.tpl-restore-btn-enter-from,\n.tpl-restore-btn-leave-to {\n opacity: 0;\n transform: translateY(-8px) scale(0.9);\n}\n\n.tpl-restore-btn-enter-to,\n.tpl-restore-btn-leave-from {\n opacity: 1;\n transform: translateY(0) scale(1);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { onMounted, onUnmounted } from \"vue\";\nimport type { TemplaticalEditorConfig } from \"./index\";\nimport { useEditor } from \"@templatical/core\";\nimport type { TemplateContent, UiTheme } from \"@templatical/types\";\nimport { useEditorCore } from \"./composables/useEditorCore\";\nimport type { Translations } from \"./i18n\";\nimport type { UseFontsReturn } from \"./composables/useFonts\";\n\nimport { RotateCcw } from \"@lucide/vue\";\nimport Canvas from \"./components/Canvas.vue\";\nimport Sidebar from \"./components/Sidebar.vue\";\nimport RightSidebar from \"./components/RightSidebar.vue\";\nimport ViewportToggle from \"./components/ViewportToggle.vue\";\nimport PreviewToggle from \"./components/PreviewToggle.vue\";\nimport DarkModeToggle from \"./components/DarkModeToggle.vue\";\nimport EditorFooter from \"./components/EditorFooter.vue\";\nimport \"./styles/index.css\";\n\nconst props = defineProps<{\n config: TemplaticalEditorConfig;\n translations: Translations;\n fontsManager: UseFontsReturn;\n}>();\n\n// --- Core editor state ---\nconst editor = useEditor({\n content: props.config.content!,\n templateDefaults: props.config.templateDefaults,\n});\n\n// --- Shared editor core (composables, provides, plugins, keyboard) ---\nconst core = useEditorCore({\n editor,\n config: {\n uiTheme: props.config.uiTheme,\n theme: props.config.theme,\n blockDefaults: props.config.blockDefaults,\n customBlocks: props.config.customBlocks,\n mergeTags: props.config.mergeTags,\n displayConditions: props.config.displayConditions,\n onRequestMedia: props.config.onRequestMedia,\n onSave: props.config.onSave\n ? () =>\n props.config.onSave!(JSON.parse(JSON.stringify(editor.state.content)))\n : undefined,\n },\n translations: props.translations,\n fontsManager: props.fontsManager,\n autoSaveOptions: props.config.onChange\n ? {\n onChange: () =>\n props.config.onChange!(\n JSON.parse(JSON.stringify(editor.state.content)),\n ),\n }\n : null,\n});\n\n// --- Lifecycle ---\nonMounted(async () => {\n await props.fontsManager.loadCustomFonts();\n});\n\nonUnmounted(() => {\n props.fontsManager.cleanupFontLinks();\n core.destroy();\n});\n\n// --- Public API (accessed via template ref from init()) ---\ndefineExpose({\n getContent: () => editor.content.value,\n setContent: (content: TemplateContent) => editor.setContent(content),\n setTheme: (theme: UiTheme) => editor.setUiTheme(theme),\n});\n</script>\n\n<template>\n <div\n class=\"tpl tpl:relative tpl:h-full tpl:overflow-hidden\"\n :class=\"{ 'tpl:dark': editor.state.darkMode }\"\n :data-tpl-theme=\"core.resolvedTheme.value\"\n :style=\"core.themeStyles.value\"\n >\n <!-- Header — absolute, full width, above everything -->\n <header\n class=\"tpl-header tpl:absolute tpl:top-0 tpl:right-0 tpl:left-0 tpl:z-50 tpl:grid tpl:h-14 tpl:grid-cols-[1fr_auto_1fr] tpl:items-center tpl:px-4 tpl:shadow-[var(--tpl-shadow-md)] tpl:border-b tpl:border-[var(--tpl-border)]\"\n style=\"\n background-color: color-mix(in srgb, var(--tpl-bg) 80%, transparent);\n backdrop-filter: blur(12px);\n -webkit-backdrop-filter: blur(12px);\n \"\n >\n <!-- Left: Logo -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-2.5\">\n <img\n width=\"24\"\n height=\"24\"\n src=\"https://templatical.com/logo.svg\"\n alt=\"Templatical\"\n />\n <span\n class=\"tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n style=\"letter-spacing: -0.01em\"\n >\n {{ core.t.header.title }}\n </span>\n </div>\n\n <!-- Center: viewport + preview + dark mode -->\n <div class=\"tpl:flex tpl:items-center tpl:justify-center tpl:gap-10\">\n <ViewportToggle\n :viewport=\"editor.state.viewport\"\n @change=\"editor.setViewport\"\n />\n <DarkModeToggle\n :dark-mode=\"editor.state.darkMode\"\n @change=\"editor.setDarkMode\"\n />\n <PreviewToggle\n :preview-mode=\"editor.state.previewMode\"\n @change=\"editor.setPreviewMode\"\n />\n </div>\n\n <!-- Right: empty in OSS mode -->\n <div\n class=\"tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3\"\n ></div>\n </header>\n\n <!-- Left sidebar — absolute, below header -->\n <Sidebar v-show=\"!editor.state.previewMode\" />\n\n <!-- Canvas area — absolute, fills remaining space -->\n <div\n class=\"tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto tpl:bg-[var(--tpl-canvas-bg)]\"\n style=\"transition: all 300ms cubic-bezier(0.34, 1.56, 0.64, 1)\"\n :class=\"[\n editor.state.previewMode\n ? 'tpl:left-0 tpl:right-0'\n : 'tpl:left-12 tpl:right-[320px]',\n 'tpl:top-14',\n ]\"\n >\n <!-- Restore hidden blocks button -->\n <div class=\"tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0\">\n <Transition name=\"tpl-restore-btn\">\n <button\n v-if=\"core.conditionPreview.hasHiddenBlocks.value\"\n class=\"tpl:absolute tpl:left-1/2 tpl:top-2 tpl:-translate-x-1/2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-full tpl:border tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:whitespace-nowrap tpl:shadow-md tpl:hover:opacity-80 tpl:bg-[var(--tpl-warning-light)] tpl:text-[var(--tpl-warning)] tpl:border-[var(--tpl-warning)]\"\n style=\"backdrop-filter: blur(8px)\"\n @click=\"core.conditionPreview.reset()\"\n >\n <RotateCcw :size=\"13\" :stroke-width=\"2\" />\n {{ core.t.blockSettings.restoreHiddenBlocks }}\n </button>\n </Transition>\n </div>\n <div class=\"tpl:flex tpl:justify-center tpl:p-8\">\n <Canvas\n :viewport=\"editor.state.viewport\"\n :content=\"editor.content.value\"\n :selected-block-id=\"editor.state.selectedBlockId\"\n :dark-mode=\"editor.state.darkMode\"\n :preview-mode=\"editor.state.previewMode\"\n @select-block=\"editor.selectBlock\"\n />\n </div>\n </div>\n\n <EditorFooter\n :position-class=\"[\n editor.state.previewMode\n ? 'tpl:left-0 tpl:right-0'\n : 'tpl:left-12 tpl:right-[320px]',\n ]\"\n />\n\n <!-- Keyboard reorder announcement region (visually hidden, screen-reader live) -->\n <div\n class=\"tpl-sr-only\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n :aria-label=\"core.t.landmarks.reorderAnnouncements\"\n >\n {{ core.keyboardReorder.announcement.value }}\n </div>\n\n <!-- Right sidebar — persisted with v-show -->\n <RightSidebar\n v-show=\"!editor.state.previewMode\"\n :selected-block=\"editor.selectedBlock.value\"\n :settings=\"editor.content.value.settings\"\n @update-block=\"\n (updates) => editor.updateBlock(editor.state.selectedBlockId!, updates)\n \"\n @delete-block=\"\n () => {\n if (editor.state.selectedBlockId) {\n core.blockActions.deleteBlock(editor.state.selectedBlockId);\n }\n }\n \"\n @duplicate-block=\"\n () => {\n if (editor.selectedBlock.value) {\n core.blockActions.duplicateBlock(editor.selectedBlock.value);\n }\n }\n \"\n @update-settings=\"(updates) => editor.updateSettings(updates)\"\n />\n </div>\n</template>\n\n<style scoped>\n.tpl-restore-btn-enter-active {\n transition:\n opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),\n transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-restore-btn-leave-active {\n transition:\n opacity 150ms ease-in,\n transform 150ms ease-in;\n}\n\n.tpl-restore-btn-enter-from,\n.tpl-restore-btn-leave-to {\n opacity: 0;\n transform: translateY(-8px) scale(0.9);\n}\n\n.tpl-restore-btn-enter-to,\n.tpl-restore-btn-leave-from {\n opacity: 1;\n transform: translateY(0) scale(1);\n}\n</style>\n","import type en from \"./locales/en\";\n\nexport type Translations = typeof en;\nexport type TranslationKey = keyof Translations;\n\nconst supportedLocales = [\"en\", \"de\"];\n\n/**\n * Get the base language code from a locale string.\n * e.g., 'en-GB' -> 'en', 'de-DE' -> 'de'\n */\nexport function getBaseLocale(locale: string): string {\n return locale.split(\"-\")[0].toLowerCase();\n}\n\n/**\n * Load translations for a given locale.\n * Falls back to English if the locale is not supported.\n * Only loads the required locale file.\n */\nexport async function loadTranslations(locale: string): Promise<Translations> {\n const baseLocale = getBaseLocale(locale);\n const targetLocale = supportedLocales.includes(baseLocale)\n ? baseLocale\n : \"en\";\n\n const module = await import(`./locales/${targetLocale}.ts`);\n return module.default as Translations;\n}\n\n/**\n * Check if a locale is supported.\n */\nexport function isLocaleSupported(locale: string): boolean {\n return (\n supportedLocales.includes(locale) ||\n supportedLocales.includes(getBaseLocale(locale))\n );\n}\n\n/**\n * Get list of supported locales.\n */\nexport function getSupportedLocales(): string[] {\n return [...supportedLocales];\n}\n","import { createApp, h, ref, type App, type Ref } from \"vue\";\nimport { INIT_TIMEOUT_MS } from \"./constants/timeouts\";\nimport type {\n BlockDefaults,\n CustomBlockDefinition,\n DisplayConditionsConfig,\n FontsConfig,\n MediaResult,\n MergeTagsConfig,\n SaveResult,\n Template,\n TemplateContent,\n TemplateDefaults,\n ThemeOverrides,\n UiTheme,\n} from \"@templatical/types\";\nimport type { MediaRequestContext } from \"@templatical/media-library\";\n\nimport Editor from \"./Editor.vue\";\nimport { loadTranslations } from \"./i18n\";\nimport { useFonts } from \"./composables\";\n\n// ---------------------------------------------------------------------------\n// OSS config + return types\n// ---------------------------------------------------------------------------\n\nexport interface TemplaticalEditorConfig {\n container: string | HTMLElement;\n content?: TemplateContent;\n\n onChange?: (content: TemplateContent) => void;\n onSave?: (content: TemplateContent) => void;\n onError?: (error: Error) => void;\n\n onRequestMedia?: OnRequestMedia;\n\n mergeTags?: MergeTagsConfig;\n displayConditions?: DisplayConditionsConfig;\n customBlocks?: CustomBlockDefinition[];\n fonts?: FontsConfig;\n\n blockDefaults?: BlockDefaults;\n templateDefaults?: TemplateDefaults;\n\n theme?: ThemeOverrides;\n uiTheme?: UiTheme;\n locale?: string;\n}\n\n/** Function type for media browser requests, used by both OSS and Cloud editors. */\nexport type OnRequestMedia = (\n context?: MediaRequestContext,\n) => Promise<MediaResult | null>;\n\nexport interface TemplaticalEditor {\n getContent(): TemplateContent;\n setContent(content: TemplateContent): void;\n setTheme(theme: UiTheme): void;\n unmount(): void;\n toMjml?(): string;\n}\n\nexport interface TemplaticalCloudEditor extends TemplaticalEditor {\n create(content?: TemplateContent): Promise<Template>;\n load(templateId: string): Promise<Template>;\n save(): Promise<SaveResult>;\n}\n\n// ---------------------------------------------------------------------------\n// OSS init — sync\n// ---------------------------------------------------------------------------\n\nlet appInstance: App | null = null;\nconst editorRef: Ref<InstanceType<typeof Editor> | null> = ref(null);\n\nexport async function init(\n config: TemplaticalEditorConfig,\n): Promise<TemplaticalEditor> {\n const container =\n typeof config.container === \"string\"\n ? document.querySelector(config.container)\n : config.container;\n\n if (!container) {\n throw new Error(\n `[Templatical] Container element not found: ${config.container}`,\n );\n }\n\n if (appInstance) {\n unmount();\n }\n\n // Load translations before mounting so child components can use useI18n synchronously\n const translations = await loadTranslations(config.locale ?? \"en\");\n\n // Create fonts manager to pass to Editor\n const fontsManager = useFonts(config.fonts);\n\n appInstance = createApp({\n setup() {\n return () =>\n h(Editor, {\n config,\n translations,\n fontsManager,\n ref: editorRef,\n });\n },\n });\n\n appInstance.mount(container);\n\n const instance: TemplaticalEditor = {\n getContent() {\n if (editorRef.value) {\n return JSON.parse(JSON.stringify(editorRef.value.getContent()));\n }\n return JSON.parse(JSON.stringify(config.content));\n },\n setContent(content: TemplateContent) {\n if (editorRef.value) {\n editorRef.value.setContent(content);\n }\n config.content = content;\n },\n setTheme(theme: UiTheme) {\n if (editorRef.value) {\n editorRef.value.setTheme(theme);\n }\n },\n unmount,\n };\n\n // Try to detect @templatical/renderer for export methods\n attachRenderer(instance);\n\n return instance;\n}\n\n// ---------------------------------------------------------------------------\n// Cloud init — async, flat config, tree-shaken when not called\n// ---------------------------------------------------------------------------\n\nlet cloudAppInstance: App | null = null;\n\nconst cloudEditorRef: Ref<InstanceType<\n typeof import(\"./cloud/CloudEditor.vue\").default\n> | null> = ref(null);\n\nexport async function initCloud(\n config: import(\"./cloud/CloudEditor.vue\").TemplaticalCloudEditorConfig,\n): Promise<TemplaticalCloudEditor> {\n const container =\n typeof config.container === \"string\"\n ? document.querySelector(config.container)\n : config.container;\n\n if (!container) {\n throw new Error(\n `[Templatical] Container element not found: ${config.container}`,\n );\n }\n\n if (cloudAppInstance) {\n unmountCloud();\n }\n\n // Dynamic import — CloudEditor.vue is tree-shaken from the OSS bundle\n const { default: CloudEditor } = await import(\"./cloud/CloudEditor.vue\");\n\n // Load translations before mounting so child components can use useI18n synchronously\n const translations = await loadTranslations(config.locale ?? \"en\");\n\n // Create fonts manager to pass to CloudEditor\n const fontsManager = useFonts(config.fonts);\n\n // Promise that resolves when CloudEditor emits 'ready'\n const readyPromise = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(\"[Templatical] Cloud editor initialization timed out\"));\n }, INIT_TIMEOUT_MS);\n\n cloudAppInstance = createApp({\n setup() {\n return () =>\n h(CloudEditor, {\n config,\n translations,\n fontsManager,\n ref: cloudEditorRef,\n onReady: () => {\n clearTimeout(timeout);\n resolve();\n },\n });\n },\n });\n\n cloudAppInstance.mount(container);\n });\n\n await readyPromise;\n\n const instance: TemplaticalCloudEditor = {\n getContent() {\n if (cloudEditorRef.value) {\n return JSON.parse(JSON.stringify(cloudEditorRef.value.getContent()));\n }\n return JSON.parse(JSON.stringify(config.content));\n },\n setContent(content: TemplateContent) {\n if (cloudEditorRef.value) {\n cloudEditorRef.value.setContent(content);\n }\n },\n setTheme(theme: UiTheme) {\n if (cloudEditorRef.value) {\n cloudEditorRef.value.setTheme(theme);\n }\n },\n unmount: unmountCloud,\n create(content?: TemplateContent) {\n if (!cloudEditorRef.value) {\n return Promise.reject(\n new Error(\"[Templatical] Cloud editor not ready\"),\n );\n }\n return cloudEditorRef.value.create(content);\n },\n load(templateId: string) {\n if (!cloudEditorRef.value) {\n return Promise.reject(\n new Error(\"[Templatical] Cloud editor not ready\"),\n );\n }\n return cloudEditorRef.value.load(templateId);\n },\n save() {\n if (!cloudEditorRef.value) {\n return Promise.reject(\n new Error(\"[Templatical] Cloud editor not ready\"),\n );\n }\n return cloudEditorRef.value.save();\n },\n };\n\n // Try to detect @templatical/renderer for export methods\n attachRenderer(instance);\n\n return instance;\n}\n\n// ---------------------------------------------------------------------------\n// Unmount helpers\n// ---------------------------------------------------------------------------\n\nexport function unmount(): void {\n if (appInstance) {\n appInstance.unmount();\n appInstance = null;\n editorRef.value = null;\n }\n}\n\nfunction unmountCloud(): void {\n if (cloudAppInstance) {\n cloudAppInstance.unmount();\n cloudAppInstance = null;\n cloudEditorRef.value = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Renderer attachment (shared by OSS + Cloud)\n// ---------------------------------------------------------------------------\n\nfunction attachRenderer(instance: TemplaticalEditor): void {\n import(\"@templatical/renderer\")\n .then((renderer) => {\n instance.toMjml = () => renderer.renderToMjml(instance.getContent());\n })\n .catch(() => {\n // @templatical/renderer not installed — export methods not available\n });\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport type { TemplaticalCloudEditorConfig } from \"./cloud/CloudEditor.vue\";\nexport type {\n BlockDefaults,\n TemplateContent,\n TemplateDefaults,\n ThemeOverrides,\n UiTheme,\n MergeTagsConfig,\n DisplayConditionsConfig,\n CustomBlockDefinition,\n ViewportSize,\n CustomFont,\n FontsConfig,\n SaveResult,\n Template,\n} from \"@templatical/types\";\n\nexport type { UseFontsReturn, FontOption } from \"./composables/useFonts\";\nexport { useFonts } from \"./composables/useFonts\";\nexport type { EditorCapabilities } from \"./types/editor-capabilities\";\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { computed as e, getCurrentInstance as t, getCurrentScope as n, hasInjectionContext as r, inject as i, isRef as a, nextTick as o, onMounted as s, onScopeDispose as c, shallowReadonly as l, shallowRef as u, toValue as d, unref as f, watch as p, watchEffect as m } from "vue";
|
|
2
|
-
//#region ../../node_modules/.bun/@vueuse+shared@14.2.1+
|
|
2
|
+
//#region ../../node_modules/.bun/@vueuse+shared@14.2.1+987b49219a7ab62d/node_modules/@vueuse/shared/dist/index.js
|
|
3
3
|
function h(e, t) {
|
|
4
4
|
return n() ? (c(e, t), !0) : !1;
|
|
5
5
|
}
|
|
@@ -113,7 +113,7 @@ function F(e, t, n) {
|
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
115
|
//#endregion
|
|
116
|
-
//#region ../../node_modules/.bun/@vueuse+core@14.2.1+
|
|
116
|
+
//#region ../../node_modules/.bun/@vueuse+core@14.2.1+987b49219a7ab62d/node_modules/@vueuse/core/dist/index.js
|
|
117
117
|
var I = v ? window : void 0;
|
|
118
118
|
v && window.document, v && window.navigator, v && window.location;
|
|
119
119
|
function L(e) {
|