@boxcc/maildeno-editor 0.0.0-stage → 0.4.14

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 (57) hide show
  1. package/CHANGELOG.md +479 -0
  2. package/README.md +442 -2
  3. package/dist/DatePicker-AdfGW0Tw.js +5347 -0
  4. package/dist/DatePicker-aNFlsoOb.js +5347 -0
  5. package/dist/Dialog-By0JLN8s.js +6294 -0
  6. package/dist/HealthIndicator-BLID6Ty0.js +1216 -0
  7. package/dist/HealthIndicator-DfzqzPNw.js +1217 -0
  8. package/dist/PopperContent-N2nAEFeH.js +2538 -0
  9. package/dist/PopperContent-eLmz1Gjd.js +2578 -0
  10. package/dist/PreviewCanvas-D3SpILsV.js +534 -0
  11. package/dist/PreviewCanvas-PtW1UL1J.js +534 -0
  12. package/dist/RichTextEditor-D6DQqbJg.js +12218 -0
  13. package/dist/RichTextEditor-DDEfKPZm.js +12217 -0
  14. package/dist/RowPreviewChildren-BGnilx-K.js +4 -0
  15. package/dist/RowPreviewChildren-CalQWx1C.js +4 -0
  16. package/dist/RowPreviewLegacyComponent-Df_1HTly.js +403 -0
  17. package/dist/RowPreviewLegacyComponent-NECG3wpn.js +403 -0
  18. package/dist/RowPreviewRow-C2XAe5Xs.js +81 -0
  19. package/dist/RowPreviewRow-DG4AdMrv.js +81 -0
  20. package/dist/SavedRowsPanel-2JBfYdxN.js +492 -0
  21. package/dist/SavedRowsPanel-B6_VHQZm.js +493 -0
  22. package/dist/_plugin-vue_export-helper-Dj7HTbfw.js +8 -0
  23. package/dist/adapters/errors.d.ts +59 -0
  24. package/dist/adapters/localStorageAdapter.d.ts +6 -0
  25. package/dist/adapters/types.d.ts +151 -0
  26. package/dist/babel-DV7WPQI0.js +10043 -0
  27. package/dist/blocks/registry.d.ts +23 -0
  28. package/dist/blocks/types.d.ts +73 -0
  29. package/dist/borderRadius-CkSa1lQ9.js +75 -0
  30. package/dist/components/features/emailBuilder/EmailEditor.vue.d.ts +183 -0
  31. package/dist/composables/emailBuilder/export/logic/espLogicWrapper.d.ts +76 -0
  32. package/dist/composables/emailBuilder/persistence/useEmailBuilderPersistence.d.ts +38 -0
  33. package/dist/composables/emailBuilder/transform/pipeline/optimize.d.ts +100 -0
  34. package/dist/composables/system/useColorScheme.d.ts +16 -0
  35. package/dist/element-DQw3HLit.js +21540 -0
  36. package/dist/element.d.ts +6 -0
  37. package/dist/element.js +5 -0
  38. package/dist/esp/registry.d.ts +33 -0
  39. package/dist/estree-DY9POgc0.js +8195 -0
  40. package/dist/html-wb0gSX1o.js +7273 -0
  41. package/dist/index.d.ts +17 -0
  42. package/dist/index.js +15032 -0
  43. package/dist/init.d.ts +180 -0
  44. package/dist/init.js +143 -0
  45. package/dist/maildeno-editor.css +2 -0
  46. package/dist/merge-tags/registry.d.ts +33 -0
  47. package/dist/mergeTagDefinitions-Cler19nv.js +27 -0
  48. package/dist/standalone-DHvJ30Td.js +3554 -0
  49. package/dist/theme.d.ts +206 -0
  50. package/dist/types/assistant.d.ts +56 -0
  51. package/dist/useEmailBuilder-2yCUzRx2.js +4934 -0
  52. package/dist/useEmailBuilder-D3uV7dwL.js +4934 -0
  53. package/dist/useToast-D1GgDMqQ.js +194 -0
  54. package/dist/utils/border.d.ts +15 -0
  55. package/dist/utils/borderRadius.d.ts +10 -0
  56. package/dist/vue.runtime.esm-bundler-D2AjRP90.js +6117 -0
  57. package/package.json +100 -4
@@ -0,0 +1,493 @@
1
+ import { W as ge, n as xe, v as be, z as he } from "./useEmailBuilder-D3uV7dwL.js";
2
+ import { o as X, r as Z } from "./borderRadius-CkSa1lQ9.js";
3
+ import { d as we, i as ee, l as ye, p as ke, r as _e, s as Ce } from "./useToast-D1GgDMqQ.js";
4
+ import { t as Re } from "./_plugin-vue_export-helper-Dj7HTbfw.js";
5
+ import { Fragment as $, Transition as $e, TransitionGroup as Se, computed as R, createBlock as H, createCommentVNode as W, createElementBlock as d, createElementVNode as t, createTextVNode as V, createVNode as G, defineAsyncComponent as te, defineComponent as U, nextTick as Pe, normalizeClass as re, normalizeStyle as I, onBeforeUnmount as Ie, onMounted as se, openBlock as a, ref as h, renderList as j, toDisplayString as z, unref as T, vModelText as Te, watch as O, withCtx as oe, withDirectives as De, withKeys as ne, withModifiers as M } from "vue";
6
+ var Fe = {
7
+ key: 1,
8
+ style: {
9
+ height: "4px",
10
+ width: "100%"
11
+ }
12
+ }, ze = /* @__PURE__ */ U({
13
+ __name: "RowPreviewChildren",
14
+ props: {
15
+ children: {},
16
+ scale: {},
17
+ depth: {}
18
+ },
19
+ setup(m) {
20
+ const w = te(() => import("./RowPreviewRow-C2XAe5Xs.js")), k = te(() => import("./RowPreviewLegacyComponent-Df_1HTly.js"));
21
+ function f(v) {
22
+ const g = v?.backgroundGradient;
23
+ if (g?.useGradient === !0 && Array.isArray(g?.gradient?.colors) && g.gradient.colors.length >= 2) {
24
+ const { type: c, direction: _, colors: D } = g.gradient, S = D.map((r) => `${r.color} ${r.position}%`).join(", ");
25
+ return c === "radial" ? `radial-gradient(circle at center, ${S})` : `linear-gradient(${_}, ${S})`;
26
+ }
27
+ return v?.backgroundColor ?? v?.props?.backgroundColor ?? "transparent";
28
+ }
29
+ function p(v) {
30
+ return v.height ?? v.props?.height ?? 8;
31
+ }
32
+ return (v, g) => (a(!0), d($, null, j(m.children, (c, _) => (a(), d($, { key: c.id }, [(m.depth ?? 0) < 5 ? (a(), d($, { key: 0 }, [c.type === "row" ? (a(), H(T(w), {
33
+ key: 0,
34
+ row: c,
35
+ scale: m.scale,
36
+ depth: (m.depth ?? 0) + 1
37
+ }, null, 8, [
38
+ "row",
39
+ "scale",
40
+ "depth"
41
+ ])) : c.type === "row-spacer" ? (a(), d("div", {
42
+ key: 1,
43
+ style: I({
44
+ width: "100%",
45
+ height: p(c) + "px",
46
+ background: f(c),
47
+ flexShrink: "0"
48
+ })
49
+ }, null, 4)) : c.type === "component" ? (a(), H(T(k), {
50
+ key: 2,
51
+ comp: {
52
+ ...c,
53
+ type: c.componentType ?? c.type
54
+ },
55
+ scale: m.scale
56
+ }, null, 8, ["comp", "scale"])) : (a(), H(T(k), {
57
+ key: 3,
58
+ comp: c,
59
+ scale: m.scale
60
+ }, null, 8, ["comp", "scale"]))], 64)) : (a(), d("div", Fe))], 64))), 128));
61
+ }
62
+ }), Me = ze, je = {
63
+ key: 0,
64
+ class: "w-full border border-dashed border-(--md-border) rounded",
65
+ style: { "min-height": "10px" }
66
+ }, Ee = /* @__PURE__ */ U({
67
+ __name: "RowPreview",
68
+ props: {
69
+ row: {},
70
+ scale: {}
71
+ },
72
+ setup(m) {
73
+ const w = m, { WEB_SAFE_FONTS: k, FONTS_WITH_ITALICS: f, DEFAULT_WEIGHTS: p } = be(), v = (r) => {
74
+ const i = r?.backgroundGradient;
75
+ if (i?.useGradient === !0 && Array.isArray(i?.gradient?.colors) && i.gradient.colors.length >= 2) {
76
+ const { type: l, direction: u, colors: x } = i.gradient, b = x.map((y) => `${y.color} ${y.position}%`).join(", ");
77
+ return l === "radial" ? `radial-gradient(circle at center, ${b})` : `linear-gradient(${u}, ${b})`;
78
+ }
79
+ return r?.backgroundColor || "transparent";
80
+ }, g = (r) => {
81
+ if (f.has(r)) {
82
+ const i = p.map((u) => `0,${u}`), l = p.map((u) => `1,${u}`);
83
+ return `ital,wght@${[...i, ...l].join(";")}`;
84
+ }
85
+ return `wght@${p.join(";")}`;
86
+ }, c = (r) => {
87
+ if (!r || typeof document > "u" || k.has(r)) return;
88
+ const i = `https://fonts.googleapis.com/css2?family=${r.trim().replace(/\s+/g, "+")}:${g(r)}&display=swap`;
89
+ if (!document.querySelector(`link[href="${i}"]`)) {
90
+ const l = document.createElement("link");
91
+ l.rel = "stylesheet", l.href = i, document.head.appendChild(l);
92
+ }
93
+ }, _ = () => {
94
+ function r(i) {
95
+ for (const l of i) if (l.type === "row") for (const u of l.columns ?? []) r(u.children ?? u.components ?? []);
96
+ else {
97
+ const u = l.props;
98
+ if (!u?.fontFamily) continue;
99
+ const x = l.componentType ?? l.type;
100
+ [
101
+ "heading",
102
+ "paragraph",
103
+ "list",
104
+ "menu",
105
+ "button",
106
+ "anchor"
107
+ ].includes(x) && c(u.fontFamily);
108
+ }
109
+ }
110
+ for (const i of w.row.columns ?? []) r(i.children ?? i.components ?? []);
111
+ };
112
+ O(() => w.row, () => _(), {
113
+ deep: !0,
114
+ immediate: !0
115
+ }), se(() => _());
116
+ const D = R(() => {
117
+ const r = w.row, i = {
118
+ display: "flex",
119
+ flexDirection: "row",
120
+ background: v(r),
121
+ padding: `${r.padding?.top ?? 0}px ${r.padding?.right ?? 0}px ${r.padding?.bottom ?? 0}px ${r.padding?.left ?? 0}px`,
122
+ alignItems: "stretch",
123
+ ...X(r.border),
124
+ borderRadius: Z(r.border?.radius ?? 0),
125
+ gap: `${r.gap ?? 0}px`
126
+ };
127
+ return r.backgroundImage && (i.backgroundImage = `url(${r.backgroundImage})`, i.backgroundSize = r.backgroundSize || "cover", i.backgroundPosition = r.backgroundPosition || "center center"), i;
128
+ });
129
+ function S(r, i) {
130
+ const l = {
131
+ top: "flex-start",
132
+ middle: "center",
133
+ bottom: "flex-end"
134
+ }, u = r.width ?? 100, x = i?.columns?.length || 1, b = i?.gap ?? 0, y = x > 1 ? b * (x - 1) / x : 0, F = y > 0 ? `calc(${u}% - ${y}px)` : `${u}%`, C = {
135
+ flex: `0 0 ${F}`,
136
+ width: F,
137
+ maxWidth: F,
138
+ boxSizing: "border-box",
139
+ background: v(r),
140
+ padding: `${r.padding?.top ?? 10}px ${r.padding?.right ?? 10}px ${r.padding?.bottom ?? 10}px ${r.padding?.left ?? 10}px`,
141
+ ...X(r.border),
142
+ borderRadius: Z(r.border?.radius ?? 0),
143
+ overflow: "hidden",
144
+ minWidth: "0",
145
+ display: "flex",
146
+ flexDirection: "column",
147
+ justifyContent: l[r.verticalAlign] || "flex-start"
148
+ };
149
+ return r.backgroundImage && (C.backgroundImage = `url(${r.backgroundImage})`, C.backgroundSize = r.backgroundSize || "cover", C.backgroundPosition = r.backgroundPosition || "center center", C.minHeight = "14px"), C;
150
+ }
151
+ return (r, i) => (a(), d("div", {
152
+ style: I(D.value),
153
+ class: "flex w-full pointer-events-none select-none"
154
+ }, [(a(!0), d($, null, j(m.row.columns, (l) => (a(), d("div", {
155
+ key: l.id,
156
+ style: I(S(l, m.row)),
157
+ class: "overflow-hidden shrink-0"
158
+ }, [G(Me, {
159
+ children: l.children ?? l.components ?? [],
160
+ scale: m.scale,
161
+ depth: 0
162
+ }, null, 8, ["children", "scale"]), (l.children ?? l.components ?? []).length === 0 ? (a(), d("div", je)) : W("", !0)], 4))), 128))], 4));
163
+ }
164
+ }), Ae = Ee, Be = {
165
+ key: 0,
166
+ class: "w-65 sticky top-16 h-[calc(100vh-5.25rem)] z-80"
167
+ }, Le = { class: "bg-(--md-surface) flex flex-col h-full border-r border-(--md-border)/80" }, He = { class: "flex items-center justify-between px-3.5 py-3 shrink-0" }, Ne = { class: "relative group/close" }, Ve = { class: "px-3.5 pb-2 shrink-0" }, We = {
168
+ key: 0,
169
+ class: "flex items-center gap-1"
170
+ }, Ge = ["aria-pressed", "onClick"], Oe = {
171
+ key: 1,
172
+ class: "text-[11px] font-medium text-(--md-text-subtle)"
173
+ }, Ue = { class: "flex-1 min-h-0 overflow-y-auto" }, Ke = {
174
+ key: 0,
175
+ class: "p-2 flex flex-col gap-2"
176
+ }, qe = {
177
+ key: 1,
178
+ class: "flex flex-col items-center gap-3 px-5 py-12 text-center"
179
+ }, Ye = {
180
+ key: 2,
181
+ class: "p-2 flex flex-col gap-1.5"
182
+ }, Je = ["onClick", "onDragstart"], Qe = ["onDblclick"], Xe = ["onBlur", "onKeyup"], Ze = { class: "text-[10px] text-(--md-text-subtle) shrink-0 tabular-nums" }, et = {
183
+ key: 2,
184
+ class: "relative group/del"
185
+ }, tt = ["onClick"], rt = {
186
+ key: 1,
187
+ class: "flex items-center gap-1.5 px-2 py-1.5"
188
+ }, ot = { class: "flex-1 text-[11px] font-medium text-(--md-text-muted) truncate" }, nt = { class: "text-[10px] text-(--md-text-subtle) shrink-0 tabular-nums" }, at = 600, ae = 25, st = /* @__PURE__ */ U({
189
+ __name: "SavedRowsPanel",
190
+ setup(m) {
191
+ const { isOpen: w, close: k } = ke(), f = ye(), p = Ce(), v = he(), g = _e(), c = ge(), { rows: _, saveToHistoryImmediate: D } = xe(), { startLayoutDrag: S, endLayoutDrag: r } = we(), i = {
192
+ rows: p.systemRows,
193
+ isFetching: p.isFetching,
194
+ ensureFetched: () => p.fetchRows(),
195
+ rename: () => {
196
+ throw new Error("Shared rows are read-only");
197
+ },
198
+ remove: () => {
199
+ throw new Error("Shared rows are read-only");
200
+ },
201
+ cloneForCanvas: (o) => p.cloneRowForCanvas(o)
202
+ }, l = {
203
+ rows: f.productRows,
204
+ isFetching: f.isFetching,
205
+ ensureFetched: () => f.fetchRows(),
206
+ rename: (o, e) => f.renameProductRow(o, e),
207
+ remove: (o) => f.deleteProductRow(o),
208
+ cloneForCanvas: (o) => f.cloneRowForCanvas(o)
209
+ }, u = h("user"), x = R(() => p.isSupported.value && p.systemRows.value.length > 0);
210
+ O(x, (o) => {
211
+ !o && u.value === "system" && (u.value = "user");
212
+ });
213
+ const b = R(() => u.value === "system" && x.value ? i : l), y = R(() => u.value === "system"), F = R(() => !y.value && c.value.rename !== !1), C = R(() => !y.value && c.value.delete !== !1);
214
+ O(w, async (o) => {
215
+ o && await Promise.all([f.fetchRows(), p.fetchRows()]);
216
+ }, { immediate: !0 });
217
+ const ie = R(() => b.value.rows.value), N = h(null);
218
+ function le(o, e) {
219
+ N.value = e, S(o, {
220
+ type: "product-row",
221
+ entryId: e
222
+ });
223
+ }
224
+ function de() {
225
+ N.value = null, r();
226
+ }
227
+ const K = h({}), q = h({});
228
+ function Y(o) {
229
+ const e = K.value[o];
230
+ return e && e > 0 ? e / at : 0;
231
+ }
232
+ function ue(o) {
233
+ const e = q.value[o];
234
+ return e ? Math.max(ae, Math.round(e * Y(o))) : ae;
235
+ }
236
+ const E = h(null), A = h(null);
237
+ function ce(o, e) {
238
+ !o || !E.value || (o.dataset.entryId = e, E.value.observe(o));
239
+ }
240
+ function pe(o, e) {
241
+ !o || !A.value || (o.dataset.entryId = e, A.value.observe(o));
242
+ }
243
+ se(() => {
244
+ E.value = new ResizeObserver((o) => {
245
+ for (const e of o) {
246
+ const n = e.target.dataset.entryId;
247
+ if (n) {
248
+ const s = e.contentRect.width;
249
+ s > 0 && (K.value[n] = s);
250
+ }
251
+ }
252
+ }), A.value = new ResizeObserver((o) => {
253
+ for (const e of o) {
254
+ const n = e.target.dataset.entryId;
255
+ if (n) {
256
+ const s = e.borderBoxSize?.[0]?.blockSize ?? e.contentRect.height;
257
+ s > 0 && (q.value[n] = s);
258
+ }
259
+ }
260
+ });
261
+ }), Ie(() => {
262
+ E.value?.disconnect(), A.value?.disconnect();
263
+ });
264
+ function me(o) {
265
+ if (P.value === o) return;
266
+ const e = b.value.cloneForCanvas(o);
267
+ e && (_.value.push(e), D("add-product-row"));
268
+ }
269
+ function ve(o) {
270
+ v.require({
271
+ message: "Remove this product row from the library?",
272
+ header: "Clear product",
273
+ acceptLabel: "Yes",
274
+ rejectLabel: "Cancel",
275
+ acceptClass: "!bg-[var(--md-danger)] !hover:opacity-90 !border-[var(--md-danger)] !px-6 !py-2",
276
+ rejectClass: "!bg-[var(--md-border)] !hover:bg-[var(--md-border-strong)] !text-[var(--md-text)] !border-[var(--md-border)] !px-6 !py-2",
277
+ accept: async () => {
278
+ try {
279
+ await b.value.remove(o);
280
+ } catch (e) {
281
+ console.error("[maildeno-editor] failed to delete saved row:", e), ee(e) || g.add({
282
+ severity: "error",
283
+ summary: "Delete failed",
284
+ detail: "That row couldn't be removed.",
285
+ life: 4e3
286
+ });
287
+ }
288
+ },
289
+ reject: () => {
290
+ }
291
+ });
292
+ }
293
+ const P = h(null), B = h(""), L = h(null);
294
+ function fe(o) {
295
+ P.value = o.id, B.value = o.name, Pe(() => {
296
+ (Array.isArray(L.value) ? L.value[0] : L.value)?.focus();
297
+ });
298
+ }
299
+ async function J(o) {
300
+ const e = "Saved";
301
+ if (P.value === o) {
302
+ const n = B.value.trim().toLowerCase().replace(/\s+/g, "_").replace(/[^a-z0-9_]/g, "");
303
+ try {
304
+ const s = await b.value.rename(o, n);
305
+ P.value = null, g.add({
306
+ severity: s ? "success" : "error",
307
+ summary: s ? "Rename successful" : "Save failed",
308
+ detail: s ? e : "Please try again",
309
+ life: 3e3
310
+ });
311
+ } catch (s) {
312
+ console.error("[maildeno-editor] failed to rename saved row:", s), ee(s) || g.add({
313
+ severity: "error",
314
+ summary: "Rename failed",
315
+ detail: "Please try again",
316
+ life: 4e3
317
+ });
318
+ }
319
+ }
320
+ }
321
+ function Q(o) {
322
+ return new Date(o).toLocaleDateString(void 0, {
323
+ month: "short",
324
+ day: "numeric"
325
+ });
326
+ }
327
+ return (o, e) => (a(), H($e, { name: "panel-slide" }, {
328
+ default: oe(() => [T(w) ? (a(), d("div", Be, [t("div", Le, [
329
+ t("div", He, [e[8] || (e[8] = t("div", { class: "flex items-center gap-2" }, [t("svg", {
330
+ class: "w-3.5 h-3.5 text-(--md-text-subtle)",
331
+ viewBox: "0 0 24 24",
332
+ fill: "none",
333
+ stroke: "currentColor",
334
+ "stroke-width": "2",
335
+ "stroke-linecap": "round",
336
+ "stroke-linejoin": "round"
337
+ }, [t("path", { d: "m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z" })]), t("span", { class: "text-[11px] font-semibold text-(--md-text-subtle) uppercase tracking-[.08em]" }, " Saved Rows ")], -1)), t("div", Ne, [t("button", {
338
+ onClick: e[0] || (e[0] = (...n) => T(k) && T(k)(...n)),
339
+ class: "w-6 h-6 flex items-center justify-center rounded-md text-(--md-text-subtle) hover:text-(--md-text-muted) hover:bg-(--md-surface-muted) transition-colors focus:outline-none"
340
+ }, [...e[6] || (e[6] = [t("svg", {
341
+ class: "w-3.5 h-3.5",
342
+ viewBox: "0 0 24 24",
343
+ fill: "none",
344
+ stroke: "currentColor",
345
+ "stroke-width": "2",
346
+ "stroke-linecap": "round",
347
+ "stroke-linejoin": "round"
348
+ }, [t("path", { d: "M18 6 6 18M6 6l12 12" })], -1)])]), e[7] || (e[7] = t("div", { class: "pointer-events-none absolute right-0 top-full mt-1.5 px-2 py-1 bg-(--md-tooltip-bg) text-(--md-tooltip-text) text-[10px] font-medium rounded-md whitespace-nowrap opacity-0 group-hover/close:opacity-100 -translate-y-0.5 group-hover/close:translate-y-0 transition-all duration-150 z-50 after:content-[''] after:absolute after:bottom-full after:right-2 after:border-4 after:border-transparent after:border-b-(--md-tooltip-bg)" }, " Close panel ", -1))])]),
349
+ t("div", Ve, [x.value ? (a(), d("div", We, [(a(), d($, null, j(["user", "system"], (n) => t("button", {
350
+ key: n,
351
+ type: "button",
352
+ class: re(["px-2 py-1 rounded-md text-[11px] font-medium transition-colors", u.value === n ? "bg-(--md-accent-bg) text-(--md-accent-text)" : "text-(--md-text-subtle) hover:text-(--md-text-muted) hover:bg-(--md-surface-muted)"]),
353
+ "aria-pressed": u.value === n,
354
+ onClick: (s) => u.value = n
355
+ }, z(n === "user" ? "My Rows" : "Shared"), 11, Ge)), 64))])) : (a(), d("span", Oe, "My Rows"))]),
356
+ t("div", Ue, [b.value.isFetching.value ? (a(), d("div", Ke, [(a(), d($, null, j(3, (n) => t("div", {
357
+ key: n,
358
+ class: "rounded-lg border border-(--md-border) overflow-hidden"
359
+ }, [t("div", {
360
+ class: "bg-(--md-surface-muted) animate-pulse",
361
+ style: I({ height: 80 + n * 20 + "px" })
362
+ }, null, 4), e[9] || (e[9] = t("div", { class: "flex items-center gap-2 px-2.5 py-2" }, [t("div", { class: "h-2 flex-1 rounded-full bg-(--md-surface-muted) animate-pulse" }), t("div", { class: "h-2 w-7 rounded-full bg-(--md-surface-muted) animate-pulse" })], -1))])), 64))])) : b.value.rows.value.length === 0 ? (a(), d("div", qe, [...e[10] || (e[10] = [t("div", { class: "w-10 h-10 rounded-xl bg-(--md-surface-hover) border border-(--md-border)/80 flex items-center justify-center" }, [t("svg", {
363
+ class: "w-5 h-5 text-(--md-text-subtle)",
364
+ viewBox: "0 0 24 24",
365
+ fill: "none",
366
+ stroke: "currentColor",
367
+ "stroke-width": "1.5",
368
+ "stroke-linecap": "round",
369
+ "stroke-linejoin": "round"
370
+ }, [t("path", { d: "m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z" })])], -1), t("div", { class: "space-y-1" }, [t("p", { class: "text-xs font-medium text-(--md-text-subtle)" }, " No saved rows yet "), t("p", { class: "text-[11px] text-(--md-text-subtle) leading-relaxed" }, [
371
+ V(" Select a row on the canvas,"),
372
+ t("br"),
373
+ V("then click "),
374
+ t("span", { class: "text-(--md-row-selection-fg) font-medium" }, "Save"),
375
+ V(" in the toolbar. ")
376
+ ])], -1)])])) : (a(), d("div", Ye, [G(Se, { name: "row-list" }, {
377
+ default: oe(() => [(a(!0), d($, null, j(ie.value, (n) => (a(), d("div", {
378
+ key: n.id,
379
+ draggable: "true",
380
+ class: re(["group relative rounded-lg border bg-(--md-surface) overflow-hidden transition-all duration-150 select-none cursor-grab active:cursor-grabbing", [N.value === n.id ? "ring-2 ring-(--md-row-selection) ring-offset-1 opacity-60 border-(--md-row-selection)" : "border-(--md-border)/80 hover:border-(--md-border-strong) hover:shadow-[0_2px_8px_rgba(0,0,0,0.07)]"]]),
381
+ onClick: (s) => me(n.id),
382
+ onDragstart: (s) => le(s, n.id),
383
+ onDragend: de
384
+ }, [t("div", {
385
+ ref_for: !0,
386
+ ref: (s) => ce(s, n.id),
387
+ class: "relative overflow-hidden border-b border-(--md-border)",
388
+ style: I({
389
+ height: ue(n.id) + "px",
390
+ backgroundColor: n.row.backgroundColor || "#f9fafb"
391
+ })
392
+ }, [t("div", {
393
+ ref_for: !0,
394
+ ref: (s) => pe(s, n.id),
395
+ class: "absolute top-0 left-0 pointer-events-none",
396
+ style: I({
397
+ width: "600px",
398
+ transformOrigin: "top left",
399
+ transform: `scale(${Y(n.id)})`
400
+ })
401
+ }, [G(Ae, { row: n.row }, null, 8, ["row"])], 4), e[11] || (e[11] = t("div", { class: "absolute inset-0 bg-(--md-text)/0 group-hover:bg-(--md-text)/[0.03] transition-colors duration-150 flex items-center justify-center" }, [t("div", { class: "opacity-0 group-hover:opacity-100 transition-opacity duration-150 flex items-center gap-1.5 bg-(--md-surface)/90 backdrop-blur-sm border border-(--md-border) rounded-full px-2.5 py-1 shadow-sm" }, [t("svg", {
402
+ class: "w-3 h-3 text-(--md-text-subtle)",
403
+ viewBox: "0 0 24 24",
404
+ fill: "none",
405
+ stroke: "currentColor",
406
+ "stroke-width": "2",
407
+ "stroke-linecap": "round",
408
+ "stroke-linejoin": "round"
409
+ }, [t("path", { d: "M12 5v14M5 12l7-7 7 7" })]), t("span", { class: "text-[10px] font-medium text-(--md-text-muted)" }, "Click to insert")])], -1))], 4), F.value ? (a(), d("div", {
410
+ key: 0,
411
+ onClick: e[5] || (e[5] = M(() => {
412
+ }, ["stop"])),
413
+ class: "flex items-center gap-1.5 px-2 py-1.5"
414
+ }, [
415
+ e[14] || (e[14] = t("div", { class: "shrink-0 text-(--md-text-subtle) group-hover:text-(--md-text-muted) transition-colors cursor-grab active:cursor-grabbing" }, [t("svg", {
416
+ class: "w-3 h-3",
417
+ viewBox: "0 0 16 16",
418
+ fill: "currentColor"
419
+ }, [
420
+ t("circle", {
421
+ cx: "5",
422
+ cy: "4",
423
+ r: "1.2"
424
+ }),
425
+ t("circle", {
426
+ cx: "11",
427
+ cy: "4",
428
+ r: "1.2"
429
+ }),
430
+ t("circle", {
431
+ cx: "5",
432
+ cy: "8",
433
+ r: "1.2"
434
+ }),
435
+ t("circle", {
436
+ cx: "11",
437
+ cy: "8",
438
+ r: "1.2"
439
+ }),
440
+ t("circle", {
441
+ cx: "5",
442
+ cy: "12",
443
+ r: "1.2"
444
+ }),
445
+ t("circle", {
446
+ cx: "11",
447
+ cy: "12",
448
+ r: "1.2"
449
+ })
450
+ ])], -1)),
451
+ P.value !== n.id ? (a(), d("span", {
452
+ key: 0,
453
+ onDblclick: M((s) => fe(n), ["stop"]),
454
+ onClick: e[1] || (e[1] = M(() => {
455
+ }, ["stop"])),
456
+ class: "flex-1 text-[11px] font-medium text-(--md-text-muted) truncate cursor-text"
457
+ }, z(n.name), 41, Qe)) : De((a(), d("input", {
458
+ key: 1,
459
+ "onUpdate:modelValue": e[2] || (e[2] = (s) => B.value = s),
460
+ onBlur: (s) => J(n.id),
461
+ onKeyup: [ne((s) => J(n.id), ["enter"]), e[3] || (e[3] = ne((s) => P.value = null, ["escape"]))],
462
+ onClick: e[4] || (e[4] = M(() => {
463
+ }, ["stop"])),
464
+ class: "flex-1 text-[11px] text-(--md-text) border border-(--md-row-selection) bg-(--md-row-selection-bg)/40 rounded-md px-1.5 py-0.5 focus:outline-none focus:border-(--md-row-selection)",
465
+ ref_for: !0,
466
+ ref_key: "renameInputRef",
467
+ ref: L
468
+ }, null, 40, Xe)), [[Te, B.value]]),
469
+ t("span", Ze, z(Q(n.createdAt)), 1),
470
+ C.value ? (a(), d("div", et, [t("button", {
471
+ onClick: M((s) => ve(n.id), ["stop"]),
472
+ class: "hidden group-hover:flex items-center justify-center w-5 h-5 shrink-0 rounded-md text-(--md-text-subtle) hover:text-(--md-danger) hover:bg-(--md-danger-bg) transition-colors focus:outline-none"
473
+ }, [...e[12] || (e[12] = [t("svg", {
474
+ class: "w-3 h-3",
475
+ viewBox: "0 0 24 24",
476
+ fill: "none",
477
+ stroke: "currentColor",
478
+ "stroke-width": "1.75",
479
+ "stroke-linecap": "round",
480
+ "stroke-linejoin": "round"
481
+ }, [t("path", { d: "M3 6h18M8 6V4h8v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), t("path", { d: "M10 11v6M14 11v6" })], -1)])], 8, tt), e[13] || (e[13] = t("div", { class: "pointer-events-none absolute bottom-full right-0 mb-1.5 px-2 py-1 bg-(--md-tooltip-bg) text-(--md-tooltip-text) text-[10px] font-medium rounded-md whitespace-nowrap opacity-0 group-hover/del:opacity-100 translate-y-0.5 group-hover/del:translate-y-0 transition-all duration-150 z-50 after:content-[''] after:absolute after:top-full after:right-2 after:border-4 after:border-transparent after:border-t-(--md-tooltip-bg)" }, " Remove ", -1))])) : W("", !0)
482
+ ])) : (a(), d("div", rt, [t("span", ot, z(n.name), 1), t("span", nt, z(Q(n.createdAt)), 1)]))], 42, Je))), 128))]),
483
+ _: 1
484
+ })]))])
485
+ ])])) : W("", !0)]),
486
+ _: 1
487
+ }));
488
+ }
489
+ }), pt = /* @__PURE__ */ Re(st, [["__scopeId", "data-v-ef885a8c"]]);
490
+ export {
491
+ pt as default,
492
+ Me as t
493
+ };
@@ -0,0 +1,8 @@
1
+ var a = (t, r) => {
2
+ const e = t.__vccOpts || t;
3
+ for (const [_, o] of r) e[_] = o;
4
+ return e;
5
+ };
6
+ export {
7
+ a as t
8
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * adapters/errors.ts — the one thing the editor and a host adapter need to
3
+ * agree on about failure.
4
+ *
5
+ * The editor has no user, role, plan or HTTP model, deliberately (see the
6
+ * README's "Positioning" section, and the comment at the top of
7
+ * SavedRowsPanel.vue). So it cannot say anything useful about a 403, a 402 or
8
+ * an expired session — only the host knows what its own statuses mean and
9
+ * what the user should do about them.
10
+ *
11
+ * That leaves a gap. A host adapter that catches its own 403 and shows a
12
+ * precise message ("your role can't delete saved rows — ask an admin") gets a
13
+ * second, vaguer toast from the editor's own catch block a moment later
14
+ * ("Delete failed"). Two toasts for one click, the less useful one last.
15
+ *
16
+ * `handled` closes it without teaching the editor anything about permissions.
17
+ * The host marks an error it has already surfaced; the editor only asks "did
18
+ * someone already tell the user?" and stays quiet if so. It still gets the
19
+ * rejection — which matters, because every optimistic update in this package
20
+ * is applied on resolve, so a swallowed failure would leave the UI showing a
21
+ * delete or rename that never happened.
22
+ *
23
+ * Hosts that don't use this lose nothing: unmarked errors take the editor's
24
+ * generic message exactly as before.
25
+ */
26
+ /**
27
+ * Marks an error as already reported to the user, and returns it for
28
+ * rethrowing:
29
+ *
30
+ * ```ts
31
+ * catch (err) {
32
+ * toast.add({ severity: "warn", summary: "Not allowed", detail });
33
+ * throw markHandled(err);
34
+ * }
35
+ * ```
36
+ *
37
+ * Mutates in place when it can, so `err.status` / `err.data` and any other
38
+ * fields the host reads downstream survive. Some rejections can't be mutated
39
+ * — ofetch's FetchError is frozen, and a thrown string isn't an object at all
40
+ * — so those get a fresh Error carrying the original as `cause` rather than
41
+ * throwing a TypeError from inside a catch block, which would replace the
42
+ * real failure with a confusing one.
43
+ */
44
+ export declare function markHandled(err: unknown): unknown;
45
+ /**
46
+ * Whether the host already showed the user a message for this failure.
47
+ *
48
+ * Guard the editor's own toast with it, never the recovery logic — a handled
49
+ * error is still an error, and state that was rolled back or a panel that was
50
+ * left open must behave identically either way:
51
+ *
52
+ * ```ts
53
+ * catch (err) {
54
+ * console.error("[maildeno-editor] failed to delete version:", err);
55
+ * if (!isHandled(err)) toast.add({ severity: "error", summary: "Delete failed" });
56
+ * }
57
+ * ```
58
+ */
59
+ export declare function isHandled(err: unknown): boolean;
@@ -0,0 +1,6 @@
1
+ import { EditorStorageAdapter } from './types';
2
+ /**
3
+ * The default adapter — fully functional with zero backend. This is what
4
+ * ships when no storageAdapter prop is passed to <EmailEditor>.
5
+ */
6
+ export declare function createLocalStorageAdapter(): EditorStorageAdapter;