@templatical/editor 0.0.4 → 0.0.5

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 (108) hide show
  1. package/dist/{AiChatSidebar-CjfhTZwo.js → AiChatSidebar-DwME3f-a.js} +84 -70
  2. package/dist/{AiFeatureMenu-K44aZa_P.js → AiFeatureMenu-DJvWL1GZ.js} +23 -23
  3. package/dist/CloudEditor-Fe0ssRgi.js +1082 -0
  4. package/dist/{CollaboratorBar-BuCEcdbB.js → CollaboratorBar-DTT0EkZn.js} +1 -1
  5. package/dist/{CommentsSidebar-2lcqMfIP.js → CommentsSidebar-DrJhQRXK.js} +131 -131
  6. package/dist/{DesignReferenceSidebar-CNMu4Zrx.js → DesignReferenceSidebar-DdOht5zn.js} +49 -49
  7. package/dist/{ModuleBrowserModal-CvQ0xyQf.js → ModuleBrowserModal-CiV_jOEM.js} +58 -58
  8. package/dist/{ModulePreviewCanvas-Be2B3Y07.js → ModulePreviewCanvas-Bmy6Y1WE.js} +1 -1
  9. package/dist/ParagraphEditor-CoQ3NlS7.js +688 -0
  10. package/dist/{SaveModuleDialog-BaaeH5Xm.js → SaveModuleDialog-CD2ZYq1o.js} +25 -25
  11. package/dist/{SnapshotHistory-BPfjiuu1.js → SnapshotHistory-DltsKvhP.js} +1 -1
  12. package/dist/TemplateScoringPanel-DmnmUE3y.js +254 -0
  13. package/dist/{TestEmailModal-DIAlB3e_.js → TestEmailModal-Dl633j9o.js} +2 -2
  14. package/dist/{TitleEditor-D9DPjQkX.js → TitleEditor-C7fds2Nc.js} +3 -3
  15. package/dist/{TplModal-CmTSvCY-.js → TplModal-C5_CF-qn.js} +1 -1
  16. package/dist/{blockTypeIcons-D1RTWOkx.js → blockTypeIcons-BrKZB10B.js} +1 -1
  17. package/dist/cdn/chunks/AiChatSidebar-X_Bv3Qys.js +2 -0
  18. package/dist/cdn/chunks/{AiFeatureMenu-lxVm1RjH.js → AiFeatureMenu-C5UQmEgV.js} +16 -16
  19. package/dist/cdn/chunks/AiFeatureMenu-C5UQmEgV.js.map +1 -0
  20. package/dist/cdn/chunks/CloudEditor-DeTolKnf.js +1056 -0
  21. package/dist/cdn/chunks/CloudEditor-DeTolKnf.js.map +1 -0
  22. package/dist/cdn/chunks/{CollaboratorBar-D2PKtlOw.js → CollaboratorBar-DO1nxSrr.js} +3 -3
  23. package/dist/cdn/chunks/{CollaboratorBar-D2PKtlOw.js.map → CollaboratorBar-DO1nxSrr.js.map} +1 -1
  24. package/dist/cdn/chunks/CommentsSidebar-4MTw_hue.js +2 -0
  25. package/dist/cdn/chunks/DesignReferenceSidebar-Bswh4Yx4.js +2 -0
  26. package/dist/cdn/chunks/{ModuleBrowserModal-CxDXzkKS.js → ModuleBrowserModal-ChBr3aXj.js} +52 -52
  27. package/dist/cdn/chunks/ModuleBrowserModal-ChBr3aXj.js.map +1 -0
  28. package/dist/cdn/chunks/{ModulePreviewCanvas-DEfHampA.js → ModulePreviewCanvas-DkSvri9H.js} +2 -2
  29. package/dist/cdn/chunks/{ModulePreviewCanvas-DEfHampA.js.map → ModulePreviewCanvas-DkSvri9H.js.map} +1 -1
  30. package/dist/cdn/chunks/ParagraphEditor-DU3oUKA7.js +539 -0
  31. package/dist/cdn/chunks/ParagraphEditor-DU3oUKA7.js.map +1 -0
  32. package/dist/cdn/chunks/{RichTextEditorContent-DWUzizsC.js → RichTextEditorContent-BrsW1p9s.js} +4 -4
  33. package/dist/cdn/chunks/{RichTextEditorContent-DWUzizsC.js.map → RichTextEditorContent-BrsW1p9s.js.map} +1 -1
  34. package/dist/cdn/chunks/{SaveModuleDialog-DVna2xUl.js → SaveModuleDialog-CjqKkTEc.js} +24 -24
  35. package/dist/cdn/chunks/SaveModuleDialog-CjqKkTEc.js.map +1 -0
  36. package/dist/cdn/chunks/SnapshotHistory-KME4xmn_.js +2 -0
  37. package/dist/cdn/chunks/TemplateScoringPanel-DgB3xDN6.js +2 -0
  38. package/dist/cdn/chunks/TestEmailModal-DdpvRbYf.js +2 -0
  39. package/dist/cdn/chunks/{TitleEditor-DDf_OcHS.js → TitleEditor-C8FYbadT.js} +9 -9
  40. package/dist/cdn/chunks/{TitleEditor-DDf_OcHS.js.map → TitleEditor-C8FYbadT.js.map} +1 -1
  41. package/dist/cdn/chunks/{blockTypeIcons-BnobReQm.js → blockTypeIcons-5QwYklNq.js} +3 -3
  42. package/dist/cdn/chunks/{blockTypeIcons-BnobReQm.js.map → blockTypeIcons-5QwYklNq.js.map} +1 -1
  43. package/dist/cdn/chunks/{dist-CJcMnY7o.js → dist-BF5c3Dr-.js} +1 -1
  44. package/dist/cdn/chunks/dist-BGzvIxcJ.js +2 -0
  45. package/dist/cdn/chunks/dist-CFemF8rI.js +2 -0
  46. package/dist/cdn/chunks/dist-Co6uFhFK.js +2 -0
  47. package/dist/cdn/chunks/{dist-BkETaOfw.js → dist-DCikBY9K.js} +1 -1
  48. package/dist/cdn/chunks/dist-DUILafAC.js +2 -0
  49. package/dist/cdn/chunks/dist-DghiKH0A.js +2 -0
  50. package/dist/cdn/chunks/dist-Dw8ckvfK.js +2 -0
  51. package/dist/cdn/chunks/dist-H07p0KAw.js +2 -0
  52. package/dist/cdn/chunks/{dist-B878xb_62.js → dist-KYv9v_1z2.js} +11 -11
  53. package/dist/cdn/chunks/{dist-B878xb_62.js.map → dist-KYv9v_1z2.js.map} +1 -1
  54. package/dist/cdn/chunks/{dist-DLWHlekl.js → dist-MjnKIc0W.js} +1 -1
  55. package/dist/cdn/chunks/{dist-CllLxIMQ.js → dist-odp0vGRv.js} +1 -1
  56. package/dist/cdn/chunks/{extensions-B_kcV0tK.js → extensions-Bj7USRLr.js} +20 -20
  57. package/dist/cdn/chunks/{extensions-B_kcV0tK.js.map → extensions-Bj7USRLr.js.map} +1 -1
  58. package/dist/cdn/chunks/{features-ofOGnSC0.js → features-Ds0XUfte.js} +1235 -1198
  59. package/dist/cdn/chunks/features-Ds0XUfte.js.map +1 -0
  60. package/dist/cdn/chunks/{icons-bIb7PBOE.js → icons-fWsuSvgd.js} +2 -2
  61. package/dist/cdn/chunks/{icons-bIb7PBOE.js.map → icons-fWsuSvgd.js.map} +1 -1
  62. package/dist/cdn/chunks/{media-library-BIYzV2Y2.js → media-library-BGQm_OyC.js} +528 -528
  63. package/dist/cdn/chunks/{media-library-BIYzV2Y2.js.map → media-library-BGQm_OyC.js.map} +1 -1
  64. package/dist/cdn/chunks/{src-BuW9oYtm.js → src-3i8rPuqd.js} +4 -4
  65. package/dist/cdn/chunks/{src-BuW9oYtm.js.map → src-3i8rPuqd.js.map} +1 -1
  66. package/dist/cdn/chunks/{styleConstants-1KwsBMxJ.js → styleConstants-DFe3I4Op.js} +6 -6
  67. package/dist/cdn/chunks/{styleConstants-1KwsBMxJ.js.map → styleConstants-DFe3I4Op.js.map} +1 -1
  68. package/dist/cdn/chunks/{styles-DQFExz-T.js → styles-Dgijy53u.js} +1224 -1096
  69. package/dist/cdn/chunks/styles-Dgijy53u.js.map +1 -0
  70. package/dist/cdn/chunks/{tiptap-DplY-S-k.js → tiptap-BhxaWR8R.js} +2 -2
  71. package/dist/cdn/chunks/{tiptap-DplY-S-k.js.map → tiptap-BhxaWR8R.js.map} +1 -1
  72. package/dist/cdn/editor.css +1 -1
  73. package/dist/cdn/editor.js +110 -139
  74. package/dist/cdn/editor.js.map +1 -1
  75. package/dist/{dist-BkIys9zn.js → dist-Ci5lFuUy.js} +1 -1
  76. package/dist/{extensions-DEjfEFhD.js → extensions-DWx_jj8v.js} +1 -1
  77. package/dist/{styleConstants-D4SOZGBV.js → styleConstants-Cxw88naD.js} +5 -5
  78. package/dist/{styles-CgLaxDfu.js → styles-fdXNRqI3.js} +1341 -1213
  79. package/dist/templatical-editor.css +1 -1
  80. package/dist/templatical-editor.js +99 -129
  81. package/dist/templatical-editor.umd.cjs +55 -64
  82. package/dist/{useEditorCore-CjwRMl7K.js → useEditorCore-DUGD6pq_.js} +1054 -1033
  83. package/package.json +4 -2
  84. package/dist/CloudEditor-DFyuRxUV.js +0 -926
  85. package/dist/ParagraphEditor-CcMPnbDr.js +0 -652
  86. package/dist/TemplateScoringPanel-D58A23Vq.js +0 -249
  87. package/dist/cdn/chunks/AiChatSidebar-CmPTbTFG.js +0 -2
  88. package/dist/cdn/chunks/AiFeatureMenu-lxVm1RjH.js.map +0 -1
  89. package/dist/cdn/chunks/CloudEditor-Bmp5IlWi.js +0 -900
  90. package/dist/cdn/chunks/CloudEditor-Bmp5IlWi.js.map +0 -1
  91. package/dist/cdn/chunks/CommentsSidebar-BOelj4Ca.js +0 -2
  92. package/dist/cdn/chunks/DesignReferenceSidebar-Bf6rg0A7.js +0 -2
  93. package/dist/cdn/chunks/ModuleBrowserModal-CxDXzkKS.js.map +0 -1
  94. package/dist/cdn/chunks/ParagraphEditor-DHdu6lb3.js +0 -503
  95. package/dist/cdn/chunks/ParagraphEditor-DHdu6lb3.js.map +0 -1
  96. package/dist/cdn/chunks/SaveModuleDialog-DVna2xUl.js.map +0 -1
  97. package/dist/cdn/chunks/SnapshotHistory-BFF2SsTN.js +0 -2
  98. package/dist/cdn/chunks/TemplateScoringPanel-gi8wc_m7.js +0 -2
  99. package/dist/cdn/chunks/TestEmailModal-Qtd6aC-6.js +0 -2
  100. package/dist/cdn/chunks/dist-B6AUkMyh.js +0 -2
  101. package/dist/cdn/chunks/dist-Bf1Op9A1.js +0 -2
  102. package/dist/cdn/chunks/dist-CWsl6S1K.js +0 -2
  103. package/dist/cdn/chunks/dist-Cs0wFwdw.js +0 -2
  104. package/dist/cdn/chunks/dist-DS3_HVpX.js +0 -2
  105. package/dist/cdn/chunks/dist-DTXopj1a.js +0 -2
  106. package/dist/cdn/chunks/dist-DnwLoNLm.js +0 -2
  107. package/dist/cdn/chunks/features-ofOGnSC0.js.map +0 -1
  108. package/dist/cdn/chunks/styles-DQFExz-T.js.map +0 -1
@@ -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 ee, j as te, lt as d, m as f, n as ne, r as p, st as m, w as h, y as g } from "./chunks/draggable-BQNU47zu.js";
2
- import { $ as _, $t as re, Bt as ie, Ft as ae, Gt as oe, Ht as se, In as ce, It as v, J as y, Jt as b, Kt as x, Lt as S, Mt as C, Pt as w, Qt as T, Ut as E, Vt as D, Wt as O, Zt as k, k as A, qt as j, un as M, zt as N } from "./chunks/features-ofOGnSC0.js";
3
- import { S as P } from "./chunks/icons-bIb7PBOE.js";
4
- import { a as F, i as I, n as L, o as le, r as R, t as z } from "./chunks/styles-DQFExz-T.js";
5
- import { t as B } from "./chunks/_rolldown_dynamic_import_helper-DMEI4TQ3.js";
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-BQNU47zu.js";
2
+ import { $ as b, J as x, Mn as S, k as C, on as w } from "./chunks/features-Ds0XUfte.js";
3
+ import { S as ee } from "./chunks/icons-fWsuSvgd.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-Dgijy53u.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 V = ["data-tpl-theme"], H = {
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
- }, U = { class: "tpl:flex tpl:items-center tpl:gap-2.5" }, W = {
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
- }, ue = { class: "tpl:flex tpl:items-center tpl:justify-center tpl:gap-10" }, de = { class: "tpl:sticky tpl:top-0 tpl:z-40 tpl:h-0" }, fe = { class: "tpl:flex tpl:justify-center tpl:p-8" }, pe = {
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 p = e, h = M({
39
- content: p.config.content,
40
- templateDefaults: p.config.templateDefaults
41
- }), _ = A({
42
- editor: h,
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: p.config.uiTheme,
45
- theme: p.config.theme,
46
- blockDefaults: p.config.blockDefaults,
47
- customBlocks: p.config.customBlocks,
48
- mergeTags: p.config.mergeTags,
49
- displayConditions: p.config.displayConditions,
50
- onRequestMedia: p.config.onRequestMedia,
51
- onSave: p.config.onSave ? () => p.config.onSave(JSON.parse(JSON.stringify(h.state.content))) : void 0
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: p.translations,
54
- fontsManager: p.fontsManager,
55
- autoSaveOptions: p.config.onChange ? { onChange: () => p.config.onChange(JSON.parse(JSON.stringify(h.state.content))) } : null
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 te(async () => {
58
- await p.fontsManager.loadCustomFonts();
44
+ return f(async () => {
45
+ await g.fontsManager.loadCustomFonts();
59
46
  }), n(() => {
60
- p.fontsManager.cleanupFontLinks(), _.destroy();
47
+ g.fontsManager.cleanupFontLinks(), b.destroy();
61
48
  }), i({
62
- getContent: () => h.content.value,
63
- setContent: (e) => h.setContent(e),
64
- setTheme: (e) => h.setUiTheme(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: m(["tpl tpl:relative tpl:h-full tpl:overflow-hidden", { "tpl:dark": s(h).state.darkMode }]),
67
- "data-tpl-theme": s(_).resolvedTheme.value,
68
- style: u(s(_).themeStyles.value)
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
- f("header", H, [
71
- f("div", U, [n[5] ||= f("img", {
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), f("span", W, d(s(_).t.header.title), 1)]),
77
- f("div", ue, [
78
- c(R, {
79
- viewport: s(h).state.viewport,
80
- onChange: s(h).setViewport
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(z, {
83
- "dark-mode": s(h).state.darkMode,
84
- onChange: s(h).setDarkMode
69
+ c(D, {
70
+ "dark-mode": s(v).state.darkMode,
71
+ onChange: s(v).setDarkMode
85
72
  }, null, 8, ["dark-mode", "onChange"]),
86
- c(L, {
87
- "preview-mode": s(h).state.previewMode,
88
- onChange: s(h).setPreviewMode
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] ||= f("div", { class: "tpl:flex tpl:min-w-[200px] tpl:items-center tpl:justify-end tpl:gap-3" }, null, -1)
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(F, null, null, 512), [[l, !s(h).state.previewMode]]),
94
- f("div", {
95
- class: m(["tpl-body tpl:absolute tpl:bottom-0 tpl:overflow-auto tpl:bg-[var(--tpl-canvas-bg)]", [s(h).state.previewMode ? "tpl:left-0 tpl:right-0" : "tpl:left-12 tpl:right-[320px]", "tpl:top-14"]]),
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
- }, [f("div", de, [c(ne, { name: "tpl-restore-btn" }, {
98
- default: t(() => [s(_).conditionPreview.hasHiddenBlocks.value ? (r(), o("button", {
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(_).conditionPreview.reset()
103
- }, [c(s(P), {
89
+ onClick: n[0] ||= (e) => s(b).conditionPreview.reset()
90
+ }, [c(s(ee), {
104
91
  size: 13,
105
92
  "stroke-width": 2
106
- }), g(" " + d(s(_).t.blockSettings.restoreHiddenBlocks), 1)])) : ee("", !0)]),
93
+ }), y(" " + p(s(b).t.blockSettings.restoreHiddenBlocks), 1)])) : d("", !0)]),
107
94
  _: 1
108
- })]), f("div", fe, [c(le, {
109
- viewport: s(h).state.viewport,
110
- content: s(h).content.value,
111
- "selected-block-id": s(h).state.selectedBlockId,
112
- "dark-mode": s(h).state.darkMode,
113
- "preview-mode": s(h).state.previewMode,
114
- onSelectBlock: s(h).selectBlock
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
- f("footer", { class: m(["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)]", [s(h).state.previewMode ? "tpl:left-0 tpl:right-0" : "tpl:left-12 tpl:right-[320px]"]]) }, [f("div", pe, [
124
- f("span", null, d(s(_).t.footer.poweredBy), 1),
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(_).t.landmarks.reorderAnnouncements
146
- }, d(s(_).keyboardReorder.announcement.value), 9, he),
147
- a(c(I, {
148
- "selected-block": s(h).selectedBlock.value,
149
- settings: s(h).content.value.settings,
150
- onUpdateBlock: n[1] ||= (e) => s(h).updateBlock(s(h).state.selectedBlockId, e),
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(h).state.selectedBlockId && s(_).blockActions.deleteBlock(s(h).state.selectedBlockId);
123
+ s(v).state.selectedBlockId && s(b).blockActions.deleteBlock(s(v).state.selectedBlockId);
153
124
  },
154
125
  onDuplicateBlock: n[3] ||= () => {
155
- s(h).selectedBlock.value && s(_).blockActions.duplicateBlock(s(h).selectedBlock.value);
126
+ s(v).selectedBlock.value && s(b).blockActions.duplicateBlock(s(v).selectedBlock.value);
156
127
  },
157
- onUpdateSettings: n[4] ||= (e) => s(h).updateSettings(e)
158
- }, null, 8, ["selected-block", "settings"]), [[l, !s(h).state.previewMode]])
159
- ], 14, V));
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-7e34c788"]]), _e = ["en", "de"];
162
- function ve(e) {
132
+ }), [["__scopeId", "data-v-8c8f0453"]]), H = ["en", "de"];
133
+ function U(e) {
163
134
  return e.split("-")[0].toLowerCase();
164
135
  }
165
- async function G(e) {
166
- let t = ve(e), n = _e.includes(t) ? t : "en";
167
- return (await B(/* @__PURE__ */ Object.assign({
136
+ async function W(e) {
137
+ let t = U(e), n = H.includes(t) ? t : "en";
138
+ return (await M(/* @__PURE__ */ Object.assign({
168
139
  "./locales/de.ts": () => import("./chunks/de-BB3dgVOc.js"),
169
140
  "./locales/en.ts": () => import("./chunks/en-DeDcpnoS.js")
170
141
  }), `./locales/${n}.ts`, 3)).default;
171
142
  }
172
143
  //#endregion
173
144
  //#region src/index.ts
174
- var K = null, q = e(null);
175
- async function J(e) {
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
- K && Z();
179
- let n = await G(e.locale ?? "en"), r = y(e.fonts);
180
- K = p({ setup() {
181
- return () => h(ge, {
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: q
156
+ ref: K
186
157
  });
187
- } }), K.mount(t);
158
+ } }), G.mount(t);
188
159
  let i = {
189
160
  getContent() {
190
- return JSON.parse(JSON.stringify(q.value ? q.value.getContent() : e.content));
161
+ return JSON.parse(JSON.stringify(K.value ? K.value.getContent() : e.content));
191
162
  },
192
163
  setContent(t) {
193
- q.value && q.value.setContent(t), e.content = t;
164
+ K.value && K.value.setContent(t), e.content = t;
194
165
  },
195
166
  setTheme(e) {
196
- q.value && q.value.setTheme(e);
167
+ K.value && K.value.setTheme(e);
197
168
  },
198
169
  unmount: Z
199
170
  };
200
171
  return $(i), i;
201
172
  }
202
- var Y = null, X = e(null);
203
- async function ye(e) {
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
- Y && Q();
207
- let { default: n } = await import("./chunks/CloudEditor-Bmp5IlWi.js"), r = await G(e.locale ?? "en"), i = y(e.fonts);
177
+ J && Q();
178
+ let { default: n } = await import("./chunks/CloudEditor-DeTolKnf.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
- }, ce);
212
- Y = p({ setup() {
213
- return () => h(n, {
182
+ }, S);
183
+ J = g({ setup() {
184
+ return () => v(n, {
214
185
  config: e,
215
186
  translations: r,
216
187
  fontsManager: i,
217
- ref: X,
188
+ ref: Y,
218
189
  onReady: () => {
219
190
  clearTimeout(s), a();
220
191
  }
221
192
  });
222
- } }), Y.mount(t);
193
+ } }), J.mount(t);
223
194
  });
224
195
  let a = {
225
196
  getContent() {
226
- return JSON.parse(JSON.stringify(X.value ? X.value.getContent() : e.content));
197
+ return JSON.parse(JSON.stringify(Y.value ? Y.value.getContent() : e.content));
227
198
  },
228
199
  setContent(e) {
229
- X.value && X.value.setContent(e);
200
+ Y.value && Y.value.setContent(e);
230
201
  },
231
202
  setTheme(e) {
232
- X.value && X.value.setTheme(e);
203
+ Y.value && Y.value.setTheme(e);
233
204
  },
234
205
  unmount: Q,
235
206
  create(e) {
236
- return X.value ? X.value.create(e) : Promise.reject(/* @__PURE__ */ Error("[Templatical] Cloud editor not ready"));
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 X.value ? X.value.load(e) : Promise.reject(/* @__PURE__ */ Error("[Templatical] Cloud editor not ready"));
210
+ return Y.value ? Y.value.load(e) : Promise.reject(/* @__PURE__ */ Error("[Templatical] Cloud editor not ready"));
240
211
  },
241
212
  save() {
242
- return X.value ? X.value.save() : Promise.reject(/* @__PURE__ */ Error("[Templatical] Cloud editor not ready"));
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
- K && (K.unmount(), K = null, q.value = null);
219
+ G && (G.unmount(), G = null, K.value = null);
249
220
  }
250
221
  function Q() {
251
- Y && (Y.unmount(), Y = null, X.value = null);
222
+ J && (J.unmount(), J = null, Y.value = null);
252
223
  }
253
224
  function $(e) {
254
- import("./chunks/dist-B878xb_62.js").then((t) => {
225
+ import("./chunks/dist-KYv9v_1z2.js").then((t) => {
255
226
  e.toMjml = () => t.renderToMjml(e.getContent());
256
227
  }).catch(() => {});
257
228
  }
258
229
  //#endregion
259
- export { C as ALLOW_CUSTOM_CONDITIONS_KEY, w as BLOCK_ACTIONS_KEY, ae as BLOCK_DEFAULTS_KEY, v as BLOCK_REGISTRY_KEY, S as CAPABILITIES_KEY, N as CONDITION_PREVIEW_KEY, ie as CUSTOM_BLOCK_DEFINITIONS_KEY, D as DISPLAY_CONDITIONS_KEY, se as EDITOR_KEY, E as FONTS_MANAGER_KEY, O as HISTORY_KEY, oe as MERGE_TAGS_KEY, x as MERGE_TAG_SYNTAX_KEY, j as ON_REQUEST_MEDIA_KEY, b as ON_REQUEST_MERGE_TAG_KEY, k as THEME_STYLES_KEY, T as TRANSLATIONS_KEY, re as UI_THEME_KEY, J as init, ye as initCloud, Z as unmount, y as useFonts };
230
+ export { q as init, X as initCloud, Z as unmount, x as useFonts };
260
231
 
261
232
  //# sourceMappingURL=editor.js.map
@@ -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,4 +1,4 @@
1
- import { I as e } from "./useEditorCore-CjwRMl7K.js";
1
+ import { L as e } from "./useEditorCore-DUGD6pq_.js";
2
2
  import { $ as t, $t as n, A as r, At as i, B as a, Bt as o, C as ee, Ct as te, D as ne, Dt as re, E as ie, Et as ae, F as oe, Ft as se, G as ce, Gt as le, H as ue, Ht as de, I as fe, It as pe, J as me, Jt as he, K as ge, Kt as _e, L as ve, Lt as ye, M as s, Mt as c, N as l, Nt as u, O as d, Ot as f, P as p, Pt as m, Q as h, Qt as g, R as _, Rt as v, S as y, St as b, T as x, Tt as S, U as C, Ut as w, V as T, Vt as E, W as D, Wt as O, X as k, Xt as A, Y as j, Yt as M, Z as N, Zt as P, _ as be, _t as F, a as xe, an as I, at as Se, b as Ce, bt as we, c as Te, cn as Ee, ct as De, d as Oe, dn as ke, dt as Ae, en as je, et as Me, f as L, fn as Ne, ft as Pe, g as Fe, gt as Ie, h as Le, ht as Re, i as ze, in as Be, it as Ve, j as He, jt as Ue, k as We, kt as Ge, l as R, ln as Ke, lt as qe, m as Je, mn as Ye, mt as Xe, n as z, nn as Ze, nt as Qe, o as $e, on as et, ot as tt, p as nt, pn as rt, pt as it, q as at, qt as ot, r as st, rn as ct, rt as lt, s as ut, sn as dt, st as ft, t as pt, tn as mt, tt as ht, u as gt, un as _t, ut as vt, v as yt, vt as bt, w as xt, wt as St, x as Ct, xt as wt, y as B, yt as Tt, z as Et, zt as Dt } from "./dist-C_ymrGFi.js";
3
3
  import { customRef as Ot, defineComponent as V, getCurrentInstance as kt, h as H, markRaw as U, nextTick as At, onBeforeUnmount as W, onMounted as jt, provide as G, reactive as Mt, ref as K, render as q, shallowRef as Nt, toRaw as Pt, unref as Ft, watchEffect as It } from "vue";
4
4
  //#region ../../node_modules/.bun/@tiptap+vue-3@3.22.1+bbf5de022be137e7/node_modules/@tiptap/vue-3/dist/index.js
@@ -1,7 +1,7 @@
1
1
  import { t as e } from "./useI18n-D6m7ZUgY.js";
2
2
  import { t } from "./useMergeTag-BZ3X0bNr.js";
3
3
  import { Wt as n, i as r, o as i, p as a, u as o } from "./dist-C_ymrGFi.js";
4
- import { n as s, t as c } from "./dist-BkIys9zn.js";
4
+ import { n as s, t as c } from "./dist-Ci5lFuUy.js";
5
5
  import { computed as l, createBlock as u, createCommentVNode as d, createElementBlock as f, createElementVNode as p, defineComponent as m, nextTick as h, normalizeClass as g, normalizeStyle as _, openBlock as v, ref as y, toDisplayString as b, unref as x, vModelText as S, withCtx as C, withDirectives as w, withKeys as T, withModifiers as E } from "vue";
6
6
  import { SYNTAX_PRESETS as D, getLogicMergeTagKeyword as O, getMergeTagLabel as k, isLogicMergeTagValue as A } from "@templatical/types";
7
7
  //#region src/extensions/FontSize.ts
@@ -38,7 +38,7 @@ var t = e("text-align-center", [
38
38
  d: "M17 19H3",
39
39
  key: "z6ezky"
40
40
  }]
41
- ]), i = "tpl:block tpl:mb-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]", a = "tpl:w-full tpl:h-10 tpl:px-3.5 tpl:py-1.5 tpl:text-sm tpl:border tpl:rounded-[var(--tpl-radius-sm)] tpl:shadow-xs tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)] tpl:border-[var(--tpl-border)] tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] tpl:outline-none focus:tpl:border-[var(--tpl-primary)] focus:tpl:shadow-[var(--tpl-ring)] placeholder:tpl:text-[var(--tpl-text-dim)]", o = "tpl:w-full tpl:h-10 tpl:px-3.5 tpl:py-1.5 tpl:text-sm tpl:border tpl:rounded-l-[var(--tpl-radius-sm)] tpl:rounded-r-none tpl:border-r-0 tpl:shadow-xs tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)] tpl:border-[var(--tpl-border)] tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] tpl:outline-none focus:tpl:border-[var(--tpl-primary)] focus:tpl:shadow-[var(--tpl-ring)] placeholder:tpl:text-[var(--tpl-text-dim)]", s = "tpl:flex tpl:items-center tpl:px-2.5 tpl:text-xs tpl:border tpl:border-l-0 tpl:text-[var(--tpl-text-dim)] tpl:bg-[var(--tpl-bg-hover)] tpl:border-[var(--tpl-border)] tpl:rounded-r-[var(--tpl-radius-sm)]", c = "tpl:flex-1 tpl:h-10 tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-mono tpl:border tpl:rounded-[var(--tpl-radius-sm)] tpl:shadow-xs tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)] tpl:border-[var(--tpl-border)] tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] tpl:outline-none focus:tpl:border-[var(--tpl-primary)] focus:tpl:shadow-[var(--tpl-ring)]", l = "tpl:rounded-[var(--tpl-radius)] tpl:bg-[var(--tpl-bg-elevated)] tpl:p-4 tpl:border tpl:border-[var(--tpl-border)] tpl:transition-colors tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] hover:tpl:bg-[var(--tpl-bg-hover)]", u = "tpl-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-[var(--tpl-radius-sm)] tpl:border tpl:px-3.5 tpl:py-2 tpl:text-sm tpl:font-medium tpl:whitespace-nowrap tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] hover:tpl:bg-[var(--tpl-primary)] hover:tpl:text-[var(--tpl-bg)] tpl:disabled:cursor-not-allowed tpl:disabled:opacity-50", d = [
41
+ ]), i = "tpl:block tpl:mb-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]", a = "tpl:w-full tpl:h-10 tpl:px-3.5 tpl:py-1.5 tpl:text-sm tpl:border tpl:rounded-[var(--tpl-radius-sm)] tpl:shadow-xs tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)] tpl:border-[var(--tpl-border)] tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] tpl:outline-none focus:tpl:border-[var(--tpl-primary)] focus:tpl:shadow-[var(--tpl-ring)] placeholder:tpl:text-[var(--tpl-text-dim)]", o = "tpl:w-full tpl:h-10 tpl:px-3.5 tpl:py-1.5 tpl:text-sm tpl:border tpl:rounded-l-[var(--tpl-radius-sm)] tpl:rounded-r-none tpl:border-r-0 tpl:shadow-xs tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)] tpl:border-[var(--tpl-border)] tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] tpl:outline-none focus:tpl:border-[var(--tpl-primary)] focus:tpl:shadow-[var(--tpl-ring)] placeholder:tpl:text-[var(--tpl-text-dim)]", s = "tpl:flex tpl:items-center tpl:px-2.5 tpl:text-xs tpl:border tpl:border-l-0 tpl:text-[var(--tpl-text-dim)] tpl:bg-[var(--tpl-bg-hover)] tpl:border-[var(--tpl-border)] tpl:rounded-r-[var(--tpl-radius-sm)]", c = "tpl:flex-1 tpl:h-10 tpl:px-3.5 tpl:py-1.5 tpl:text-xs tpl:font-mono tpl:border tpl:rounded-[var(--tpl-radius-sm)] tpl:shadow-xs tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)] tpl:border-[var(--tpl-border)] tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] tpl:outline-none focus:tpl:border-[var(--tpl-primary)] focus:tpl:shadow-[var(--tpl-ring)]", l = "tpl:rounded-[var(--tpl-radius)] tpl:bg-[var(--tpl-bg-elevated)] tpl:p-4 tpl:border tpl:border-[var(--tpl-border)] tpl:transition-colors tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] hover:tpl:bg-[var(--tpl-bg-hover)]", u = "tpl:flex tpl:size-8 tpl:shrink-0 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text-muted)] tpl:transition-all tpl:duration-150 tpl:hover:border-[var(--tpl-danger)] tpl:hover:bg-[var(--tpl-danger-light)] tpl:hover:text-[var(--tpl-danger)]", d = "tpl:flex tpl:w-full tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:border-dashed tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text-muted)] tpl:transition-all tpl:duration-150 tpl:hover:border-[var(--tpl-primary)] tpl:hover:text-[var(--tpl-primary)]", f = "tpl:w-full tpl:resize-y tpl:rounded-md tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-2.5 tpl:py-2 tpl:font-mono tpl:text-xs tpl:text-[var(--tpl-text)] tpl:outline-none tpl:transition-all tpl:duration-150 tpl:placeholder:text-[var(--tpl-text-dim)] tpl:focus:border-[var(--tpl-primary)] tpl:focus:shadow-[0_0_0_3px_var(--tpl-primary-light)]", p = "tpl-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-[var(--tpl-radius-sm)] tpl:border tpl:px-3.5 tpl:py-2 tpl:text-sm tpl:font-medium tpl:whitespace-nowrap tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)] hover:tpl:bg-[var(--tpl-primary)] hover:tpl:text-[var(--tpl-bg)] tpl:disabled:cursor-not-allowed tpl:disabled:opacity-50", m = [
42
42
  "10px",
43
43
  "12px",
44
44
  "14px",
@@ -51,7 +51,7 @@ var t = e("text-align-center", [
51
51
  "36px",
52
52
  "48px",
53
53
  "64px"
54
- ], f = [
54
+ ], h = [
55
55
  "1",
56
56
  "1.2",
57
57
  "1.4",
@@ -60,7 +60,7 @@ var t = e("text-align-center", [
60
60
  "1.8",
61
61
  "2",
62
62
  "2.5"
63
- ], p = [
63
+ ], g = [
64
64
  {
65
65
  label: "Normal",
66
66
  value: "normal"
@@ -89,6 +89,6 @@ var t = e("text-align-center", [
89
89
  label: "3px",
90
90
  value: "3px"
91
91
  }
92
- ], m = "#000000", h = "#ffffff", g = "#ffff00", _ = "#f2f2f2";
92
+ ], _ = "#000000", v = "#ffffff", y = "#ffff00", b = "#f2f2f2";
93
93
  //#endregion
94
- export { t as _, d as a, l as c, a as d, o as f, n as g, r as h, m as i, c as l, i as m, g as n, p as o, s as p, _ as r, f as s, h as t, u };
94
+ export { u as _, m as a, t as b, d as c, p as d, a as f, f as g, i as h, _ as i, l, s as m, y as n, g as o, o as p, b as r, h as s, v as t, c as u, r as v, n as y };