@boxcc/maildeno-editor 0.0.0-stage → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +479 -0
- package/README.md +441 -2
- package/dist/DatePicker-AdfGW0Tw.js +5347 -0
- package/dist/DatePicker-aNFlsoOb.js +5347 -0
- package/dist/Dialog-By0JLN8s.js +6294 -0
- package/dist/HealthIndicator-4Iw6N-g_.js +1216 -0
- package/dist/HealthIndicator-ZohgzF2_.js +1217 -0
- package/dist/PopperContent-N2nAEFeH.js +2538 -0
- package/dist/PopperContent-eLmz1Gjd.js +2578 -0
- package/dist/PreviewCanvas-DzpLghCo.js +534 -0
- package/dist/PreviewCanvas-QN4C68KA.js +534 -0
- package/dist/RichTextEditor-CmM4XRFC.js +12218 -0
- package/dist/RichTextEditor-Cz1-_ZtA.js +12217 -0
- package/dist/RowPreviewChildren-BYaMZID3.js +4 -0
- package/dist/RowPreviewChildren-_A9gPQCs.js +4 -0
- package/dist/RowPreviewLegacyComponent-Df_1HTly.js +403 -0
- package/dist/RowPreviewLegacyComponent-NECG3wpn.js +403 -0
- package/dist/RowPreviewRow-DPaSbxmB.js +81 -0
- package/dist/RowPreviewRow-Dx4ExtSN.js +81 -0
- package/dist/SavedRowsPanel-DqSHB6Jk.js +492 -0
- package/dist/SavedRowsPanel-DyXjSOEt.js +493 -0
- package/dist/_plugin-vue_export-helper-Dj7HTbfw.js +8 -0
- package/dist/adapters/errors.d.ts +59 -0
- package/dist/adapters/localStorageAdapter.d.ts +6 -0
- package/dist/adapters/types.d.ts +151 -0
- package/dist/babel-DV7WPQI0.js +10043 -0
- package/dist/blocks/registry.d.ts +23 -0
- package/dist/blocks/types.d.ts +73 -0
- package/dist/borderRadius-CkSa1lQ9.js +75 -0
- package/dist/components/features/emailBuilder/EmailEditor.vue.d.ts +182 -0
- package/dist/composables/emailBuilder/export/logic/espLogicWrapper.d.ts +76 -0
- package/dist/composables/emailBuilder/persistence/useEmailBuilderPersistence.d.ts +38 -0
- package/dist/composables/emailBuilder/transform/pipeline/optimize.d.ts +100 -0
- package/dist/composables/system/useColorScheme.d.ts +16 -0
- package/dist/element-B3gq8Xvd.js +21500 -0
- package/dist/element.d.ts +6 -0
- package/dist/element.js +5 -0
- package/dist/esp/registry.d.ts +33 -0
- package/dist/estree-DY9POgc0.js +8195 -0
- package/dist/html-wb0gSX1o.js +7273 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +14992 -0
- package/dist/init.d.ts +178 -0
- package/dist/init.js +137 -0
- package/dist/maildeno-editor.css +2 -0
- package/dist/merge-tags/registry.d.ts +33 -0
- package/dist/mergeTagDefinitions-Cler19nv.js +27 -0
- package/dist/standalone-DHvJ30Td.js +3554 -0
- package/dist/theme.d.ts +206 -0
- package/dist/types/assistant.d.ts +56 -0
- package/dist/useEmailBuilder-B19p-2yp.js +4924 -0
- package/dist/useEmailBuilder-BR4wfai1.js +4924 -0
- package/dist/useToast-DD11IxqP.js +194 -0
- package/dist/utils/border.d.ts +15 -0
- package/dist/utils/borderRadius.d.ts +10 -0
- package/dist/vue.runtime.esm-bundler-D2AjRP90.js +6117 -0
- package/package.json +100 -4
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BlockDefinition } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Registers a block type.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* registerBlock({
|
|
7
|
+
* name: "product-card",
|
|
8
|
+
* label: "Product Card",
|
|
9
|
+
* icon: "<svg …>",
|
|
10
|
+
* schema: { … },
|
|
11
|
+
* renderCanvas, renderSettings, renderEmail,
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* A two-argument form, `registerBlock(id, definition)`, is also accepted. The
|
|
16
|
+
* definition already carries `name`, so the separate id is redundant — but the
|
|
17
|
+
* built-in blocks are registered that way and external code may be too, so
|
|
18
|
+
* both keep working. When both are given, the explicit id wins.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerBlock(definition: BlockDefinition): void;
|
|
21
|
+
export declare function registerBlock(id: string, definition: BlockDefinition): void;
|
|
22
|
+
export declare function getBlock(id: string): BlockDefinition | undefined;
|
|
23
|
+
export declare function getAllBlocks(): ReadonlyMap<string, BlockDefinition>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Component } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Confirmed against the real generators (html.ts/mjml.ts/react-email.ts):
|
|
4
|
+
* each is a switch(type) dispatcher with no default case — an unmapped type
|
|
5
|
+
* renders as an empty string, silently. That's why all three export
|
|
6
|
+
* renderers are required, not optional-with-fallback.
|
|
7
|
+
*
|
|
8
|
+
* Confirmed against CanvasComponent.vue and ContentTab.vue: block dispatch
|
|
9
|
+
* actually happens in five places, not three — canvas rendering and the
|
|
10
|
+
* settings panel are separate v-if chains the original README draft didn't
|
|
11
|
+
* account for. Same "no silent gap" rule applies here for consistency:
|
|
12
|
+
* renderCanvas and renderSettings are required too.
|
|
13
|
+
*/
|
|
14
|
+
export interface BlockRenderContext {
|
|
15
|
+
uid: string;
|
|
16
|
+
marginStyle: string;
|
|
17
|
+
paddingStyle: string;
|
|
18
|
+
escapeHtml: (s: string) => string;
|
|
19
|
+
escapeAttr: (s: string) => string;
|
|
20
|
+
safeUrl: (s: string) => string;
|
|
21
|
+
resolveBgCss: (gradient: any, fallback: string) => string;
|
|
22
|
+
resolveBgVml: (gradient: any, fallback: string) => {
|
|
23
|
+
vmlOpen: string;
|
|
24
|
+
vmlClose: string;
|
|
25
|
+
};
|
|
26
|
+
getResponsiveClasses: (desktopHide: boolean, mobileHide: boolean, suffix?: string) => string;
|
|
27
|
+
/** React Email target only — builds JSX style objects instead of CSS
|
|
28
|
+
* strings (confirmed: hand-rolled, not the real react/mjml packages). */
|
|
29
|
+
react: {
|
|
30
|
+
parseCssString: (css: string) => Record<string, string>;
|
|
31
|
+
parseMarginPaddingDiscrete: (margin?: any, padding?: any) => Record<string, string>;
|
|
32
|
+
normalizeFontFamily: (value: string) => string;
|
|
33
|
+
styleObj: (obj: Record<string, any>) => string;
|
|
34
|
+
normalizeInlineStylesToReact: (html: string) => string;
|
|
35
|
+
buildInlineJsx: (component: "Text" | "Heading", className: string, styleRecord: Record<string, any>, children: string, as?: string) => string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export interface BlockDefinition {
|
|
39
|
+
name: string;
|
|
40
|
+
/**
|
|
41
|
+
* Shown in the sidebar tooltip and the block's info dialog. Falls back to
|
|
42
|
+
* `name` when omitted.
|
|
43
|
+
*/
|
|
44
|
+
label?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Sidebar icon. Either a raw SVG string or a Vue component.
|
|
47
|
+
*
|
|
48
|
+
* A string is the common case — paste the SVG from whatever icon set you
|
|
49
|
+
* use, no import or build step. It is rendered inline so it inherits
|
|
50
|
+
* `currentColor` and the surrounding sizing, which keeps a custom block
|
|
51
|
+
* visually consistent with the built-in ones.
|
|
52
|
+
*
|
|
53
|
+
* Without an icon a registered block still works, but has no sidebar
|
|
54
|
+
* entry — it can only be added programmatically.
|
|
55
|
+
*/
|
|
56
|
+
icon?: string | Component;
|
|
57
|
+
/** Drives future tooling (docs, a generic settings fallback for
|
|
58
|
+
* third-party blocks). Built-ins point renderSettings at their existing
|
|
59
|
+
* bespoke panel instead of relying on this to generate one. */
|
|
60
|
+
schema: Record<string, unknown>;
|
|
61
|
+
/** Vue component, receives a single `component` prop — the block's own
|
|
62
|
+
* node from the tree ({ id, componentType, props, ... }). Matches the
|
|
63
|
+
* existing renderer pattern (ImageRenderer, AnchorRenderer, etc). */
|
|
64
|
+
renderCanvas: Component;
|
|
65
|
+
/** Vue component, no props — reads the selected component itself via
|
|
66
|
+
* useEmailBuilder(), same as every existing panel (ButtonPanel, etc). */
|
|
67
|
+
renderSettings: Component;
|
|
68
|
+
renderEmail: {
|
|
69
|
+
html: (props: any, ctx: BlockRenderContext) => string;
|
|
70
|
+
mjml: (props: any, ctx: BlockRenderContext) => string;
|
|
71
|
+
reactEmail: (props: any, ctx: BlockRenderContext) => string;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
var i = [
|
|
2
|
+
"top",
|
|
3
|
+
"right",
|
|
4
|
+
"bottom",
|
|
5
|
+
"left"
|
|
6
|
+
];
|
|
7
|
+
function n(t) {
|
|
8
|
+
const s = {
|
|
9
|
+
width: t?.width ?? 0,
|
|
10
|
+
color: t?.color ?? "transparent",
|
|
11
|
+
style: t?.style ?? "solid"
|
|
12
|
+
};
|
|
13
|
+
return Object.fromEntries(i.map((o) => [o, {
|
|
14
|
+
...s,
|
|
15
|
+
...t?.sides?.[o]
|
|
16
|
+
}]));
|
|
17
|
+
}
|
|
18
|
+
function f(t) {
|
|
19
|
+
const { sides: s, ...o } = t;
|
|
20
|
+
return s ? {
|
|
21
|
+
...o,
|
|
22
|
+
...n(t).top
|
|
23
|
+
} : {
|
|
24
|
+
...o,
|
|
25
|
+
sides: n(t)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function m(t) {
|
|
29
|
+
return Object.values(n(t)).some((s) => s.width > 0 && s.style !== "none");
|
|
30
|
+
}
|
|
31
|
+
function p(t) {
|
|
32
|
+
const s = n(t);
|
|
33
|
+
if (!t?.sides) {
|
|
34
|
+
const { width: o, style: r, color: e } = s.top;
|
|
35
|
+
return { border: `${o}px ${r} ${e}` };
|
|
36
|
+
}
|
|
37
|
+
return Object.fromEntries(i.map((o) => {
|
|
38
|
+
const { width: r, style: e, color: c } = s[o];
|
|
39
|
+
return [`border${o[0].toUpperCase()}${o.slice(1)}`, `${r}px ${e} ${c}`];
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
function u(t, s = !1) {
|
|
43
|
+
return Object.entries(p(t)).map(([o, r]) => `${o.replace(/[A-Z]/g, (e) => `-${e.toLowerCase()}`)}:${r}${s ? " !important" : ""}`).join(";");
|
|
44
|
+
}
|
|
45
|
+
function a(t = 0) {
|
|
46
|
+
return typeof t == "number" ? {
|
|
47
|
+
topLeft: t,
|
|
48
|
+
topRight: t,
|
|
49
|
+
bottomRight: t,
|
|
50
|
+
bottomLeft: t
|
|
51
|
+
} : { ...t };
|
|
52
|
+
}
|
|
53
|
+
function b(t = 0) {
|
|
54
|
+
return Object.values(a(t)).some((s) => s > 0);
|
|
55
|
+
}
|
|
56
|
+
function d(t = 0, s = 0) {
|
|
57
|
+
const o = (r) => `${r > 0 ? r + s : 0}px`;
|
|
58
|
+
return typeof t == "number" ? o(t) : [
|
|
59
|
+
t.topLeft,
|
|
60
|
+
t.topRight,
|
|
61
|
+
t.bottomRight,
|
|
62
|
+
t.bottomLeft
|
|
63
|
+
].map(o).join(" ");
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
n as a,
|
|
67
|
+
m as c,
|
|
68
|
+
i,
|
|
69
|
+
f as l,
|
|
70
|
+
a as n,
|
|
71
|
+
p as o,
|
|
72
|
+
d as r,
|
|
73
|
+
u as s,
|
|
74
|
+
b as t
|
|
75
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { ColorMode } from '../../../composables/system/useColorScheme';
|
|
2
|
+
import { PartialStorageAdapter } from '../../../adapters/types';
|
|
3
|
+
import { ThemeOptions } from '../../../theme';
|
|
4
|
+
import { AssistantMount, EditorWriteApi } from '../../../types/assistant';
|
|
5
|
+
type __VLS_Props = {
|
|
6
|
+
isReady?: boolean;
|
|
7
|
+
storageAdapter?: PartialStorageAdapter;
|
|
8
|
+
/** If given, loaded via the adapter on mount. Omit to start blank
|
|
9
|
+
* (create mode) — matches the original app's /create vs /edit split,
|
|
10
|
+
* now driven by a prop instead of a route. */
|
|
11
|
+
templateId?: string;
|
|
12
|
+
/** Applied via CSS custom properties (see theme.ts) — works whether this
|
|
13
|
+
* component is used directly or wrapped by element.ts's
|
|
14
|
+
* defineCustomElement, because both write to the same place: this
|
|
15
|
+
* component's own root element, which is where the package's bundled
|
|
16
|
+
* defaults land too once the library build has scoped them. Reactive:
|
|
17
|
+
* assigning a new object re-themes live, no remount. */
|
|
18
|
+
theme?: ThemeOptions;
|
|
19
|
+
/**
|
|
20
|
+
* Which half of `theme` applies.
|
|
21
|
+
*
|
|
22
|
+
* `auto` (the default) follows the host page: useColorScheme.ts watches
|
|
23
|
+
* for a `dark` class on <html> or <body> and mirrors it onto the editor
|
|
24
|
+
* root. A host that already has a Tailwind-style theme switcher needs no
|
|
25
|
+
* wiring at all — flipping the class moves the editor in the same frame.
|
|
26
|
+
*
|
|
27
|
+
* Pass `light` or `dark` to pin the editor regardless of the page: a
|
|
28
|
+
* light editor deliberately embedded in a dark shell, or a host whose
|
|
29
|
+
* switcher signals something other than a class.
|
|
30
|
+
*/
|
|
31
|
+
colorMode?: ColorMode;
|
|
32
|
+
/** If provided, the "Send test" button appears in the header. Editor
|
|
33
|
+
* owns the form/validation UI; this callback owns what actually
|
|
34
|
+
* happens on submit (SMTP, an API, anything) — same host-owns-the-
|
|
35
|
+
* operation pattern as the storage adapter. */
|
|
36
|
+
/**
|
|
37
|
+
* Called after a successful save. Its presence is what reveals the Save
|
|
38
|
+
* button — same idiom as onSendTestEmail below.
|
|
39
|
+
*
|
|
40
|
+
* Gating on an explicit handler rather than on the storage adapter,
|
|
41
|
+
* because the adapter can't answer the question: PartialStorageAdapter
|
|
42
|
+
* is merged with the localStorage defaults, so `saveTemplate` always
|
|
43
|
+
* exists by the time anything reads it. A host that wants a read-only or
|
|
44
|
+
* guest editor simply omits this.
|
|
45
|
+
*
|
|
46
|
+
* The `save` event still fires alongside, so `@save` keeps working — and
|
|
47
|
+
* because Vue compiles `@save="fn"` to an `onSave` prop, writing the
|
|
48
|
+
* listener is itself enough to reveal the button.
|
|
49
|
+
*/
|
|
50
|
+
onSave?: (payload: {
|
|
51
|
+
templateId: string | null;
|
|
52
|
+
}) => void;
|
|
53
|
+
/**
|
|
54
|
+
* The same handler, under a name that doesn't begin with "on".
|
|
55
|
+
*
|
|
56
|
+
* For the custom-element path only. Vue's defineCustomElement treats
|
|
57
|
+
* `on*` keys as event listeners rather than props, so `el.onSave = fn`
|
|
58
|
+
* never reaches this component — the button appeared and the callback
|
|
59
|
+
* never fired. init() sets this instead. Vue hosts should use `@save`.
|
|
60
|
+
*/
|
|
61
|
+
saveHandler?: (payload: {
|
|
62
|
+
templateId: string | null;
|
|
63
|
+
}) => void;
|
|
64
|
+
onSendTestEmail?: (payload: {
|
|
65
|
+
to: string;
|
|
66
|
+
subject: string;
|
|
67
|
+
html: string;
|
|
68
|
+
}) => Promise<void> | void;
|
|
69
|
+
/** Explicit UI restrictions, layered on top of the implicit ones
|
|
70
|
+
* (e.g. onSendTestEmail's mere presence/absence already gates that
|
|
71
|
+
* button — capabilities doesn't replace that, it adds to it).
|
|
72
|
+
* Omit any key to leave that area fully enabled — this restricts,
|
|
73
|
+
* it never grants something that wasn't already possible. */
|
|
74
|
+
capabilities?: {
|
|
75
|
+
/** Which formats appear in the Export dropdown. Omit for all four. */
|
|
76
|
+
export?: Array<"html" | "mjml" | "react" | "json">;
|
|
77
|
+
/** Which saved-row controls this user gets: the canvas row's bookmark
|
|
78
|
+
* button, and the panel's per-row rename and delete. Omit a key for
|
|
79
|
+
* "allowed", the same as omitting the object. For a host with roles,
|
|
80
|
+
* this is what stops a viewer being shown three buttons that can only
|
|
81
|
+
* 403 — the toast their adapter raises afterwards is the backstop, not
|
|
82
|
+
* the design. Does not touch the Shared tab, which is read-only for
|
|
83
|
+
* everyone because no adapter method backs writing to it. */
|
|
84
|
+
savedRows?: {
|
|
85
|
+
create?: boolean;
|
|
86
|
+
rename?: boolean;
|
|
87
|
+
delete?: boolean;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/** Name shown in the loading overlay and in the desktop-only notice's
|
|
91
|
+
* "Powered by" line.
|
|
92
|
+
*
|
|
93
|
+
* Deliberately a prop rather than a theme token: `theme` carries
|
|
94
|
+
* colours, and this is text, so it has no sensible home in the token
|
|
95
|
+
* map. It is also the one piece of chrome a host cannot restyle away,
|
|
96
|
+
* since the notice replaces the entire editor on small screens.
|
|
97
|
+
*
|
|
98
|
+
* No default is declared here on purpose. Both consumers resolve an
|
|
99
|
+
* undefined value from DEFAULT_BRAND_NAME in brand.ts, so there is one
|
|
100
|
+
* place to change it rather than three that can drift — and declaring a
|
|
101
|
+
* default here would also make the empty-string case unreachable, since
|
|
102
|
+
* the prop would never arrive undefined. Omit for the package default;
|
|
103
|
+
* pass an empty string to render no wordmark and drop the attribution
|
|
104
|
+
* line entirely. */
|
|
105
|
+
brandName?: string;
|
|
106
|
+
/** Replaces the saved-templates panel (and its header button) with
|
|
107
|
+
* version history.
|
|
108
|
+
*
|
|
109
|
+
* A swap rather than an addition, because the two answer different
|
|
110
|
+
* questions — "which template?" versus "which state of this template?"
|
|
111
|
+
* — and a host that has its own template browser elsewhere in its app
|
|
112
|
+
* has no use for the former inside the editor. Two panels competing for
|
|
113
|
+
* the same slot would also mean two header buttons and a layout
|
|
114
|
+
* decision the editor shouldn't be making.
|
|
115
|
+
*
|
|
116
|
+
* Top-level rather than a `capabilities` key on purpose: capabilities
|
|
117
|
+
* documents itself as only ever restricting, never granting, and this
|
|
118
|
+
* grants.
|
|
119
|
+
*
|
|
120
|
+
* The panel still degrades per-method — see the version methods on
|
|
121
|
+
* EditorStorageAdapter. Setting this with an adapter that can't list
|
|
122
|
+
* versions gets an honest "not supported" message, not a broken panel. */
|
|
123
|
+
versions?: boolean;
|
|
124
|
+
/** Fills the assistant drawer from a non-Vue host (init(), React,
|
|
125
|
+
* vanilla). Vue hosts use the #assistant slot instead; either one being
|
|
126
|
+
* present reveals the trigger button, and neither means no assistant UI
|
|
127
|
+
* renders at all.
|
|
128
|
+
*
|
|
129
|
+
* The editor supplies the drawer, its trigger, open/close state, escape
|
|
130
|
+
* handling, focus return and shadow-DOM-safe teleporting. What goes
|
|
131
|
+
* inside is entirely the host's — see the AssistantPanel comment for
|
|
132
|
+
* why the assistant itself isn't in this package. */
|
|
133
|
+
assistant?: AssistantMount;
|
|
134
|
+
};
|
|
135
|
+
declare var __VLS_17: {
|
|
136
|
+
templateId: string | null;
|
|
137
|
+
isSaving: boolean;
|
|
138
|
+
saveStatus: import('../../..').AutoSaveStatus;
|
|
139
|
+
}, __VLS_80: {
|
|
140
|
+
editor: EditorWriteApi;
|
|
141
|
+
};
|
|
142
|
+
type __VLS_Slots = {} & {
|
|
143
|
+
'header-actions'?: (props: typeof __VLS_17) => any;
|
|
144
|
+
} & {
|
|
145
|
+
assistant?: (props: typeof __VLS_80) => any;
|
|
146
|
+
};
|
|
147
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {
|
|
148
|
+
getHtml: (mode?: "prune" | "wrap") => string | null;
|
|
149
|
+
getMjml: (mode?: "prune" | "wrap") => string | null;
|
|
150
|
+
getReactEmail: (mode?: "prune" | "wrap") => string | null;
|
|
151
|
+
getJson: () => {
|
|
152
|
+
template_id: string;
|
|
153
|
+
template_name: string;
|
|
154
|
+
canvas: Partial<import('../../..').Canvas>;
|
|
155
|
+
rows: Partial<import('../../..').NestedRow | import('../../..').RowSpacer>[];
|
|
156
|
+
schema_version: string;
|
|
157
|
+
} | null;
|
|
158
|
+
setJson: (data: any, opts?: {
|
|
159
|
+
history?: "undoable" | "reset";
|
|
160
|
+
}) => void;
|
|
161
|
+
getSelection: () => {
|
|
162
|
+
id: string;
|
|
163
|
+
type: string | null;
|
|
164
|
+
} | null;
|
|
165
|
+
setSelection: (id: string | null) => boolean;
|
|
166
|
+
onChange: (cb: () => void) => (() => void);
|
|
167
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
168
|
+
ready: () => any;
|
|
169
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
170
|
+
onReady?: (() => any) | undefined;
|
|
171
|
+
}>, {
|
|
172
|
+
isReady: boolean;
|
|
173
|
+
colorMode: ColorMode;
|
|
174
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
175
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
176
|
+
declare const _default: typeof __VLS_export;
|
|
177
|
+
export default _default;
|
|
178
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
179
|
+
new (): {
|
|
180
|
+
$slots: S;
|
|
181
|
+
};
|
|
182
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export type KnownESPSyntax = "handlebars" | "sendgrid" | "mailchimp" | "klaviyo" | "liquid" | "braze" | "sfmc" | "hubspot" | "iterable" | "activecampaign" | "marketo" | "campaign_monitor" | "pardot" | "mso";
|
|
2
|
+
export type ESPSyntax = KnownESPSyntax | (string & {});
|
|
3
|
+
export interface ESPSyntaxMeta {
|
|
4
|
+
label: string;
|
|
5
|
+
group: "handlebars" | "liquid" | "ampscript" | "custom" | "mso";
|
|
6
|
+
description: string;
|
|
7
|
+
docsUrl?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Whether this ESP supports boolean nesting / parenthesised sub-expressions.
|
|
10
|
+
* When false, buildFullExpression flattens all rules to a single level and
|
|
11
|
+
* the UI should warn the user that nested groups are not supported.
|
|
12
|
+
*/
|
|
13
|
+
supportsNesting: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const ESP_SYNTAX_META: Record<KnownESPSyntax, ESPSyntaxMeta>;
|
|
16
|
+
export type SupportLevel = "native" | "helper" | "fallback" | "none";
|
|
17
|
+
export interface OperatorSupportRow {
|
|
18
|
+
syntax: ESPSyntax;
|
|
19
|
+
label: string;
|
|
20
|
+
eq: SupportLevel;
|
|
21
|
+
neq: SupportLevel;
|
|
22
|
+
contains: SupportLevel;
|
|
23
|
+
not_contains: SupportLevel;
|
|
24
|
+
starts_with: SupportLevel;
|
|
25
|
+
ends_with: SupportLevel;
|
|
26
|
+
in: SupportLevel;
|
|
27
|
+
not_in: SupportLevel;
|
|
28
|
+
numeric: SupportLevel;
|
|
29
|
+
is_empty: SupportLevel;
|
|
30
|
+
/** date_before / date_after / date_on */
|
|
31
|
+
date: SupportLevel;
|
|
32
|
+
}
|
|
33
|
+
export declare const OPERATOR_SUPPORT_MATRIX: OperatorSupportRow[];
|
|
34
|
+
export interface VisibilityRuleForESP {
|
|
35
|
+
tag: string;
|
|
36
|
+
operator: string;
|
|
37
|
+
value: string;
|
|
38
|
+
}
|
|
39
|
+
export interface VisibilityGroupForESP {
|
|
40
|
+
match: "all" | "any";
|
|
41
|
+
rules: VisibilityRuleForESP[];
|
|
42
|
+
}
|
|
43
|
+
export interface VisibilityConfigForESP {
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
match: "all" | "any";
|
|
46
|
+
rules: VisibilityRuleForESP[];
|
|
47
|
+
groups?: VisibilityGroupForESP[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Wraps `content` in ESP conditional tags derived from `config`.
|
|
51
|
+
*
|
|
52
|
+
* Returns `content` unchanged when:
|
|
53
|
+
* • config is undefined / null
|
|
54
|
+
* • config.enabled is false
|
|
55
|
+
* • config has no rules and no groups (or all produce null expressions)
|
|
56
|
+
*
|
|
57
|
+
* Mailchimp: emits nested *|IF|* blocks instead of inline AND/OR because
|
|
58
|
+
* Mailchimp's parser does not reliably support complex boolean expressions.
|
|
59
|
+
*
|
|
60
|
+
* Liquid ESPs (Klaviyo, Braze, HubSpot, generic Liquid): for date_before /
|
|
61
|
+
* date_after rules, emits {% assign %} prelude lines before the {% if %} tag
|
|
62
|
+
* so that the unix-timestamp filter is captured in a variable rather than
|
|
63
|
+
* evaluated inline (which most Liquid engines do not support).
|
|
64
|
+
*/
|
|
65
|
+
export declare const wrapWithESPLogic: (content: string, config: VisibilityConfigForESP | undefined | null, syntax?: ESPSyntax) => string;
|
|
66
|
+
/**
|
|
67
|
+
* Preview the generated open/close tags without actual content.
|
|
68
|
+
* Useful for rendering a live preview in the VisibilityWrapESP component.
|
|
69
|
+
*
|
|
70
|
+
* For Mailchimp the openTag preview shows the first *|IF:…|* expression.
|
|
71
|
+
* For Liquid date rules the openTag includes any {% assign %} preludes.
|
|
72
|
+
*/
|
|
73
|
+
export declare const previewESPTags: (config: VisibilityConfigForESP | undefined | null, syntax?: ESPSyntax) => {
|
|
74
|
+
openTag: string;
|
|
75
|
+
closeTag: string;
|
|
76
|
+
} | null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type AutoSaveStatus = "idle" | "saving" | "saved" | "error";
|
|
2
|
+
export interface AutoSavePayload {
|
|
3
|
+
schemaVersion: string;
|
|
4
|
+
/** Which template this draft belongs to. Null for brand-new unsaved documents. */
|
|
5
|
+
templateId: string | null;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
touchedAt: number;
|
|
8
|
+
updatedAt: string;
|
|
9
|
+
/** Template display name — cached so the page title can be set without a DB fetch. */
|
|
10
|
+
name?: string;
|
|
11
|
+
/** Template tags — cached alongside name to fully avoid a DB fetch on draft restore. */
|
|
12
|
+
tags?: any[];
|
|
13
|
+
content: {
|
|
14
|
+
rows: any[];
|
|
15
|
+
canvas: Record<string, any>;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface RestoredDraft {
|
|
19
|
+
rows: any[];
|
|
20
|
+
canvas: Record<string, any>;
|
|
21
|
+
updatedAt: string;
|
|
22
|
+
/** Reflects the templateId stored in the payload — use this to verify the
|
|
23
|
+
* draft belongs to the currently open template before restoring it. */
|
|
24
|
+
templateId: string | null;
|
|
25
|
+
/** Cached template display name — set when the template was first loaded from DB. */
|
|
26
|
+
name?: string;
|
|
27
|
+
/** Cached template tags — set when the template was first loaded from DB. */
|
|
28
|
+
tags?: any[];
|
|
29
|
+
}
|
|
30
|
+
export declare const useEmailBuilderPersistence: () => {
|
|
31
|
+
saveToLocal: (rows: any[], canvas: Record<string, any>, templateId?: string | null, name?: string, tags?: any[]) => void;
|
|
32
|
+
flushSave: (rows: any[], canvas: Record<string, any>, templateId?: string | null, name?: string, tags?: any[]) => void;
|
|
33
|
+
loadFromLocal: () => RestoredDraft | null;
|
|
34
|
+
clearLocal: () => void;
|
|
35
|
+
hasDraft: (templateId?: string) => boolean;
|
|
36
|
+
saveStatus: import('vue').Ref<AutoSaveStatus, AutoSaveStatus>;
|
|
37
|
+
lastSaved: import('vue').Ref<Date | null, Date | null>;
|
|
38
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { BorderValue } from '../../../../utils/border';
|
|
2
|
+
import { BorderRadius } from '../../../../utils/borderRadius';
|
|
3
|
+
/**
|
|
4
|
+
* optimize.ts
|
|
5
|
+
* Strips default/noise values from rows, columns, components, and canvas before
|
|
6
|
+
* JSON export. Pairs with hydrate.ts — everything stripped here is restored on import.
|
|
7
|
+
*
|
|
8
|
+
* Supports both new `children` shape and legacy `components` shape per column.
|
|
9
|
+
*/
|
|
10
|
+
export interface VisibilityConfig {
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
match: "all" | "any";
|
|
13
|
+
rules: unknown[];
|
|
14
|
+
}
|
|
15
|
+
export interface BorderConfig extends BorderValue {
|
|
16
|
+
radius?: BorderRadius;
|
|
17
|
+
}
|
|
18
|
+
export interface GradientConfig {
|
|
19
|
+
useGradient: boolean;
|
|
20
|
+
solid: string;
|
|
21
|
+
gradient: {
|
|
22
|
+
type: "linear" | "radial";
|
|
23
|
+
direction: string;
|
|
24
|
+
colors: Array<{
|
|
25
|
+
color: string;
|
|
26
|
+
position: number;
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
interface Component {
|
|
31
|
+
id: string;
|
|
32
|
+
/** New discriminated shape uses "component"; legacy uses the componentType directly */
|
|
33
|
+
type: string;
|
|
34
|
+
/** Present when type === "component" */
|
|
35
|
+
componentType?: string;
|
|
36
|
+
props: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
type CanvasChild = Component | NestedRow | RowSpacer;
|
|
39
|
+
export interface Column {
|
|
40
|
+
id: string;
|
|
41
|
+
width: number;
|
|
42
|
+
/** New shape */
|
|
43
|
+
children?: CanvasChild[];
|
|
44
|
+
/** Legacy shape — kept for backward compat */
|
|
45
|
+
components?: Component[];
|
|
46
|
+
backgroundColor?: string;
|
|
47
|
+
backgroundGradient?: GradientConfig;
|
|
48
|
+
backgroundImage?: string;
|
|
49
|
+
backgroundSize?: string;
|
|
50
|
+
backgroundPosition?: string;
|
|
51
|
+
backgroundRepeat?: string;
|
|
52
|
+
padding?: Record<string, number>;
|
|
53
|
+
border?: BorderConfig;
|
|
54
|
+
verticalAlign?: string;
|
|
55
|
+
[key: string]: unknown;
|
|
56
|
+
}
|
|
57
|
+
export interface NestedRow {
|
|
58
|
+
id: string;
|
|
59
|
+
type: "row";
|
|
60
|
+
name?: string;
|
|
61
|
+
columns?: Column[];
|
|
62
|
+
visibility?: VisibilityConfig;
|
|
63
|
+
border?: BorderConfig;
|
|
64
|
+
backgroundImage?: string;
|
|
65
|
+
backgroundSize?: string;
|
|
66
|
+
backgroundPosition?: string;
|
|
67
|
+
backgroundRepeat?: string;
|
|
68
|
+
padding?: Record<string, number>;
|
|
69
|
+
backgroundGradient?: GradientConfig;
|
|
70
|
+
minHeight?: number;
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
export interface RowSpacer {
|
|
74
|
+
id: string;
|
|
75
|
+
type: "row-spacer";
|
|
76
|
+
name?: string;
|
|
77
|
+
height?: number;
|
|
78
|
+
backgroundColor?: string;
|
|
79
|
+
backgroundGradient?: GradientConfig;
|
|
80
|
+
visibility?: VisibilityConfig;
|
|
81
|
+
[key: string]: unknown;
|
|
82
|
+
}
|
|
83
|
+
type Row = NestedRow | RowSpacer;
|
|
84
|
+
export interface Canvas {
|
|
85
|
+
language?: string;
|
|
86
|
+
preheaderText?: string;
|
|
87
|
+
bodyBackgroundColor?: string;
|
|
88
|
+
bodyBackgroundImage?: string;
|
|
89
|
+
bodyBackgroundSize?: string;
|
|
90
|
+
bodyBackgroundPosition?: string;
|
|
91
|
+
bodyBackgroundRepeat?: string;
|
|
92
|
+
backgroundColor?: string;
|
|
93
|
+
width?: number;
|
|
94
|
+
padding?: Record<string, number>;
|
|
95
|
+
mobileBreakpoint?: number;
|
|
96
|
+
[key: string]: unknown;
|
|
97
|
+
}
|
|
98
|
+
export declare const optimizeCanvas: (canvas: Canvas) => Partial<Canvas>;
|
|
99
|
+
export declare const optimizeRows: (rows: Row[]) => Partial<Row>[];
|
|
100
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* `auto` follows the host page. `light` and `dark` pin the editor regardless
|
|
4
|
+
* of what the page is doing — useful when the editor is embedded in a shell
|
|
5
|
+
* whose theme it should not inherit.
|
|
6
|
+
*/
|
|
7
|
+
export type ColorMode = "light" | "dark" | "auto";
|
|
8
|
+
/**
|
|
9
|
+
* @param mode The `colorMode` prop, as a ref.
|
|
10
|
+
* @param host The custom-element host when running under element.ts, else
|
|
11
|
+
* null. Reflected onto as well, so `:host(.dark)` matches in an
|
|
12
|
+
* unscoped shadow build.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useColorScheme(mode: Ref<ColorMode | undefined>, host?: HTMLElement | null): {
|
|
15
|
+
isDark: import('vue').ComputedRef<boolean>;
|
|
16
|
+
};
|