@maildeno/editor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +426 -0
  3. package/dist/RowPreviewLegacyComponent-CXsY4P-R.js +439 -0
  4. package/dist/RowPreviewLegacyComponent-osWbuByc.js +439 -0
  5. package/dist/RowPreviewRow-D-U1mV4v.js +107 -0
  6. package/dist/RowPreviewRow-MSc_unf3.js +107 -0
  7. package/dist/adapters/index.d.ts +7 -0
  8. package/dist/adapters/localStorageAdapter.d.ts +6 -0
  9. package/dist/adapters/types.d.ts +83 -0
  10. package/dist/baseStyles.d.ts +13 -0
  11. package/dist/blocks/canvasStyleHelpers.d.ts +17 -0
  12. package/dist/blocks/definitions/anchor.d.ts +2 -0
  13. package/dist/blocks/definitions/button.d.ts +2 -0
  14. package/dist/blocks/definitions/divider.d.ts +2 -0
  15. package/dist/blocks/definitions/heading.d.ts +2 -0
  16. package/dist/blocks/definitions/image.d.ts +2 -0
  17. package/dist/blocks/definitions/list.d.ts +2 -0
  18. package/dist/blocks/definitions/menu.d.ts +2 -0
  19. package/dist/blocks/definitions/paragraph.d.ts +2 -0
  20. package/dist/blocks/definitions/socials.d.ts +2 -0
  21. package/dist/blocks/definitions/spacer.d.ts +2 -0
  22. package/dist/blocks/definitions/video.d.ts +2 -0
  23. package/dist/blocks/index.d.ts +8 -0
  24. package/dist/blocks/registry.d.ts +23 -0
  25. package/dist/blocks/types.d.ts +73 -0
  26. package/dist/composables/emailBuilder/components/useComponentStyleEditor.d.ts +72 -0
  27. package/dist/composables/emailBuilder/components/useProductRowActions.d.ts +3 -0
  28. package/dist/composables/emailBuilder/components/useProductRows.d.ts +59 -0
  29. package/dist/composables/emailBuilder/core/config/componentConfig.d.ts +29 -0
  30. package/dist/composables/emailBuilder/core/link-tags/useLinkTagInsert.d.ts +13 -0
  31. package/dist/composables/emailBuilder/core/merge-tags/mergeTagDefinitions.d.ts +64 -0
  32. package/dist/composables/emailBuilder/core/merge-tags/resolveMergeTags.d.ts +27 -0
  33. package/dist/composables/emailBuilder/core/ui/useLayerHoverScroll.d.ts +20 -0
  34. package/dist/composables/emailBuilder/core/ui/useLayoutDrag.d.ts +85 -0
  35. package/dist/composables/emailBuilder/core/ui/useRichTextEditors.d.ts +6 -0
  36. package/dist/composables/emailBuilder/core/ui/visibilityBadgeHelpers.d.ts +22 -0
  37. package/dist/composables/emailBuilder/core/useEmailBuilder.d.ts +274 -0
  38. package/dist/composables/emailBuilder/core/useEmailBuilderDefault.d.ts +507 -0
  39. package/dist/composables/emailBuilder/core/useEmailBuilderOperations.d.ts +31 -0
  40. package/dist/composables/emailBuilder/core/useEmailBuilderVisibility.d.ts +31 -0
  41. package/dist/composables/emailBuilder/export/actions/download.d.ts +24 -0
  42. package/dist/composables/emailBuilder/export/generators/html.d.ts +3 -0
  43. package/dist/composables/emailBuilder/export/generators/mjml.d.ts +6 -0
  44. package/dist/composables/emailBuilder/export/generators/react-email.d.ts +61 -0
  45. package/dist/composables/emailBuilder/export/helpers/generatorHelpers.d.ts +53 -0
  46. package/dist/composables/emailBuilder/export/logic/espLogicWrapper.d.ts +76 -0
  47. package/dist/composables/emailBuilder/export/logic/reactLogicWrapper.d.ts +31 -0
  48. package/dist/composables/emailBuilder/export/merge-tags/mergeTagMapper.d.ts +42 -0
  49. package/dist/composables/emailBuilder/export/merge-tags/reactMergeTagMapper.d.ts +26 -0
  50. package/dist/composables/emailBuilder/export/shared/containers.d.ts +18 -0
  51. package/dist/composables/emailBuilder/export/shared/styles.d.ts +12 -0
  52. package/dist/composables/emailBuilder/export/shared/tagIdentifier.d.ts +1 -0
  53. package/dist/composables/emailBuilder/export/targets/htmlExport.d.ts +20 -0
  54. package/dist/composables/emailBuilder/export/targets/jsonExport.d.ts +28 -0
  55. package/dist/composables/emailBuilder/export/targets/mjmlExport.d.ts +19 -0
  56. package/dist/composables/emailBuilder/export/targets/reactEmailExport.d.ts +20 -0
  57. package/dist/composables/emailBuilder/export/transformers/espWrapper.d.ts +2 -0
  58. package/dist/composables/emailBuilder/export/transformers/formatting.d.ts +3 -0
  59. package/dist/composables/emailBuilder/export/transformers/minify.d.ts +33 -0
  60. package/dist/composables/emailBuilder/export/transformers/tagMapper.d.ts +29 -0
  61. package/dist/composables/emailBuilder/export/types/export.d.ts +24 -0
  62. package/dist/composables/emailBuilder/export/useEmailExportEngine.d.ts +63 -0
  63. package/dist/composables/emailBuilder/export/useEmailExportMobileStyles.d.ts +3 -0
  64. package/dist/composables/emailBuilder/export/useExportSettings.d.ts +5 -0
  65. package/dist/composables/emailBuilder/health/accessibilityChecker.d.ts +64 -0
  66. package/dist/composables/emailBuilder/health/healthIndicator.d.ts +19 -0
  67. package/dist/composables/emailBuilder/history/useEmailBuilderHistory.d.ts +26 -0
  68. package/dist/composables/emailBuilder/history/useHistory.d.ts +16 -0
  69. package/dist/composables/emailBuilder/persistence/useEmailBuilderPersistence.d.ts +38 -0
  70. package/dist/composables/emailBuilder/preview/useClientPreview.d.ts +127 -0
  71. package/dist/composables/emailBuilder/transform/pipeline/hydrate.d.ts +54 -0
  72. package/dist/composables/emailBuilder/transform/pipeline/optimize.d.ts +101 -0
  73. package/dist/composables/emailBuilder/transform/pipeline/optimizeAI.d.ts +125 -0
  74. package/dist/composables/emailBuilder/types/emailBuilder.d.ts +79 -0
  75. package/dist/composables/system/useColor.d.ts +26 -0
  76. package/dist/composables/system/useDeviceDetection.d.ts +5 -0
  77. package/dist/composables/system/useGoogleFonts.d.ts +11 -0
  78. package/dist/composables/system/useImageUpload.d.ts +23 -0
  79. package/dist/composables/system/useSavedRowsPanel.d.ts +35 -0
  80. package/dist/composables/ui/useConfirm.d.ts +33 -0
  81. package/dist/composables/ui/useInfoDialog.d.ts +22 -0
  82. package/dist/composables/ui/useTeleportTarget.d.ts +49 -0
  83. package/dist/composables/ui/useToast.d.ts +32 -0
  84. package/dist/devStyleMirror.d.ts +20 -0
  85. package/dist/documentScopedStyles.d.ts +39 -0
  86. package/dist/editor.css +2411 -0
  87. package/dist/element-DN22fZmQ.js +72000 -0
  88. package/dist/element-scoped-styles.css +2411 -0
  89. package/dist/element.d.ts +6 -0
  90. package/dist/element.js +2 -0
  91. package/dist/esp/registry.d.ts +33 -0
  92. package/dist/estree-C12ASyI-.js +7993 -0
  93. package/dist/html-DGrfikay.js +7353 -0
  94. package/dist/index.d.ts +12 -0
  95. package/dist/index.js +71955 -0
  96. package/dist/init.d.ts +85 -0
  97. package/dist/init.js +130 -0
  98. package/dist/lightDom.d.ts +30 -0
  99. package/dist/merge-tags/registry.d.ts +33 -0
  100. package/dist/shadowStyles.d.ts +8 -0
  101. package/dist/standalone-Bd2oQFm3.js +3639 -0
  102. package/dist/theme.d.ts +132 -0
  103. package/dist/typescript-D-z2dDu9.js +23190 -0
  104. package/dist/utils/generateId.d.ts +1 -0
  105. package/dist/utils/shadowDom.d.ts +30 -0
  106. package/dist/vue.runtime.esm-bundler-DwQEK7WO.js +9028 -0
  107. package/package.json +99 -0
package/dist/init.d.ts ADDED
@@ -0,0 +1,85 @@
1
+ import { PartialStorageAdapter } from './adapters/types';
2
+ import { ThemeOptions } from './theme';
3
+ /**
4
+ * The ergonomic, no-Vue-knowledge entry point. element.ts already provides
5
+ * everything this composes — a real custom element, complete CSS bundling,
6
+ * live theming via CSS variables — init() just wires it up with a plain
7
+ * options object and hands back a small handle instead of requiring the
8
+ * caller to know defineCustomElement, prop reflection, or DOM CustomEvent
9
+ * details themselves.
10
+ */
11
+ export interface InitOptions {
12
+ /** A DOM element, or a CSS selector resolved via document.querySelector. */
13
+ container: HTMLElement | string;
14
+ templateId?: string;
15
+ storageAdapter?: PartialStorageAdapter;
16
+ theme?: ThemeOptions;
17
+ capabilities?: {
18
+ export?: Array<"html" | "mjml" | "react" | "json">;
19
+ };
20
+ onSendTestEmail?: (payload: {
21
+ to: string;
22
+ subject: string;
23
+ html: string;
24
+ }) => Promise<void> | void;
25
+ /**
26
+ * Render inside a shadow root (default) or directly in the page.
27
+ *
28
+ * Shadow DOM isolates the editor's styles from the host page, which is
29
+ * usually what you want. Set false when you'd rather have predictable
30
+ * DOM behaviour than isolation: inside a shadow root `event.target` is
31
+ * retargeted to the host, `document.activeElement` returns the host,
32
+ * `document.querySelector` can't see in, and `@font-face`/`@property`
33
+ * are ignored. This package handles all of that internally, but a host
34
+ * page's own scripts — or a third-party library — may not, and that is
35
+ * not fixable from inside the editor. Light DOM is the escape hatch.
36
+ *
37
+ * The trade-off is real in both directions: with `shadowDom: false`,
38
+ * the host page's CSS can reach the editor and vice versa.
39
+ */
40
+ shadowDom?: boolean;
41
+ }
42
+ export interface EditorHandle {
43
+ /** The underlying <maildeno-editor> element, for anything this handle
44
+ * doesn't wrap directly — it's a real DOM element, nothing hidden. */
45
+ readonly element: HTMLElement;
46
+ /** Vue's defineCustomElement dispatches emits as real DOM CustomEvents
47
+ * on the host element, with the emit payload in event.detail — this is
48
+ * just addEventListener with that unwrapping done for you. */
49
+ on(event: "save", handler: (payload: {
50
+ templateId: string | null;
51
+ }) => void): void;
52
+ off(event: "save", handler: (payload: {
53
+ templateId: string | null;
54
+ }) => void): void;
55
+ /** Re-themes live — sets the theme prop, which EmailEditor.vue's own
56
+ * watch(..., {immediate: true}) picks up via useHost(), the same
57
+ * mechanism that applies it on initial mount. Calling this again after
58
+ * mount is the actual "live" part, not just initial configuration. */
59
+ setTheme(theme: ThemeOptions): void;
60
+ /** These four call EmailEditor.vue's defineExpose'd methods, which Vue's
61
+ * own defineCustomElement implementation forwards directly onto the
62
+ * custom element instance (confirmed: _instance.exposed is read and
63
+ * redefined as properties on the element itself, not something Vue-
64
+ * internal or requiring a $refs-style lookup). "prune" (default)
65
+ * evaluates against the current preview context; "wrap" always
66
+ * includes every ESP-conditional branch, matching the same two modes
67
+ * the Export dropdown itself offers. */
68
+ getHtml(mode?: "prune" | "wrap"): string | null;
69
+ getMjml(mode?: "prune" | "wrap"): string | null;
70
+ getReactEmail(mode?: "prune" | "wrap"): string | null;
71
+ getJson(): Record<string, unknown> | null;
72
+ /** Removes the element from the DOM. Vue's custom element wrapper
73
+ * handles unmounting the internal app and cleaning up watchers/effects
74
+ * as part of its own disconnectedCallback — not reimplemented here. */
75
+ destroy(): void;
76
+ }
77
+ export declare function init(options: InitOptions): Promise<EditorHandle>;
78
+ export { registerBlock, getBlock, getAllBlocks, } from './blocks/registry';
79
+ export { registerESPSyntax, getRegisteredCustomESPs, } from './esp/registry';
80
+ export { registerMergeTags, getRegisteredMergeTagIds, } from './merge-tags/registry';
81
+ export { setEditorTheme, palette } from './theme';
82
+ export { createLocalStorageAdapter } from './adapters/localStorageAdapter';
83
+ export type { BlockDefinition } from './blocks/types';
84
+ export type { ThemeOptions, ThemeTokens } from './theme';
85
+ export type { EditorStorageAdapter, PartialStorageAdapter, TemplateSnapshot, TemplateSummary, SavedRow, } from './adapters/types';
package/dist/init.js ADDED
@@ -0,0 +1,130 @@
1
+ import { D as h, at as ref, i as createApp, rt as reactive } from "./vue.runtime.esm-bundler-DwQEK7WO.js";
2
+ import { a as setEditorTheme, c as createLocalStorageAdapter, d as getRegisteredMergeTagIds, f as registerMergeTags, h as registerBlock, i as palette, l as getRegisteredCustomESPs, m as getBlock, n as registerMaildenoEditorElement, p as getAllBlocks, r as EmailEditor_default, s as buildShadowStyles, u as registerESPSyntax } from "./element-DN22fZmQ.js";
3
+ //#region src/lightDom.ts
4
+ var stylesInjected = false;
5
+ /**
6
+ * The shadow path hands these strings to defineCustomElement, which turns
7
+ * them into <style> tags inside the shadow root. Here they go to
8
+ * document.head instead — same content, different destination. Guarded so
9
+ * multiple editors on one page inject once.
10
+ */
11
+ function injectStylesIntoHead() {
12
+ if (stylesInjected || typeof document === "undefined") return;
13
+ stylesInjected = true;
14
+ for (const css of buildShadowStyles()) {
15
+ if (!css) continue;
16
+ const style = document.createElement("style");
17
+ style.setAttribute("data-maildeno-light-dom", "");
18
+ style.textContent = css;
19
+ document.head.appendChild(style);
20
+ }
21
+ }
22
+ function mountLightDom(container, initialProps) {
23
+ injectStylesIntoHead();
24
+ const props = reactive({ ...initialProps });
25
+ const saveHandlers = /* @__PURE__ */ new Set();
26
+ const editorRef = ref(null);
27
+ const mountEl = document.createElement("div");
28
+ mountEl.style.height = "100%";
29
+ container.appendChild(mountEl);
30
+ const app = createApp({ setup() {
31
+ return () => h(EmailEditor_default, {
32
+ ...props,
33
+ ref: editorRef,
34
+ onSave: (payload) => saveHandlers.forEach((fn) => fn(payload))
35
+ });
36
+ } });
37
+ app.mount(mountEl);
38
+ return {
39
+ element: mountEl,
40
+ exposed: () => editorRef.value ?? null,
41
+ setProp: (key, value) => {
42
+ props[key] = value;
43
+ },
44
+ addSaveHandler: (fn) => saveHandlers.add(fn),
45
+ removeSaveHandler: (fn) => saveHandlers.delete(fn),
46
+ destroy: () => {
47
+ app.unmount();
48
+ mountEl.remove();
49
+ }
50
+ };
51
+ }
52
+ //#endregion
53
+ //#region src/init.ts
54
+ function toDomEventName(event) {
55
+ return event;
56
+ }
57
+ async function init(options) {
58
+ const container = typeof options.container === "string" ? document.querySelector(options.container) : options.container;
59
+ if (!container) throw new Error(`[maildeno-editor] init() couldn't find a container${typeof options.container === "string" ? ` matching "${options.container}"` : ""}.`);
60
+ if (options.shadowDom === false) {
61
+ const mount = mountLightDom(container, {
62
+ templateId: options.templateId,
63
+ storageAdapter: options.storageAdapter,
64
+ theme: options.theme,
65
+ capabilities: options.capabilities,
66
+ onSendTestEmail: options.onSendTestEmail
67
+ });
68
+ await new Promise((resolve) => setTimeout(resolve, 0));
69
+ const call = (name, ...args) => {
70
+ const fn = mount.exposed()?.[name];
71
+ return typeof fn === "function" ? fn(...args) : null;
72
+ };
73
+ return {
74
+ element: mount.element,
75
+ on: (_event, handler) => mount.addSaveHandler(handler),
76
+ off: (_event, handler) => mount.removeSaveHandler(handler),
77
+ setTheme: (theme) => mount.setProp("theme", theme),
78
+ getHtml: (mode = "prune") => call("getHtml", mode),
79
+ getMjml: (mode = "prune") => call("getMjml", mode),
80
+ getReactEmail: (mode = "prune") => call("getReactEmail", mode),
81
+ getJson: () => call("getJson"),
82
+ destroy: () => mount.destroy()
83
+ };
84
+ }
85
+ registerMaildenoEditorElement();
86
+ const el = document.createElement("maildeno-editor");
87
+ if (options.templateId !== void 0) el.templateId = options.templateId;
88
+ if (options.storageAdapter) el.storageAdapter = options.storageAdapter;
89
+ if (options.theme) el.theme = options.theme;
90
+ if (options.capabilities) el.capabilities = options.capabilities;
91
+ if (options.onSendTestEmail) el.onSendTestEmail = options.onSendTestEmail;
92
+ container.appendChild(el);
93
+ await new Promise((resolve) => setTimeout(resolve, 0));
94
+ const listenerWrappers = /* @__PURE__ */ new WeakMap();
95
+ return {
96
+ element: el,
97
+ on(event, handler) {
98
+ const wrapped = ((e) => handler(Array.isArray(e.detail) ? e.detail[0] : e.detail));
99
+ listenerWrappers.set(handler, wrapped);
100
+ el.addEventListener(toDomEventName(event), wrapped);
101
+ },
102
+ off(event, handler) {
103
+ const wrapped = listenerWrappers.get(handler);
104
+ if (wrapped) {
105
+ el.removeEventListener(toDomEventName(event), wrapped);
106
+ listenerWrappers.delete(handler);
107
+ }
108
+ },
109
+ setTheme(theme) {
110
+ el.theme = theme;
111
+ },
112
+ getHtml(mode = "prune") {
113
+ return el.getHtml ? el.getHtml(mode) : null;
114
+ },
115
+ getMjml(mode = "prune") {
116
+ return el.getMjml ? el.getMjml(mode) : null;
117
+ },
118
+ getReactEmail(mode = "prune") {
119
+ return el.getReactEmail ? el.getReactEmail(mode) : null;
120
+ },
121
+ getJson() {
122
+ return el.getJson ? el.getJson() : null;
123
+ },
124
+ destroy() {
125
+ el.remove();
126
+ }
127
+ };
128
+ }
129
+ //#endregion
130
+ export { createLocalStorageAdapter, getAllBlocks, getBlock, getRegisteredCustomESPs, getRegisteredMergeTagIds, init, palette, registerBlock, registerESPSyntax, registerMergeTags, setEditorTheme };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Mounts the editor directly into the page, with no shadow root.
3
+ *
4
+ * This is the `shadowDom: false` path. Shadow DOM buys style isolation,
5
+ * but it costs real behaviour: `event.target` is retargeted to the host,
6
+ * `document.activeElement` returns the host rather than the focused
7
+ * element, `document.querySelector` cannot see inside, and `@font-face`
8
+ * and `@property` are ignored entirely. Every one of those has caused a
9
+ * concrete bug in this package, and third-party libraries hit them too —
10
+ * Reka UI's own internals use `document.activeElement` and never
11
+ * `composedPath()`, so anything built on it can misbehave inside a shadow
12
+ * root in ways that cannot be fixed from the outside.
13
+ *
14
+ * Light DOM trades isolation for predictability: the host page's CSS can
15
+ * reach the editor (and vice versa), but every browser API behaves
16
+ * normally. It is the right choice when the host page's styles are known
17
+ * and controlled, and the escape hatch when something in the shadow path
18
+ * misbehaves.
19
+ */
20
+ export interface LightDomMount {
21
+ /** The element the editor was mounted into. */
22
+ element: HTMLElement;
23
+ /** Reads EmailEditor.vue's defineExpose'd methods. */
24
+ exposed: () => Record<string, any> | null;
25
+ setProp: (key: string, value: unknown) => void;
26
+ addSaveHandler: (fn: (payload: any) => void) => void;
27
+ removeSaveHandler: (fn: (payload: any) => void) => void;
28
+ destroy: () => void;
29
+ }
30
+ export declare function mountLightDom(container: HTMLElement, initialProps: Record<string, unknown>): LightDomMount;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Confirmed against the real pipeline (mergeTagMapper.ts's transformToken):
3
+ * any tag ID not in the hardcoded SYSTEM_TAG_MAP already falls through to
4
+ * transformCustomTag, which handles arbitrary tag names generically for
5
+ * all known ESP syntaxes — this was already true before this registry
6
+ * existed (see the "Zero Vendor Lock-in" note in mergeTagMapper.ts).
7
+ *
8
+ * So registering a merge tag isn't fixing a correctness gap the way the
9
+ * ESP registry was. It solves a narrower, real problem: getSystemTagIds()
10
+ * only returns SYSTEM_TAG_MAP's hardcoded keys, so a host's own fields
11
+ * (order_total, loyalty_points, ...) never show up in the "Common tags"
12
+ * picker UI — a user would have to already know to type {{ order_total }}
13
+ * by hand. This registry makes registered tags discoverable there.
14
+ *
15
+ * Optional per-ESP token overrides exist for the rare case a custom tag
16
+ * needs something other than the generic transform (e.g. a genuinely
17
+ * ESP-specific system-level token) — most registrations won't need them.
18
+ */
19
+ export interface MergeTagRegistration {
20
+ key: string;
21
+ /** Optional — omit to use the existing generic transformCustomTag path
22
+ * for every ESP syntax, which is already correct for ordinary data
23
+ * fields. Only provide this for a tag that needs ESP-specific hardcoded
24
+ * tokens, the same category SYSTEM_TAG_MAP covers for built-ins. */
25
+ tokens?: Partial<Record<string, string>>;
26
+ }
27
+ export declare function registerMergeTags(tags: MergeTagRegistration[]): void;
28
+ /** Custom-registered IDs, appended after the built-ins for the picker UI. */
29
+ export declare function getRegisteredMergeTagIds(): string[];
30
+ /** Only returns a value for tags that were registered WITH explicit token
31
+ * overrides — most registered tags return undefined here on purpose, so
32
+ * transformToken's existing transformCustomTag fallback handles them. */
33
+ export declare function getRegisteredMergeTagToken(tagId: string, syntax: string): string | undefined;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * False when running from source, where the build-time substitution above
3
+ * never ran and the shadow root therefore has no component CSS. Used to
4
+ * decide whether the dev style mirror is needed — a capability check rather
5
+ * than an environment guess, so it self-corrects in either direction.
6
+ */
7
+ export declare function hasExtractedScopedCss(): boolean;
8
+ export declare function buildShadowStyles(): string[];