@marlinjai/email-editor 0.2.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.
- package/LICENSE +21 -0
- package/README.md +328 -0
- package/dist/chunk-EFHKH3BN.mjs +47 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +173 -0
- package/dist/index.mjs +112 -0
- package/dist/react.d.mts +51 -0
- package/dist/react.d.ts +51 -0
- package/dist/react.js +125 -0
- package/dist/react.mjs +62 -0
- package/dist/styles.css +3 -0
- package/dist/types-BoNyjNFe.d.mts +42 -0
- package/dist/types-BoNyjNFe.d.ts +42 -0
- package/dist/types-G7Ak2dWQ.d.mts +117 -0
- package/dist/types-G7Ak2dWQ.d.ts +117 -0
- package/package.json +79 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { EmailTemplate, BlockDefinition } from '@marlinjai/email-editor-core';
|
|
2
|
+
import { OnRequestImage } from '@marlinjai/email-editor-ui';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Editor theme: brand colors and the UI font of the editor chrome. Each value
|
|
6
|
+
* sets one design token on the editor's root element; anything left out keeps
|
|
7
|
+
* the default. Every token (`--ee-*`) can also be overridden in the host's CSS
|
|
8
|
+
* on `.ee-root`, outside any cascade layer.
|
|
9
|
+
*/
|
|
10
|
+
interface EditorTheme {
|
|
11
|
+
colors?: {
|
|
12
|
+
/** Accent: primary buttons, selection, focus rings (`--ee-accent`) */
|
|
13
|
+
primary?: string;
|
|
14
|
+
/** Accent on hover (`--ee-accent-hover`) */
|
|
15
|
+
primaryHover?: string;
|
|
16
|
+
/** Light panel surfaces (`--ee-canvas-2`) */
|
|
17
|
+
surface?: string;
|
|
18
|
+
/** Text on light surfaces (`--ee-text-dark`) */
|
|
19
|
+
text?: string;
|
|
20
|
+
/** Borders on light surfaces (`--ee-border-light`) */
|
|
21
|
+
border?: string;
|
|
22
|
+
};
|
|
23
|
+
fonts?: {
|
|
24
|
+
/** Font stack of the editor chrome (`--ee-font-sans`) */
|
|
25
|
+
body?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Editor configuration options
|
|
30
|
+
*/
|
|
31
|
+
interface EditorOptions {
|
|
32
|
+
container: HTMLElement;
|
|
33
|
+
initialValue?: EmailTemplate;
|
|
34
|
+
theme?: EditorTheme;
|
|
35
|
+
/** Redefine standard block types (label, icon, category, default props). New types are refused. */
|
|
36
|
+
blocks?: BlockDefinition[];
|
|
37
|
+
onChange?: (template: EmailTemplate) => void;
|
|
38
|
+
onSave?: (template: EmailTemplate) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Supply images from your own picker or uploader. Resolve with
|
|
41
|
+
* `{ url, alt? }`, or `null` when the user cancels (the block is left
|
|
42
|
+
* unchanged). A rejected promise is shown inline in the image inspector.
|
|
43
|
+
* Without it, the image inspector shows a plain URL field.
|
|
44
|
+
*/
|
|
45
|
+
onRequestImage?: OnRequestImage;
|
|
46
|
+
/**
|
|
47
|
+
* The sections this workspace has saved, offered in the section picker
|
|
48
|
+
* beside the built-in ones, under their own group.
|
|
49
|
+
*
|
|
50
|
+
* Optional: a host that passes none gets exactly the built-in library, which
|
|
51
|
+
* is what a standalone consumer of this package gets today.
|
|
52
|
+
*/
|
|
53
|
+
savedSections?: SavedSectionInput[];
|
|
54
|
+
/**
|
|
55
|
+
* Whether to offer the 35 sections that ship with this package (a hero, a
|
|
56
|
+
* few content and feature layouts, events, coupons, products, signatures and
|
|
57
|
+
* footers). True by default, which is what a workspace with nothing saved
|
|
58
|
+
* yet needs: an empty picker is a worse first run than a generic one.
|
|
59
|
+
*
|
|
60
|
+
* Pass false to offer only `savedSections`, which is what a host with its own
|
|
61
|
+
* library wants. The built-in set is brand neutral by construction (grey
|
|
62
|
+
* palette, fonts every mail client has, placeholder copy naming nobody, and
|
|
63
|
+
* `data:` URI images, so a workspace whose `asset_policy` is `service_only`
|
|
64
|
+
* can send them); turning them off is about whose library it is, not about
|
|
65
|
+
* whether they are safe to show.
|
|
66
|
+
*/
|
|
67
|
+
builtInSections?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* The origin the editor's placeholder images are served from, with no
|
|
70
|
+
* trailing slash, e.g. `https://mail.example.com`. Each becomes
|
|
71
|
+
* `<base>/p/<width>x<height>.png`.
|
|
72
|
+
*
|
|
73
|
+
* Give it whenever the documents this editor produces are going to be sent.
|
|
74
|
+
* Without it every placeholder is a `data:` URI, which renders in the canvas
|
|
75
|
+
* but which Gmail and Outlook.com do not render at all, and which a workspace
|
|
76
|
+
* that only allows its own service's addresses may not be able to replace.
|
|
77
|
+
*/
|
|
78
|
+
placeholderBase?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Keep a section for reuse. When set, a section's controls on the canvas
|
|
81
|
+
* carry a "Save as a section" action, which asks for a name (refusing one
|
|
82
|
+
* already in `savedSections`) and calls this with the section as plain data.
|
|
83
|
+
*
|
|
84
|
+
* Resolve when it is stored; a rejection is shown in the dialog with the
|
|
85
|
+
* error's message and the dialog stays open. Without it no action appears,
|
|
86
|
+
* rather than one that fails.
|
|
87
|
+
*
|
|
88
|
+
* The editor does not reload `savedSections` afterwards: the host owns that
|
|
89
|
+
* list and passes a new one when it has stored the section.
|
|
90
|
+
*/
|
|
91
|
+
onSaveSection?: (section: Record<string, unknown>, name: string) => Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* One saved section as the host holds it. The `section` is a snapshot of a
|
|
95
|
+
* single section of a document; inserting it rebuilds every id, so the same
|
|
96
|
+
* saved section can go into one document twice.
|
|
97
|
+
*/
|
|
98
|
+
interface SavedSectionInput {
|
|
99
|
+
id: string;
|
|
100
|
+
name: string;
|
|
101
|
+
description?: string;
|
|
102
|
+
section: Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Editor instance API
|
|
106
|
+
*/
|
|
107
|
+
interface EditorInstance {
|
|
108
|
+
getValue(): EmailTemplate;
|
|
109
|
+
setValue(template: EmailTemplate): void;
|
|
110
|
+
getHTML(): string;
|
|
111
|
+
getMJML(): string;
|
|
112
|
+
undo(): void;
|
|
113
|
+
redo(): void;
|
|
114
|
+
destroy(): void;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type { EditorOptions as E, SavedSectionInput as S, EditorInstance as a, EditorTheme as b };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { EmailTemplate, BlockDefinition } from '@marlinjai/email-editor-core';
|
|
2
|
+
import { OnRequestImage } from '@marlinjai/email-editor-ui';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Editor theme: brand colors and the UI font of the editor chrome. Each value
|
|
6
|
+
* sets one design token on the editor's root element; anything left out keeps
|
|
7
|
+
* the default. Every token (`--ee-*`) can also be overridden in the host's CSS
|
|
8
|
+
* on `.ee-root`, outside any cascade layer.
|
|
9
|
+
*/
|
|
10
|
+
interface EditorTheme {
|
|
11
|
+
colors?: {
|
|
12
|
+
/** Accent: primary buttons, selection, focus rings (`--ee-accent`) */
|
|
13
|
+
primary?: string;
|
|
14
|
+
/** Accent on hover (`--ee-accent-hover`) */
|
|
15
|
+
primaryHover?: string;
|
|
16
|
+
/** Light panel surfaces (`--ee-canvas-2`) */
|
|
17
|
+
surface?: string;
|
|
18
|
+
/** Text on light surfaces (`--ee-text-dark`) */
|
|
19
|
+
text?: string;
|
|
20
|
+
/** Borders on light surfaces (`--ee-border-light`) */
|
|
21
|
+
border?: string;
|
|
22
|
+
};
|
|
23
|
+
fonts?: {
|
|
24
|
+
/** Font stack of the editor chrome (`--ee-font-sans`) */
|
|
25
|
+
body?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Editor configuration options
|
|
30
|
+
*/
|
|
31
|
+
interface EditorOptions {
|
|
32
|
+
container: HTMLElement;
|
|
33
|
+
initialValue?: EmailTemplate;
|
|
34
|
+
theme?: EditorTheme;
|
|
35
|
+
/** Redefine standard block types (label, icon, category, default props). New types are refused. */
|
|
36
|
+
blocks?: BlockDefinition[];
|
|
37
|
+
onChange?: (template: EmailTemplate) => void;
|
|
38
|
+
onSave?: (template: EmailTemplate) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Supply images from your own picker or uploader. Resolve with
|
|
41
|
+
* `{ url, alt? }`, or `null` when the user cancels (the block is left
|
|
42
|
+
* unchanged). A rejected promise is shown inline in the image inspector.
|
|
43
|
+
* Without it, the image inspector shows a plain URL field.
|
|
44
|
+
*/
|
|
45
|
+
onRequestImage?: OnRequestImage;
|
|
46
|
+
/**
|
|
47
|
+
* The sections this workspace has saved, offered in the section picker
|
|
48
|
+
* beside the built-in ones, under their own group.
|
|
49
|
+
*
|
|
50
|
+
* Optional: a host that passes none gets exactly the built-in library, which
|
|
51
|
+
* is what a standalone consumer of this package gets today.
|
|
52
|
+
*/
|
|
53
|
+
savedSections?: SavedSectionInput[];
|
|
54
|
+
/**
|
|
55
|
+
* Whether to offer the 35 sections that ship with this package (a hero, a
|
|
56
|
+
* few content and feature layouts, events, coupons, products, signatures and
|
|
57
|
+
* footers). True by default, which is what a workspace with nothing saved
|
|
58
|
+
* yet needs: an empty picker is a worse first run than a generic one.
|
|
59
|
+
*
|
|
60
|
+
* Pass false to offer only `savedSections`, which is what a host with its own
|
|
61
|
+
* library wants. The built-in set is brand neutral by construction (grey
|
|
62
|
+
* palette, fonts every mail client has, placeholder copy naming nobody, and
|
|
63
|
+
* `data:` URI images, so a workspace whose `asset_policy` is `service_only`
|
|
64
|
+
* can send them); turning them off is about whose library it is, not about
|
|
65
|
+
* whether they are safe to show.
|
|
66
|
+
*/
|
|
67
|
+
builtInSections?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* The origin the editor's placeholder images are served from, with no
|
|
70
|
+
* trailing slash, e.g. `https://mail.example.com`. Each becomes
|
|
71
|
+
* `<base>/p/<width>x<height>.png`.
|
|
72
|
+
*
|
|
73
|
+
* Give it whenever the documents this editor produces are going to be sent.
|
|
74
|
+
* Without it every placeholder is a `data:` URI, which renders in the canvas
|
|
75
|
+
* but which Gmail and Outlook.com do not render at all, and which a workspace
|
|
76
|
+
* that only allows its own service's addresses may not be able to replace.
|
|
77
|
+
*/
|
|
78
|
+
placeholderBase?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Keep a section for reuse. When set, a section's controls on the canvas
|
|
81
|
+
* carry a "Save as a section" action, which asks for a name (refusing one
|
|
82
|
+
* already in `savedSections`) and calls this with the section as plain data.
|
|
83
|
+
*
|
|
84
|
+
* Resolve when it is stored; a rejection is shown in the dialog with the
|
|
85
|
+
* error's message and the dialog stays open. Without it no action appears,
|
|
86
|
+
* rather than one that fails.
|
|
87
|
+
*
|
|
88
|
+
* The editor does not reload `savedSections` afterwards: the host owns that
|
|
89
|
+
* list and passes a new one when it has stored the section.
|
|
90
|
+
*/
|
|
91
|
+
onSaveSection?: (section: Record<string, unknown>, name: string) => Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* One saved section as the host holds it. The `section` is a snapshot of a
|
|
95
|
+
* single section of a document; inserting it rebuilds every id, so the same
|
|
96
|
+
* saved section can go into one document twice.
|
|
97
|
+
*/
|
|
98
|
+
interface SavedSectionInput {
|
|
99
|
+
id: string;
|
|
100
|
+
name: string;
|
|
101
|
+
description?: string;
|
|
102
|
+
section: Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Editor instance API
|
|
106
|
+
*/
|
|
107
|
+
interface EditorInstance {
|
|
108
|
+
getValue(): EmailTemplate;
|
|
109
|
+
setValue(template: EmailTemplate): void;
|
|
110
|
+
getHTML(): string;
|
|
111
|
+
getMJML(): string;
|
|
112
|
+
undo(): void;
|
|
113
|
+
redo(): void;
|
|
114
|
+
destroy(): void;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type { EditorOptions as E, SavedSectionInput as S, EditorInstance as a, EditorTheme as b };
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@marlinjai/email-editor",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Embeddable visual email editor (React component and vanilla factory) that produces an MJML-compilable document",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/marlinjai/email-editor.git",
|
|
9
|
+
"directory": "packages/editor"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/marlinjai/email-editor/tree/main/packages/editor#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/marlinjai/email-editor/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"email",
|
|
17
|
+
"mjml",
|
|
18
|
+
"email-editor",
|
|
19
|
+
"react",
|
|
20
|
+
"newsletter"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"sideEffects": [
|
|
26
|
+
"*.css"
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"main": "./dist/index.js",
|
|
34
|
+
"module": "./dist/index.mjs",
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"import": "./dist/index.mjs",
|
|
40
|
+
"require": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./react": {
|
|
43
|
+
"types": "./dist/react.d.ts",
|
|
44
|
+
"import": "./dist/react.mjs",
|
|
45
|
+
"require": "./dist/react.js"
|
|
46
|
+
},
|
|
47
|
+
"./styles.css": "./dist/styles.css"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@marlinjai/email-editor-blocks": "^0.2.0",
|
|
51
|
+
"@marlinjai/email-editor-ui": "^0.2.0",
|
|
52
|
+
"@marlinjai/email-editor-core": "^0.2.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"react": "^18.2.0 || ^19.0.0",
|
|
56
|
+
"react-dom": "^18.2.0 || ^19.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/react": "^19.3.0",
|
|
60
|
+
"@types/react-dom": "^19.3.0",
|
|
61
|
+
"jsdom": "^24",
|
|
62
|
+
"react": "^19.2.0",
|
|
63
|
+
"react-dom": "^19.2.0",
|
|
64
|
+
"tsup": "^8.0.1",
|
|
65
|
+
"typescript": "^5.3.0",
|
|
66
|
+
"vitest": "^1.0.4"
|
|
67
|
+
},
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=20.19.0"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "tsup src/index.ts src/react.tsx --format cjs,esm --dts --clean && cp ../ui/dist/styles.css ./dist/styles.css",
|
|
73
|
+
"dev": "tsup src/index.ts src/react.tsx --format cjs,esm --dts --watch",
|
|
74
|
+
"lint": "tsc --noEmit",
|
|
75
|
+
"test": "vitest run",
|
|
76
|
+
"test:watch": "vitest",
|
|
77
|
+
"clean": "rm -rf dist"
|
|
78
|
+
}
|
|
79
|
+
}
|