@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
@@ -0,0 +1,16 @@
1
+ export interface HistorySnapshot<T> {
2
+ state: T;
3
+ action: string;
4
+ timestamp: number;
5
+ }
6
+ export declare const useHistory: <T = unknown>() => {
7
+ canUndo: import('vue').ComputedRef<boolean>;
8
+ canRedo: import('vue').ComputedRef<boolean>;
9
+ historyStatus: import('vue').ComputedRef<string>;
10
+ saveState: (state: T, action?: string, immediate?: boolean) => void;
11
+ undo: () => T | null;
12
+ redo: () => T | null;
13
+ clearHistory: () => void;
14
+ initHistory: (initialState: T) => void;
15
+ version: import('vue').Ref<number, number>;
16
+ };
@@ -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,127 @@
1
+ export type ClientPlatform = "web" | "desktop" | "mobile";
2
+ export type DarkModeStrategy = "respects-meta" | "near-black-swap" | "partial-transparent" | "none";
3
+ export interface ClientCapabilities {
4
+ /** @font-face / Google Fonts <link> support. Falls back to the next
5
+ * font in the `font-family` stack (typically Arial) when false. */
6
+ webFonts: boolean;
7
+ /** CSS gradients (linear / radial) on <td> background. Outlook desktop
8
+ * needs VML for these — see `vml` below. */
9
+ gradients: boolean;
10
+ /** border-radius on <td>. Note: border-radius on <a> (your button output)
11
+ * works much more broadly — even Outlook desktop renders rounded <a>
12
+ * buttons since 2016 via the -webkit-border-radius alias. Use
13
+ * `buttonBorderRadius` for the button-specific capability. */
14
+ tdBorderRadius: boolean;
15
+ /** border-radius on <a> elements styled as inline-block buttons.
16
+ * Outlook desktop SUPPORTS this (since 2016 webkit). */
17
+ buttonBorderRadius: boolean;
18
+ /** box-shadow on <td> or <div>. Rare — only modern WebKit clients. */
19
+ boxShadow: boolean;
20
+ /** background-image / `background="..."` attribute on <td>. */
21
+ bgImageOnTd: boolean;
22
+ /** VML rendering — required for gradients and bg images in Outlook desktop.
23
+ * When false, gradient/bg fallback to the solid `backgroundColor`. */
24
+ vml: boolean;
25
+ /** Honors <!--[if mso]> conditional comments. Used to feed Outlook
26
+ * VML-only fallbacks. Universal Microsoft trait. */
27
+ msoConditionals: boolean;
28
+ /** Animated GIF support. Outlook desktop shows first frame only. */
29
+ animatedGifs: boolean;
30
+ /** <video> tag in email. Only Apple Mail and iOS Mail render this. */
31
+ videoTag: boolean;
32
+ /** SVG as <img src="*.svg">. Renders in all modern clients including
33
+ * Outlook desktop (verified by QA) — file extension doesn't affect
34
+ * rendering once the image is fetched via HTTP and decoded. */
35
+ svgImg: boolean;
36
+ /** Retina / 2x images via srcset / width attribute. */
37
+ retinaImages: boolean;
38
+ /** @media (max-width: 600px) query support for responsive design.
39
+ * Outlook desktop classic ignores all <style> tags entirely. */
40
+ mediaQueries: boolean;
41
+ /** <style> tag in <head> respected at all. Gmail web strips it from
42
+ * <head> but keeps inline styles. */
43
+ embeddedStyles: boolean;
44
+ /** `align="center"` attribute on <table> and `<td>`. Universal. */
45
+ tableAlign: boolean;
46
+ /** `padding` style on <td>. Universal in practice, but Outlook desktop
47
+ * measures padding differently — included for completeness. */
48
+ tdPadding: boolean;
49
+ darkModeStrategy: DarkModeStrategy;
50
+ }
51
+ export interface EmailClient {
52
+ id: string;
53
+ name: string;
54
+ vendor: string;
55
+ platform: ClientPlatform;
56
+ /** Engine that powers rendering. */
57
+ engine: string;
58
+ /** Approximate global market share (%). For sorting; not displayed as fact. */
59
+ marketShare?: number;
60
+ /** Brand accent color for the client tile. */
61
+ accentColor: string;
62
+ /** Single emoji or short identifier shown in the card avatar. */
63
+ logoText: string;
64
+ capabilities: ClientCapabilities;
65
+ /** Maximum content width the client renders at (chrome-excluded). */
66
+ viewportWidth: number;
67
+ /** Short human description for tooltip / detail header. */
68
+ description: string;
69
+ /** When previewing on this client, treat the layout as mobile (forces
70
+ * mobile-only CSS classes to apply and triggers `mobileStack` if set). */
71
+ forcesMobile: boolean;
72
+ }
73
+ declare function hydrateFromStorage(): void;
74
+ export declare function useClientPreview(): {
75
+ selectedClients: import('vue').ComputedRef<EmailClient[]>;
76
+ availableClients: import('vue').ComputedRef<EmailClient[]>;
77
+ allClients: readonly {
78
+ readonly id: string;
79
+ readonly name: string;
80
+ readonly vendor: string;
81
+ readonly platform: ClientPlatform;
82
+ readonly engine: string;
83
+ readonly marketShare?: number | undefined;
84
+ readonly accentColor: string;
85
+ readonly logoText: string;
86
+ readonly capabilities: {
87
+ readonly webFonts: boolean;
88
+ readonly gradients: boolean;
89
+ readonly tdBorderRadius: boolean;
90
+ readonly buttonBorderRadius: boolean;
91
+ readonly boxShadow: boolean;
92
+ readonly bgImageOnTd: boolean;
93
+ readonly vml: boolean;
94
+ readonly msoConditionals: boolean;
95
+ readonly animatedGifs: boolean;
96
+ readonly videoTag: boolean;
97
+ readonly svgImg: boolean;
98
+ readonly retinaImages: boolean;
99
+ readonly mediaQueries: boolean;
100
+ readonly embeddedStyles: boolean;
101
+ readonly tableAlign: boolean;
102
+ readonly tdPadding: boolean;
103
+ readonly darkModeStrategy: DarkModeStrategy;
104
+ };
105
+ readonly viewportWidth: number;
106
+ readonly description: string;
107
+ readonly forcesMobile: boolean;
108
+ }[];
109
+ activeClientId: Readonly<import('vue').Ref<string | null, string | null>>;
110
+ activeClient: import('vue').ComputedRef<EmailClient | null>;
111
+ activeClientIndex: import('vue').ComputedRef<number>;
112
+ hasNext: import('vue').ComputedRef<boolean>;
113
+ hasPrev: import('vue').ComputedRef<boolean>;
114
+ isHydrated: Readonly<import('vue').Ref<boolean, boolean>>;
115
+ addClient: (id: string) => void;
116
+ removeClient: (id: string) => void;
117
+ setActiveClient: (id: string | null) => void;
118
+ goToNextClient: () => void;
119
+ goToPrevClient: () => void;
120
+ resetToDefaults: () => void;
121
+ hydrateFromStorage: typeof hydrateFromStorage;
122
+ transformForClient: (html: string, client: EmailClient) => string;
123
+ darkModeCss: (client: EmailClient, isDark: boolean) => string;
124
+ darkChromeBg: (isDark: boolean) => string;
125
+ applyDarkModeDom: (doc: Document | null | undefined, client: EmailClient, isDark: boolean) => void;
126
+ };
127
+ export {};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * hydrate.ts
3
+ * Restores stripped defaults when importing an optimized JSON template.
4
+ *
5
+ * Strategy: deepMerge(DEFAULTS, saved) — saved value always wins;
6
+ * stripped keys fall back to current defaults automatically.
7
+ *
8
+ * Now supports both new `children` shape and legacy `components` shape per column.
9
+ * On hydration, columns are always written with `children` going forward.
10
+ */
11
+ interface Component {
12
+ id: string;
13
+ type: string;
14
+ componentType?: string;
15
+ props: Record<string, unknown>;
16
+ }
17
+ type CanvasChild = Component | NestedRow | RowSpacer;
18
+ interface Column {
19
+ id: string;
20
+ width: number;
21
+ children?: CanvasChild[];
22
+ components?: Component[];
23
+ [key: string]: unknown;
24
+ }
25
+ interface NestedRow {
26
+ id: string;
27
+ type: "row";
28
+ columns?: Column[];
29
+ [key: string]: unknown;
30
+ }
31
+ interface RowSpacer {
32
+ id: string;
33
+ type: "row-spacer";
34
+ [key: string]: unknown;
35
+ }
36
+ type Row = NestedRow | RowSpacer;
37
+ interface Canvas {
38
+ language?: string;
39
+ preheaderText?: string;
40
+ bodyBackgroundColor?: string;
41
+ bodyBackgroundImage?: string;
42
+ bodyBackgroundSize?: string;
43
+ bodyBackgroundPosition?: string;
44
+ bodyBackgroundRepeat?: string;
45
+ backgroundColor?: string;
46
+ width?: number;
47
+ padding?: Record<string, number>;
48
+ mobileBreakpoint?: number;
49
+ [key: string]: unknown;
50
+ }
51
+ export declare const hydrateComponent: (comp: Component) => Component;
52
+ export declare const hydrateCanvas: (canvas: Canvas) => Canvas;
53
+ export declare const hydrateRows: (rows: Row[]) => Row[];
54
+ export {};
@@ -0,0 +1,101 @@
1
+ /**
2
+ * optimize.ts
3
+ * Strips default/noise values from rows, columns, components, and canvas before
4
+ * JSON export. Pairs with hydrate.ts — everything stripped here is restored on import.
5
+ *
6
+ * Supports both new `children` shape and legacy `components` shape per column.
7
+ */
8
+ interface VisibilityConfig {
9
+ enabled: boolean;
10
+ match: "all" | "any";
11
+ rules: unknown[];
12
+ }
13
+ interface BorderConfig {
14
+ width: number;
15
+ style: string;
16
+ color: string;
17
+ radius?: number;
18
+ }
19
+ interface GradientConfig {
20
+ useGradient: boolean;
21
+ solid: string;
22
+ gradient: {
23
+ type: "linear" | "radial";
24
+ direction: string;
25
+ colors: Array<{
26
+ color: string;
27
+ position: number;
28
+ }>;
29
+ };
30
+ }
31
+ interface Component {
32
+ id: string;
33
+ /** New discriminated shape uses "component"; legacy uses the componentType directly */
34
+ type: string;
35
+ /** Present when type === "component" */
36
+ componentType?: string;
37
+ props: Record<string, unknown>;
38
+ }
39
+ type CanvasChild = Component | NestedRow | RowSpacer;
40
+ interface Column {
41
+ id: string;
42
+ width: number;
43
+ /** New shape */
44
+ children?: CanvasChild[];
45
+ /** Legacy shape — kept for backward compat */
46
+ components?: Component[];
47
+ backgroundColor?: string;
48
+ backgroundGradient?: GradientConfig;
49
+ backgroundImage?: string;
50
+ backgroundSize?: string;
51
+ backgroundPosition?: string;
52
+ backgroundRepeat?: string;
53
+ padding?: Record<string, number>;
54
+ border?: BorderConfig;
55
+ verticalAlign?: string;
56
+ [key: string]: unknown;
57
+ }
58
+ export interface NestedRow {
59
+ id: string;
60
+ type: "row";
61
+ name?: string;
62
+ columns?: Column[];
63
+ visibility?: VisibilityConfig;
64
+ border?: BorderConfig;
65
+ backgroundImage?: string;
66
+ backgroundSize?: string;
67
+ backgroundPosition?: string;
68
+ backgroundRepeat?: string;
69
+ padding?: Record<string, number>;
70
+ backgroundGradient?: GradientConfig;
71
+ minHeight?: number;
72
+ [key: string]: unknown;
73
+ }
74
+ export interface RowSpacer {
75
+ id: string;
76
+ type: "row-spacer";
77
+ name?: string;
78
+ height?: number;
79
+ backgroundColor?: string;
80
+ backgroundGradient?: GradientConfig;
81
+ visibility?: VisibilityConfig;
82
+ [key: string]: unknown;
83
+ }
84
+ type Row = NestedRow | RowSpacer;
85
+ export interface Canvas {
86
+ language?: string;
87
+ preheaderText?: string;
88
+ bodyBackgroundColor?: string;
89
+ bodyBackgroundImage?: string;
90
+ bodyBackgroundSize?: string;
91
+ bodyBackgroundPosition?: string;
92
+ bodyBackgroundRepeat?: string;
93
+ backgroundColor?: string;
94
+ width?: number;
95
+ padding?: Record<string, number>;
96
+ mobileBreakpoint?: number;
97
+ [key: string]: unknown;
98
+ }
99
+ export declare const optimizeCanvas: (canvas: Canvas) => Partial<Canvas>;
100
+ export declare const optimizeRows: (rows: Row[]) => Partial<Row>[];
101
+ export {};
@@ -0,0 +1,125 @@
1
+ /**
2
+ * optimizeAI.ts
3
+ * AI-facing counterpart to optimize.ts. Strips default/noise values from
4
+ * rows, columns, components, and canvas before building the snapshot sent
5
+ * to the AI model — separate pipeline so it can strip more aggressively
6
+ * than the JSON-export pipeline without the two compromising each other.
7
+ *
8
+ * optimize.ts / hydrate.ts are NOT modified by this file and are unaffected.
9
+ *
10
+ * Two different kinds of "default" are handled differently, on purpose:
11
+ *
12
+ * - STATELESS style props (margin, padding, border, letterSpacing, ...):
13
+ * no "user chose to remove this" meaning attached — just set vs. unset.
14
+ * Diffed against each component TYPE's real default via
15
+ * useEmailBuilderDefaults(), so this never drifts out of sync the way a
16
+ * hardcoded universal check (e.g. "is it all-zero") can for component
17
+ * types whose real default isn't zero. The AI doesn't lose anything by
18
+ * these being stripped: schemaBlock() in useEmailAIPrompts.ts already
19
+ * tells it every prop + its default, independent of what's in the
20
+ * snapshot. Snapshot = the diff; schema = the full menu.
21
+ *
22
+ * - SELECTION-style fields (socials platforms, mobile overrides, the icon
23
+ * cluster): reflect a deliberate choice, not just set-vs-unset. Mirrored
24
+ * EXACTLY from optimize.ts's existing logic, unchanged, so this pipeline
25
+ * respects the same choices the export pipeline already does.
26
+ *
27
+ * Restoring what gets stripped here needs no new hydrate-side code: hydrate.ts's
28
+ * hydrateComponent() already deep-merges against each type's real defaults
29
+ * (via the same useEmailBuilderDefaults()), so it already restores anything
30
+ * this file strips. See useEmailAISnapshot.ts's existing hydrateAIRows /
31
+ * hydrateAIRow / hydrateAIComponent — those remain the AI hydration path,
32
+ * unchanged.
33
+ */
34
+ interface VisibilityConfig {
35
+ enabled: boolean;
36
+ match: "all" | "any";
37
+ rules: unknown[];
38
+ }
39
+ interface BorderConfig {
40
+ width: number;
41
+ style: string;
42
+ color: string;
43
+ radius?: number;
44
+ }
45
+ interface GradientConfig {
46
+ useGradient: boolean;
47
+ solid: string;
48
+ gradient: {
49
+ type: "linear" | "radial";
50
+ direction: string;
51
+ colors: Array<{
52
+ color: string;
53
+ position: number;
54
+ }>;
55
+ };
56
+ }
57
+ interface Component {
58
+ id: string;
59
+ type: string;
60
+ componentType?: string;
61
+ props: Record<string, unknown>;
62
+ }
63
+ type CanvasChild = Component | NestedRow | RowSpacer;
64
+ interface Column {
65
+ id: string;
66
+ width: number;
67
+ children?: CanvasChild[];
68
+ components?: Component[];
69
+ backgroundColor?: string;
70
+ backgroundGradient?: GradientConfig;
71
+ backgroundImage?: string;
72
+ backgroundSize?: string;
73
+ backgroundPosition?: string;
74
+ backgroundRepeat?: string;
75
+ padding?: Record<string, number>;
76
+ border?: BorderConfig;
77
+ verticalAlign?: string;
78
+ [key: string]: unknown;
79
+ }
80
+ interface NestedRow {
81
+ id: string;
82
+ type: "row";
83
+ name?: string;
84
+ columns?: Column[];
85
+ visibility?: VisibilityConfig;
86
+ border?: BorderConfig;
87
+ backgroundColor?: string;
88
+ backgroundImage?: string;
89
+ backgroundSize?: string;
90
+ backgroundPosition?: string;
91
+ backgroundRepeat?: string;
92
+ padding?: Record<string, number>;
93
+ backgroundGradient?: GradientConfig;
94
+ minHeight?: number;
95
+ gap?: number;
96
+ [key: string]: unknown;
97
+ }
98
+ interface RowSpacer {
99
+ id: string;
100
+ type: "row-spacer";
101
+ name?: string;
102
+ height?: number;
103
+ backgroundColor?: string;
104
+ backgroundGradient?: GradientConfig;
105
+ visibility?: VisibilityConfig;
106
+ [key: string]: unknown;
107
+ }
108
+ type Row = NestedRow | RowSpacer;
109
+ interface Canvas {
110
+ language?: string;
111
+ preheaderText?: string;
112
+ bodyBackgroundColor?: string;
113
+ bodyBackgroundImage?: string;
114
+ bodyBackgroundSize?: string;
115
+ bodyBackgroundPosition?: string;
116
+ bodyBackgroundRepeat?: string;
117
+ backgroundColor?: string;
118
+ width?: number;
119
+ padding?: Record<string, number>;
120
+ mobileBreakpoint?: number;
121
+ [key: string]: unknown;
122
+ }
123
+ export declare const optimizeCanvasForAI: (canvas: Canvas) => Partial<Canvas>;
124
+ export declare const optimizeRowsForAI: (rows: Row[]) => Partial<Row>[];
125
+ export {};
@@ -0,0 +1,79 @@
1
+ export interface Padding {
2
+ top: number;
3
+ right: number;
4
+ bottom: number;
5
+ left: number;
6
+ }
7
+ export interface Border {
8
+ width: number;
9
+ style: string;
10
+ color: string;
11
+ radius: number;
12
+ }
13
+ export interface GradientStop {
14
+ color: string;
15
+ position: number;
16
+ }
17
+ export interface Gradient {
18
+ type: "linear" | "radial";
19
+ direction: string;
20
+ colors: GradientStop[];
21
+ }
22
+ export interface BackgroundGradient {
23
+ useGradient: boolean;
24
+ solid: string;
25
+ gradient: Gradient;
26
+ }
27
+ export interface Visibility {
28
+ [conditionKey: string]: any;
29
+ }
30
+ export type CanvasChild = CanvasComponentNode | CanvasRowNode | CanvasSpacerNode;
31
+ export interface CanvasComponentNode {
32
+ id: string;
33
+ type: "component";
34
+ componentType: string;
35
+ props: Record<string, any>;
36
+ visibility?: Visibility;
37
+ }
38
+ export interface CanvasRowNode {
39
+ id: string;
40
+ type: "row";
41
+ name: string;
42
+ columns: CanvasColumn[];
43
+ backgroundColor: string;
44
+ backgroundGradient: BackgroundGradient;
45
+ backgroundImage?: string;
46
+ backgroundSize?: string;
47
+ backgroundPosition?: string;
48
+ backgroundRepeat?: string;
49
+ padding: Padding;
50
+ border: Border;
51
+ minHeight: number;
52
+ gap: number;
53
+ mobileStack: boolean;
54
+ visibility: Visibility;
55
+ }
56
+ export interface CanvasSpacerNode {
57
+ id: string;
58
+ type: "row-spacer";
59
+ name: string;
60
+ height: number;
61
+ backgroundColor: string;
62
+ backgroundGradient: BackgroundGradient;
63
+ visibility: Visibility;
64
+ }
65
+ export interface CanvasColumn {
66
+ id: string;
67
+ width: number;
68
+ children: CanvasChild[];
69
+ backgroundColor: string;
70
+ backgroundGradient: BackgroundGradient;
71
+ backgroundImage?: string;
72
+ backgroundSize?: string;
73
+ backgroundPosition?: string;
74
+ backgroundRepeat?: string;
75
+ padding: Padding;
76
+ border: Border;
77
+ verticalAlign: "top" | "middle" | "bottom";
78
+ }
79
+ export type TopLevelRow = CanvasRowNode | CanvasSpacerNode;
@@ -0,0 +1,26 @@
1
+ type RGB = [number, number, number];
2
+ export declare function useColor(initial?: string): {
3
+ h: import('vue').Ref<number, number>;
4
+ s: import('vue').Ref<number, number>;
5
+ v: import('vue').Ref<number, number>;
6
+ a: import('vue').Ref<number, number>;
7
+ rgb: import('vue').ComputedRef<RGB>;
8
+ hex: import('vue').ComputedRef<string>;
9
+ rgba: import('vue').ComputedRef<string>;
10
+ cssColor: import('vue').ComputedRef<string>;
11
+ hsl: import('vue').ComputedRef<{
12
+ h: number;
13
+ s: number;
14
+ l: number;
15
+ }>;
16
+ hsb: import('vue').ComputedRef<{
17
+ h: number;
18
+ s: number;
19
+ b: number;
20
+ }>;
21
+ setFromHex: (hexVal: string) => boolean;
22
+ setFromRgb: (r: number, g: number, b: number) => void;
23
+ setFromHsl: (hh: number, ss: number, ll: number) => void;
24
+ setFromHsb: (hh: number, ss: number, bb: number) => void;
25
+ };
26
+ export {};
@@ -0,0 +1,5 @@
1
+ import { Ref } from 'vue';
2
+ export declare const useDeviceDetection: () => {
3
+ isDesktop: Ref<boolean, boolean>;
4
+ isMobile: import('vue').ComputedRef<boolean>;
5
+ };
@@ -0,0 +1,11 @@
1
+ export declare const useGoogleFonts: () => {
2
+ googleFonts: import('vue').Ref<string[], string[]>;
3
+ loadGoogleFont: (fontFamily?: string) => void;
4
+ getGoogleFontImports: (fonts: string[]) => string;
5
+ syncFontsForTemplate: (fonts: string[]) => void;
6
+ preconnectGoogleFonts: () => void;
7
+ isWebSafeFont: (font: string) => boolean;
8
+ WEB_SAFE_FONTS: Set<string>;
9
+ FONTS_WITH_ITALICS: Set<string>;
10
+ DEFAULT_WEIGHTS: number[];
11
+ };
@@ -0,0 +1,23 @@
1
+ export interface UploadResult {
2
+ previewUrl: string;
3
+ permanentUrl: string;
4
+ cleanup: () => void;
5
+ }
6
+ export declare class ImageUploadError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ export declare function validateImageFile(file: File): void;
10
+ export declare function swapOnLoad(permanentUrl: string, onReady: () => void, cleanup: () => void): void;
11
+ /**
12
+ * Called from within a component's setup — useStorageAdapter() requires
13
+ * that timing, which is why this is a composable rather than a plain
14
+ * export like the three functions above (none of which need injection).
15
+ *
16
+ * Returns handleImageUploadFlow pre-bound to the active adapter, so call
17
+ * sites keep the exact same 4-argument call shape they always had.
18
+ */
19
+ export declare function useImageUploader(): {
20
+ handleImageUploadFlow: (file: File, onPreview: (objectUrl: string) => void, onSuccess: (permanentUrl: string, cleanup: () => void) => void, onError: (message: string) => void) => Promise<void>;
21
+ swapOnLoad: typeof swapOnLoad;
22
+ validateImageFile: typeof validateImageFile;
23
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared open/close state for the Saved Rows panel.
3
+ *
4
+ * this used to be Nuxt's useState, shared across components by
5
+ * matching string key. Same provide/inject conversion as useEmailBuilder —
6
+ * one instance created at the EmailEditor root, injected everywhere else,
7
+ * so LayoutTab's toggle button and SavedRowsPanel's isOpen check still see
8
+ * the same boolean.
9
+ *
10
+ * The "system" tab concept was removed from SavedRowsPanel.vue
11
+ * (see its top-of-file note) — activeTab is kept here since LayoutTab still
12
+ * references the shape, but it's permanently "user" now in practice.
13
+ */
14
+ export type SavedRowsTab = "user" | "system";
15
+ type SavedRowsPanelInstance = ReturnType<typeof createSavedRowsPanelInstance>;
16
+ /** Called once, at the EmailEditor root. */
17
+ export declare function provideSavedRowsPanel(): {
18
+ isOpen: import('vue').Ref<boolean, boolean>;
19
+ activeTab: import('vue').Ref<SavedRowsTab, SavedRowsTab>;
20
+ open: (tab?: SavedRowsTab) => void;
21
+ close: () => void;
22
+ toggle: (tab?: SavedRowsTab) => void;
23
+ setTab: (tab: SavedRowsTab) => void;
24
+ };
25
+ /** Every other file calls this exactly as before. */
26
+ export declare const useSavedRowsPanel: () => SavedRowsPanelInstance;
27
+ declare function createSavedRowsPanelInstance(): {
28
+ isOpen: import('vue').Ref<boolean, boolean>;
29
+ activeTab: import('vue').Ref<SavedRowsTab, SavedRowsTab>;
30
+ open: (tab?: SavedRowsTab) => void;
31
+ close: () => void;
32
+ toggle: (tab?: SavedRowsTab) => void;
33
+ setTab: (tab: SavedRowsTab) => void;
34
+ };
35
+ export {};
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Confirmation dialog store.
3
+ *
4
+ * Module-level singleton state rather than provide/inject, deliberately.
5
+ * An injected service has two failure modes this avoids: it can't be read
6
+ * from the same component that provides it (Vue's inject() never sees the
7
+ * current component's own provide()), and two copies of the providing
8
+ * module produce two different injection keys for what should be one
9
+ * store. A module-scoped ref has neither problem — one store, no keys, no
10
+ * dependency on where in the tree the caller sits — so it behaves
11
+ * identically however the editor is mounted.
12
+ */
13
+ export interface ConfirmOptions {
14
+ message?: string;
15
+ header?: string;
16
+ acceptLabel?: string;
17
+ rejectLabel?: string;
18
+ acceptClass?: string;
19
+ rejectClass?: string;
20
+ accept?: () => void;
21
+ reject?: () => void;
22
+ }
23
+ /** Null when nothing is pending — ConfirmDialog.vue renders on this. */
24
+ export declare const activeConfirm: import('vue').ShallowRef<ConfirmOptions | null, ConfirmOptions | null>;
25
+ export declare const confirmVisible: import('vue').Ref<boolean, boolean>;
26
+ declare function close(): void;
27
+ export declare function acceptActive(): void;
28
+ export declare function rejectActive(): void;
29
+ export declare function useConfirm(): {
30
+ require(options: ConfirmOptions): void;
31
+ close: typeof close;
32
+ };
33
+ export {};