react-email-studio 2.0.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/README.md +126 -0
- package/TUTORIAL.md +264 -0
- package/USER_README.md +28 -0
- package/dist/index.cjs +7571 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +407 -0
- package/dist/index.d.ts +407 -0
- package/dist/index.js +7585 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# react-email-studio
|
|
2
|
+
|
|
3
|
+
**Visual email editor for React** — drag-and-drop layouts and blocks, rich text, images, buttons, tables, and more. Designs save as **JSON** (`email_document`); use **`jsonToHtml()`** to generate **HTML** for preview and your ESP (SendGrid, SES, Mailgun, …).
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/react-email-studio)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- Multi-column **layout rows** and **content blocks** (heading, text/HTML, image, button, link, divider, spacer, social, video, menu, timer, table, nested layouts)
|
|
13
|
+
- **Page & content** backgrounds (solid, gradient, image), responsive preview
|
|
14
|
+
- **Undo / redo**, zoom, device preview modal
|
|
15
|
+
- **Internationalized** UI strings (`en`, `fr`, `de`, `es`)
|
|
16
|
+
- **Merge tags** support for templates
|
|
17
|
+
- Tree-shakeable ESM + CJS, TypeScript types
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install react-email-studio
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add react-email-studio
|
|
29
|
+
yarn add react-email-studio
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Peer dependencies
|
|
33
|
+
|
|
34
|
+
Install these in your application (versions should satisfy `peerDependencies` in this package):
|
|
35
|
+
|
|
36
|
+
`react`, `react-dom`, `lucide-react`, and TipTap v3 (`@tiptap/react`, `@tiptap/core`, `@tiptap/starter-kit`, `@tiptap/extension-link`, `@tiptap/extension-placeholder`, `@tiptap/extension-text-align`, `@tiptap/extension-text-style`, `@tiptap/extension-underline`).
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { useRef } from "react";
|
|
44
|
+
import {
|
|
45
|
+
ReactEmailEditor,
|
|
46
|
+
type ReactEmailEditorRef,
|
|
47
|
+
jsonToHtml,
|
|
48
|
+
} from "react-email-studio";
|
|
49
|
+
|
|
50
|
+
export function App() {
|
|
51
|
+
const editorRef = useRef<ReactEmailEditorRef>(null);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<button
|
|
56
|
+
type="button"
|
|
57
|
+
onClick={() =>
|
|
58
|
+
editorRef.current?.exportJson((json) => {
|
|
59
|
+
// Persist JSON (API / database)
|
|
60
|
+
fetch("/api/save-email", { method: "POST", body: json });
|
|
61
|
+
}, true)
|
|
62
|
+
}
|
|
63
|
+
>
|
|
64
|
+
Save design
|
|
65
|
+
</button>
|
|
66
|
+
|
|
67
|
+
<ReactEmailEditor
|
|
68
|
+
ref={editorRef}
|
|
69
|
+
hideTemplates
|
|
70
|
+
onReady={(api) => {
|
|
71
|
+
/* api.loadJson(existingDesign); */
|
|
72
|
+
}}
|
|
73
|
+
onUpload={async (file) => {
|
|
74
|
+
const url = await uploadToYourStorage(file); // must return a public URL
|
|
75
|
+
return url;
|
|
76
|
+
}}
|
|
77
|
+
options={{ locale: "en" }}
|
|
78
|
+
/>
|
|
79
|
+
</>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Generate HTML for sending (server or client)
|
|
84
|
+
const html = jsonToHtml(savedDesignJson, {
|
|
85
|
+
customCSS: `/* optional extra styles */`,
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Implement **`onUpload`** so image/video uploads return URLs your recipients can load (HTTPS recommended).
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Package exports
|
|
94
|
+
|
|
95
|
+
| Export | Description |
|
|
96
|
+
|--------|-------------|
|
|
97
|
+
| `ReactEmailEditor` | Main editor component (`forwardRef`). |
|
|
98
|
+
| `ReactEmailEditorProps` | Component props type. |
|
|
99
|
+
| `ReactEmailEditorRef` | Imperative API: `loadJson`, `exportJson`. |
|
|
100
|
+
| `jsonToHtml` | `(design, opts?) => string` — full HTML email document. |
|
|
101
|
+
| `utf8ToBase64`, `base64ToUtf8` | Encoding helpers. |
|
|
102
|
+
| `EmailPreviewModal` | Standalone responsive preview modal. |
|
|
103
|
+
| `emailPreviewDevices` | Device presets for preview. |
|
|
104
|
+
| `EmailPreviewModalProps`, `MobilePreviewVariant` | TypeScript types. |
|
|
105
|
+
| `ReactEmailEditorOptions`, `JsonToHtmlOptions`, `EmailHtmlOptions` | Editor options and HTML generation options. |
|
|
106
|
+
| `EmailDocument`, `EmailDocumentSettings`, … | JSON schema types for stored designs. |
|
|
107
|
+
|
|
108
|
+
For framework setup (Next.js client/SSR), props tables, and troubleshooting, see **[TUTORIAL.md](./TUTORIAL.md)**.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Documentation in this package
|
|
113
|
+
|
|
114
|
+
| File | Audience |
|
|
115
|
+
|------|----------|
|
|
116
|
+
| **[USER_README.md](./USER_README.md)** | User guide — editor UI, workflows, options overview, troubleshooting. |
|
|
117
|
+
| **[TUTORIAL.md](./TUTORIAL.md)** | Integration tutorial — peers, save/load, Next.js/Vite, APIs, TypeScript. |
|
|
118
|
+
| **README.md** (this file) | npm landing page — install, quick start, exports. |
|
|
119
|
+
|
|
120
|
+
Deployment (hosting, CSP, publishing), deeper integration notes, and monorepo **`DEPLOYMENT.md`** live in the **source repository** alongside this package—clone or browse the repo for the full file.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT
|
package/TUTORIAL.md
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# react-email-studio — Integration tutorial & API reference
|
|
2
|
+
|
|
3
|
+
This document is for **npm users**: wiring **react-email-studio** into an app, persisting designs, generating HTML, and using optional APIs (preview modal, helpers, TypeScript types).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What you are integrating
|
|
8
|
+
|
|
9
|
+
| Piece | Role |
|
|
10
|
+
|--------|------|
|
|
11
|
+
| **`ReactEmailEditor`** | Full-screen (or sized) visual editor: rows, columns, blocks, settings. |
|
|
12
|
+
| **Design JSON** | Canonical storage format: `email_document` schema (see exported types). |
|
|
13
|
+
| **`jsonToHtml`** | Turns saved JSON into a **full HTML document** for preview iframes or your ESP. |
|
|
14
|
+
| **`onUpload`** | Your code uploads assets and returns **HTTPS URLs** referenced in the HTML. |
|
|
15
|
+
|
|
16
|
+
The package does **not** send mail, host files, or provide a backend—you connect those.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install react-email-studio
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Install **peer dependencies** in your app (same major versions as in this package’s `peerDependencies`):
|
|
27
|
+
|
|
28
|
+
- `react`, `react-dom`
|
|
29
|
+
- `lucide-react`
|
|
30
|
+
- TipTap v3: `@tiptap/react`, `@tiptap/core`, `@tiptap/starter-kit`, `@tiptap/extension-link`, `@tiptap/extension-placeholder`, `@tiptap/extension-text-align`, `@tiptap/extension-text-style`, `@tiptap/extension-underline`
|
|
31
|
+
|
|
32
|
+
TypeScript projects should also have **`@types/react`** and **`@types/react-dom`** as dev dependencies.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 2. Minimal integration (save / load)
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { useRef, useCallback } from "react";
|
|
40
|
+
import {
|
|
41
|
+
ReactEmailEditor,
|
|
42
|
+
type ReactEmailEditorRef,
|
|
43
|
+
jsonToHtml,
|
|
44
|
+
} from "react-email-studio";
|
|
45
|
+
|
|
46
|
+
export function MailStudioPage() {
|
|
47
|
+
const ref = useRef<ReactEmailEditorRef>(null);
|
|
48
|
+
|
|
49
|
+
const save = useCallback(() => {
|
|
50
|
+
ref.current?.exportJson((jsonString, _pretty) => {
|
|
51
|
+
// POST jsonString to your API or write to localStorage
|
|
52
|
+
void fetch("/api/email-designs", {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: { "Content-Type": "application/json" },
|
|
55
|
+
body: JSON.stringify({ design: jsonString }),
|
|
56
|
+
});
|
|
57
|
+
}, true);
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
<button type="button" onClick={save}>
|
|
63
|
+
Save design
|
|
64
|
+
</button>
|
|
65
|
+
<ReactEmailEditor
|
|
66
|
+
ref={ref}
|
|
67
|
+
hideTemplates
|
|
68
|
+
onReady={(api) => {
|
|
69
|
+
// Load previously saved JSON (string or parsed object)
|
|
70
|
+
// const saved = await fetch(...).then(r => r.json());
|
|
71
|
+
// api.loadJson(saved.design);
|
|
72
|
+
}}
|
|
73
|
+
onUpload={uploadImageAndReturnUrl}
|
|
74
|
+
options={{ locale: "en" }}
|
|
75
|
+
/>
|
|
76
|
+
</>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function uploadImageAndReturnUrl(file: File): Promise<string> {
|
|
81
|
+
const body = new FormData();
|
|
82
|
+
body.append("file", file);
|
|
83
|
+
const res = await fetch("/api/upload", { method: "POST", body });
|
|
84
|
+
const { url } = await res.json();
|
|
85
|
+
return url as string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Server-side or after save: build HTML for sending
|
|
89
|
+
function htmlFromStoredDesign(designJson: string) {
|
|
90
|
+
return jsonToHtml(designJson, {
|
|
91
|
+
customCSS: `/* optional: brand overrides */`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Important:** `onUpload` must return a URL that **email recipients** can open (usually `https://…`). Avoid `localhost` or short-lived signed URLs unless you understand deliverability.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 3. Framework notes
|
|
101
|
+
|
|
102
|
+
### Vite / Create React App
|
|
103
|
+
|
|
104
|
+
Import the editor like any other component. No special config is required beyond installing peers.
|
|
105
|
+
|
|
106
|
+
### Next.js (App Router)
|
|
107
|
+
|
|
108
|
+
The editor depends on the DOM and TipTap. Use a **client** boundary:
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
"use client";
|
|
112
|
+
|
|
113
|
+
import { ReactEmailEditor } from "react-email-studio";
|
|
114
|
+
// ...
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
If you see SSR-related errors (window/document during prerender), load the editor only on the client:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import dynamic from "next/dynamic";
|
|
121
|
+
|
|
122
|
+
const ReactEmailEditor = dynamic(
|
|
123
|
+
() => import("react-email-studio").then((m) => m.ReactEmailEditor),
|
|
124
|
+
{ ssr: false },
|
|
125
|
+
);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Adjust the import path to match your structure.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 4. `ReactEmailEditor` — props
|
|
133
|
+
|
|
134
|
+
| Prop | Type | Description |
|
|
135
|
+
|------|------|-------------|
|
|
136
|
+
| `ref` | `ReactEmailEditorRef` | Imperative API: `loadJson`, `exportJson` (see below). |
|
|
137
|
+
| `options` | `ReactEmailEditorOptions` | Editor chrome, locale, merge tags, feature flags, etc. (see §6). |
|
|
138
|
+
| `onUpload` | `(file: File) => Promise<string>` | Required for good image/video UX; return public URL string. |
|
|
139
|
+
| `onLoad` / `onReady` | `(api: ReactEmailEditorRef) => void` | Fired once with the same API object; use to call `loadJson` with server data. |
|
|
140
|
+
| `hideTemplates` | `boolean` | Hide built-in templates UI; use when you only load via `loadJson`. |
|
|
141
|
+
| `templates` | `{ name: string; design: unknown; thumbnail?: string }[]` | Optional starter templates. |
|
|
142
|
+
| `minHeight` | `string` | Default `"100vh"`. |
|
|
143
|
+
| `editorId` | `string` | Prefix for DOM ids (multiple editors on one page). |
|
|
144
|
+
| `style` | `CSSProperties` | Outer wrapper style. |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 5. Imperative API (`ReactEmailEditorRef`)
|
|
149
|
+
|
|
150
|
+
| Method | Description |
|
|
151
|
+
|--------|-------------|
|
|
152
|
+
| `loadJson(input: string \| Record<string, unknown>)` | Replace editor content from JSON string or object (invalid input is ignored safely). |
|
|
153
|
+
| `exportJson(cb: (json: string) => void, pretty?: boolean)` | Current design as JSON string (`email_document`). Use `pretty === true` for readable storage diffs. |
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 6. `options` (`ReactEmailEditorOptions`)
|
|
158
|
+
|
|
159
|
+
`ReactEmailEditorOptions` extends HTML generation hints with **`customCSS`** (injected in preview HTML) plus editor behavior:
|
|
160
|
+
|
|
161
|
+
| Area | Examples |
|
|
162
|
+
|------|----------|
|
|
163
|
+
| **`customCSS`** | Extra `<style>` content for generated HTML (preview / export parity). |
|
|
164
|
+
| **`appearance`** | `theme`, `colors`, `customThemes` — chrome theming. |
|
|
165
|
+
| **`locale`** | `"en"` \| `"fr"` \| `"de"` \| `"es"` for UI strings. |
|
|
166
|
+
| **`mergeTags`** | `{ name: string; value: string }[]` for rich-text insertion. |
|
|
167
|
+
| **`features.autoSave`** | `{ enabled?: boolean; interval?: number }` — UI autosave hint. |
|
|
168
|
+
| **`tools`** | `{ [blockType: string]: { enabled?: boolean } }` — toggle blocks. |
|
|
169
|
+
| **`blockLibrary`** | `groupHeadings`, `paletteGroupLabels` — library copy overrides. |
|
|
170
|
+
|
|
171
|
+
Full typings ship with the package (`ReactEmailEditorOptions`).
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 7. `jsonToHtml` — HTML for preview & ESP
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { jsonToHtml, type JsonToHtmlOptions } from "react-email-studio";
|
|
179
|
+
|
|
180
|
+
const html: string = jsonToHtml(designInput, options);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
| Argument | Description |
|
|
184
|
+
|----------|-------------|
|
|
185
|
+
| `designInput` | `unknown` — JSON string or parsed object; invalid or empty designs yield `""`. |
|
|
186
|
+
| `options` | `JsonToHtmlOptions` (= `EmailHtmlOptions`): `{ customCSS?: string }`. |
|
|
187
|
+
|
|
188
|
+
Use the returned string as the **email body HTML** with your provider (SendGrid, SES, Mailgun, Postmark, …). Test in real clients (Gmail, Outlook, Apple Mail).
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 8. Optional: `EmailPreviewModal` & `emailPreviewDevices`
|
|
193
|
+
|
|
194
|
+
For a **standalone** responsive preview (outside the built-in toolbar preview), the package exports:
|
|
195
|
+
|
|
196
|
+
- **`EmailPreviewModal`** — modal with device frames.
|
|
197
|
+
- **`emailPreviewDevices`** — device metadata for labels/layout.
|
|
198
|
+
|
|
199
|
+
You must pass **`html`** (from `jsonToHtml` or your pipeline) and a theme map **`C`** (`Record<string, string>`) for chrome colors—mirror the palette you use in your app or define a minimal set for the modal.
|
|
200
|
+
|
|
201
|
+
See TypeScript types **`EmailPreviewModalProps`** and **`MobilePreviewVariant`** (`"iphone"` \| `"android"`).
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## 9. Encoding helpers
|
|
206
|
+
|
|
207
|
+
| Export | Purpose |
|
|
208
|
+
|--------|---------|
|
|
209
|
+
| `utf8ToBase64(raw: string)` | Encode UTF-8 text to Base64. |
|
|
210
|
+
| `base64ToUtf8(b64: string)` | Decode Base64 to UTF-8 string. |
|
|
211
|
+
|
|
212
|
+
Useful for data URLs or compact transport—not email-specific.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 10. TypeScript — exported types
|
|
217
|
+
|
|
218
|
+
Import names match what you get from the package entry:
|
|
219
|
+
|
|
220
|
+
| Type | Purpose |
|
|
221
|
+
|------|---------|
|
|
222
|
+
| `ReactEmailEditorProps`, `ReactEmailEditorRef`, `ReactEmailEditorOptions` | Component contract. |
|
|
223
|
+
| `JsonToHtmlOptions`, `EmailHtmlOptions` | HTML generation options (`customCSS`). |
|
|
224
|
+
| `EmailDocument`, `EmailDocumentSettings`, `EmailDocumentRow`, `EmailDocumentColumn`, `BlockBase` | JSON schema shapes for storage / validation. |
|
|
225
|
+
| `EmailPreviewModalProps`, `MobilePreviewVariant` | Preview modal. |
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
import type {
|
|
231
|
+
EmailDocument,
|
|
232
|
+
ReactEmailEditorRef,
|
|
233
|
+
} from "react-email-studio";
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 11. JSON schema (`email_document`)
|
|
239
|
+
|
|
240
|
+
Persist **`exportJson`** output as your source of truth. Top-level shape:
|
|
241
|
+
|
|
242
|
+
- `type: "email_document"`
|
|
243
|
+
- `settings` — global email / content shell options
|
|
244
|
+
- `rows` — layout rows → columns → blocks
|
|
245
|
+
|
|
246
|
+
Use exported **`EmailDocument`** when typing API payloads or DB columns.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 12. Troubleshooting
|
|
251
|
+
|
|
252
|
+
| Issue | What to check |
|
|
253
|
+
|-------|----------------|
|
|
254
|
+
| Module not found (TipTap / lucide) | Install all peer dependencies; TipTap majors must align (v3). |
|
|
255
|
+
| Blank HTML from `jsonToHtml` | Empty rows after normalization, or invalid JSON. |
|
|
256
|
+
| Broken images in sent mail | URLs from `onUpload` must be publicly reachable from recipient networks. |
|
|
257
|
+
| SSR errors in Next.js | `"use client"` and/or `dynamic(..., { ssr: false })`. |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
MIT — see `package.json`.
|
package/USER_README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# react-email-studio — User guide
|
|
2
|
+
|
|
3
|
+
For **install, quick start, and export list**, see **`README.md`** on npm.
|
|
4
|
+
|
|
5
|
+
For **step-by-step integration** (Next.js, APIs, TypeScript), see **`TUTORIAL.md`**.
|
|
6
|
+
|
|
7
|
+
## Editor areas
|
|
8
|
+
|
|
9
|
+
| Area | Role |
|
|
10
|
+
|------|------|
|
|
11
|
+
| **Canvas** | Drag blocks, click to select rows/blocks, zoom, preview. |
|
|
12
|
+
| **Right rail** | Block inspector, row settings, **Blocks** / **Settings** tabs. |
|
|
13
|
+
| **Toolbar** | Undo/redo, templates (if enabled), preview. |
|
|
14
|
+
|
|
15
|
+
## Core APIs
|
|
16
|
+
|
|
17
|
+
- **`ref.loadJson` / `ref.exportJson`** — load or save design JSON.
|
|
18
|
+
- **`onUpload`** — return a public **HTTPS** URL for uploaded images.
|
|
19
|
+
- **`jsonToHtml`** — design JSON → full HTML for sending.
|
|
20
|
+
|
|
21
|
+
## Troubleshooting
|
|
22
|
+
|
|
23
|
+
| Issue | Check |
|
|
24
|
+
|-------|--------|
|
|
25
|
+
| Module not found | Install all **peer** packages (React, TipTap v3, `lucide-react`). |
|
|
26
|
+
| Broken images in mail | `onUpload` URLs must be reachable by recipients (not `localhost`). |
|
|
27
|
+
|
|
28
|
+
MIT — see `package.json`.
|