react-email-studio 3.4.0 → 3.8.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/CHANGELOG.md +70 -2
- package/README.md +12 -0
- package/TUTORIAL.md +56 -2
- package/USER_README.md +17 -0
- package/dist/index.cjs +1560 -491
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -33
- package/dist/index.d.ts +84 -33
- package/dist/index.js +1566 -494
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,74 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.8.0] - 2026-05-15
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Export shape (restored)**: `exportJson` / `designToEmailDocument` again emit **`rows[]`** with **`columns[].blocks[]`** — the LMS / studio interchange format. Each row includes **`styles`**, block **`props`**, and **`_reactEmailStudio.row`** (preset, ratios, column props).
|
|
13
|
+
- **Settings export**: writes **`settings._reactEmailStudio`** (`contentPadding`, `contentBorderRadius`, `editorSettings` snapshot) plus top-level **`contentPadding`** / **`contentBorderRadius`**.
|
|
14
|
+
- **New blocks from palette**: content blocks are added as **new root sections** (one row each), not dropped into the first layout column.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`loadJson(design, { mode: 'replace' | 'append' })`** — append merges imported rows/blocks onto the canvas.
|
|
19
|
+
- **`canonicalizeEmailDocument(input)`** — normalize any supported input to export-shaped `email_document` JSON.
|
|
20
|
+
- **Section reorder**: left **⋮⋮** drag handle, larger row drop zones, and **Move section up/down** in the row inspector.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **Root section order**: row drag-and-drop and move actions update canvas order (and exported `rows[]` order).
|
|
25
|
+
- **Rich HTML**: text color in the toolbar; bullet/numbered lists in canvas, preview, and exported HTML (`email-rich-html-content` styles).
|
|
26
|
+
|
|
27
|
+
### Notes for integrators
|
|
28
|
+
|
|
29
|
+
- **Import**: still accepts **`blocks[]`**, legacy **`rows[]`**, **`styles`**, and **`_reactEmailStudio`**.
|
|
30
|
+
- If you briefly integrated against **3.7.0** `blocks[]`-only export, use **`rows[]`** + **`_reactEmailStudio`** again — that is the primary export in **3.8.0**.
|
|
31
|
+
|
|
32
|
+
## [3.7.0] - 2026-05-15
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **Export shape**: `exportJson` / `designToEmailDocument` emit a flat root **`blocks[]`** instead of **`rows[]`**. Each canvas row becomes a root **`layout`** block; a row with a single content block exports that block directly at the root.
|
|
37
|
+
- **Settings**: **`contentPadding`** and **`contentBorderRadius`** are top-level `settings` fields. **`_reactEmailStudio` is no longer written** on export (including `settings._reactEmailStudio` and `editorSettings` snapshots).
|
|
38
|
+
- **`loadJson`**: optional second argument `{ mode: 'replace' | 'append' }` — append merges blocks/rows onto the canvas. Accepts `{ "blocks": [...] }` fragments and raw block arrays.
|
|
39
|
+
|
|
40
|
+
### Notes for integrators
|
|
41
|
+
|
|
42
|
+
- **Import**: legacy JSON with **`rows[]`**, **`styles`**, and **`_reactEmailStudio`** still loads.
|
|
43
|
+
- **Breaking**: consumers reading **`rows`** or **`_reactEmailStudio`** from export must switch to **`blocks`** and top-level **`settings`**.
|
|
44
|
+
|
|
45
|
+
## [3.6.0] - 2026-05-15
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
- **Column layout**: per-column surface styling uses **`columns: [{ props }]`** instead of **`columnStyles`** maps (rows, nested layouts, and `email_document` columns). Legacy `columnStyles` / column `styles` still import via `columnProps` helpers.
|
|
50
|
+
|
|
51
|
+
### Notes for integrators
|
|
52
|
+
|
|
53
|
+
- **Row export**: **`exportJson` / `designToEmailDocument`** no longer write **`_reactEmailStudio.row`** on each row. Row shell uses **`props`** (editor field names: `bgColor`, `padding`, …), not **`styles`**. Column surfaces use **`columns[].props`**. Optional **`layout.preset`** / **`layout.ratios`**. Legacy **`styles`** / **`_reactEmailStudio.row`** still import.
|
|
54
|
+
|
|
55
|
+
## [3.5.0] - 2026-05-15
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- **`htmlToJson(html, pretty?)`**: convert an HTML fragment or full page document into an `email_document` JSON string (one row, one column, single **html** block) — suitable for `loadJson` or storage.
|
|
60
|
+
- **`htmlToEmailDesignTemplate(html)`** and **`extractHtmlForDesign(html)`**: object and extraction helpers used by `htmlToJson`.
|
|
61
|
+
- **`ReactEmailEditor.htmlToJson`**: static method on the component (same implementation as the standalone export).
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- **Rich HTML blocks (`type: "html"`)**: body markup lives on the block root as a **string** `content` field; typography and chrome stay in **`props`** (not `props.content` in exported JSON).
|
|
66
|
+
- **`exportJson` / `designToEmailDocument`**: styling is carried in **`props`** only (blocks, rows, columns) — no **`styles`** on export. Legacy **`styles`** still import.
|
|
67
|
+
- **`BlockBase.content`**: typed as `Record<string, unknown> | string` so `html` blocks can use a plain string at the root.
|
|
68
|
+
|
|
69
|
+
### Notes for integrators
|
|
70
|
+
|
|
71
|
+
- **Export shape (blocks)**: `{ id, type, content?, props }` — no block `styles`. Example **html** block: `"content": "<p>…</p>"` plus `props` for `fontSize`, `padding`, backgrounds, etc.
|
|
72
|
+
- **Import**: legacy JSON with block `content` objects and/or `styles` still loads; `props` wins when present.
|
|
73
|
+
- **HTML → editor**: `loadJson(htmlToJson(paste))` or `loadJson(htmlToEmailDesignTemplate(paste))`.
|
|
74
|
+
- **HTML ← editor**: `jsonToHtml(exportJson)` unchanged.
|
|
75
|
+
|
|
8
76
|
## [3.4.0] - 2026-05-08
|
|
9
77
|
|
|
10
78
|
### Added
|
|
@@ -20,7 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
20
88
|
### Added
|
|
21
89
|
|
|
22
90
|
- **Loading state for `loadJson`**: `ReactEmailEditor` shows a full-workspace overlay (spinner + localized “Loading design…”) while a design JSON is applied, including invalid-parse early exit.
|
|
23
|
-
- **Lossless studio JSON**: document `settings._reactEmailStudio.editorSettings` stores a snapshot of editor settings
|
|
91
|
+
- **Lossless studio JSON**: document `settings._reactEmailStudio.editorSettings` stores a snapshot of editor settings. Row layout metadata is carried on **`layout`** (`preset`, `ratios`, …); legacy imports may still supply **`_reactEmailStudio.row`**.
|
|
24
92
|
- **i18n**: `loadingDesign` string in `en`, `fr`, `de`, `es`.
|
|
25
93
|
|
|
26
94
|
### Fixed
|
|
@@ -33,5 +101,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
33
101
|
|
|
34
102
|
### Notes for integrators
|
|
35
103
|
|
|
36
|
-
- Prefer **`loadJson` / `exportJson`** (or `designToEmailDocument` + `normalizeEmailDesignInput`) for full fidelity
|
|
104
|
+
- Prefer **`loadJson` / `exportJson`** (or `designToEmailDocument` + `normalizeEmailDesignInput`) for full fidelity. As of **3.5.0**, exported blocks use **`props`** for styling (block `styles` are not written on export); **`html`** blocks use a root-level string **`content`**.
|
|
37
105
|
- **`jsonToHtml`** nested layouts already receive `columnStyles` when present on hydrated blocks.
|
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
## Release notes
|
|
9
9
|
|
|
10
|
+
**Latest: 3.8.0** — export uses **`rows[]`** + **`_reactEmailStudio`** (LMS shape); palette blocks add as root sections; section reorder via drag handle or inspector.
|
|
11
|
+
|
|
10
12
|
Version history and migration hints: **[CHANGELOG.md](./CHANGELOG.md)** (also included in the published npm tarball under `node_modules/react-email-studio/CHANGELOG.md`).
|
|
11
13
|
|
|
12
14
|
---
|
|
@@ -49,6 +51,7 @@ import {
|
|
|
49
51
|
ReactEmailEditor,
|
|
50
52
|
type ReactEmailEditorRef,
|
|
51
53
|
jsonToHtml,
|
|
54
|
+
htmlToJson,
|
|
52
55
|
} from "react-email-studio";
|
|
53
56
|
|
|
54
57
|
export function App() {
|
|
@@ -88,6 +91,10 @@ export function App() {
|
|
|
88
91
|
const html = jsonToHtml(savedDesignJson, {
|
|
89
92
|
customCSS: `/* optional extra styles */`,
|
|
90
93
|
});
|
|
94
|
+
|
|
95
|
+
// Import existing HTML into the editor (fragment or full document)
|
|
96
|
+
const designJson = htmlToJson("<p>Hello from HTML</p>", true);
|
|
97
|
+
editorRef.current?.loadJson(designJson);
|
|
91
98
|
```
|
|
92
99
|
|
|
93
100
|
Implement **`onUpload`** so image/video uploads return URLs your recipients can load (HTTPS recommended).
|
|
@@ -102,6 +109,11 @@ Implement **`onUpload`** so image/video uploads return URLs your recipients can
|
|
|
102
109
|
| `ReactEmailEditorProps` | Component props type. |
|
|
103
110
|
| `ReactEmailEditorRef` | Imperative API: `loadJson`, `exportJson`. |
|
|
104
111
|
| `jsonToHtml` | `(design, opts?) => string` — full HTML email document. |
|
|
112
|
+
| `htmlToJson` | `(html, pretty?) => string` — HTML fragment/page → `email_document` JSON. |
|
|
113
|
+
| `htmlToEmailDesignTemplate` | `(html) => EmailDocument \| null` — same conversion as object. |
|
|
114
|
+
| `canonicalizeEmailDocument` | `(input) => EmailDocument \| null` — normalize import/export JSON. |
|
|
115
|
+
| `extractHtmlForDesign` | `(html) => string` — pull body/fragment from a full HTML document. |
|
|
116
|
+
| `ReactEmailEditor.jsonToHtml` / `.htmlToJson` | Static helpers on the component. |
|
|
105
117
|
| `utf8ToBase64`, `base64ToUtf8` | Encoding helpers. |
|
|
106
118
|
| `EmailPreviewModal` | Standalone responsive preview modal. |
|
|
107
119
|
| `emailPreviewDevices` | Device presets for preview. |
|
package/TUTORIAL.md
CHANGED
|
@@ -11,6 +11,7 @@ This document is for **npm users**: wiring **react-email-studio** into an app, p
|
|
|
11
11
|
| **`ReactEmailEditor`** | Full-screen (or sized) visual editor: rows, columns, blocks, settings. |
|
|
12
12
|
| **Design JSON** | Canonical storage format: `email_document` schema (see exported types). |
|
|
13
13
|
| **`jsonToHtml`** | Turns saved JSON into a **full HTML document** for preview iframes or your ESP. |
|
|
14
|
+
| **`htmlToJson`** | Wraps pasted HTML in `email_document` JSON for **`loadJson`**. |
|
|
14
15
|
| **`onUpload`** | Your code uploads assets and returns **HTTPS URLs** referenced in the HTML. |
|
|
15
16
|
|
|
16
17
|
The package does **not** send mail, host files, or provide a backend—you connect those.
|
|
@@ -188,6 +189,34 @@ Use the returned string as the **email body HTML** with your provider (SendGrid,
|
|
|
188
189
|
|
|
189
190
|
---
|
|
190
191
|
|
|
192
|
+
## 7b. `htmlToJson` — HTML into the editor
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import {
|
|
196
|
+
htmlToJson,
|
|
197
|
+
htmlToEmailDesignTemplate,
|
|
198
|
+
extractHtmlForDesign,
|
|
199
|
+
} from "react-email-studio";
|
|
200
|
+
|
|
201
|
+
const json = htmlToJson("<p>Welcome</p>", true); // pretty-print optional
|
|
202
|
+
editorRef.current?.loadJson(json);
|
|
203
|
+
|
|
204
|
+
// Or as an object:
|
|
205
|
+
const doc = htmlToEmailDesignTemplate(fullPageHtml);
|
|
206
|
+
if (doc) editorRef.current?.loadJson(doc);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| Export | Description |
|
|
210
|
+
|--------|-------------|
|
|
211
|
+
| `htmlToJson(html, pretty?)` | `email_document` JSON string; `""` if HTML is empty after normalization. |
|
|
212
|
+
| `htmlToEmailDesignTemplate(html)` | Same design as an `EmailDocument` object, or `null`. |
|
|
213
|
+
| `extractHtmlForDesign(html)` | Body/fragment only (strips `<html>` wrapper when present). |
|
|
214
|
+
| `ReactEmailEditor.htmlToJson` | Static method — same as `htmlToJson`. |
|
|
215
|
+
|
|
216
|
+
Creates one row, one column, and a single **html** block with default typography `props`.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
191
220
|
## 8. Optional: `EmailPreviewModal` & `emailPreviewDevices`
|
|
192
221
|
|
|
193
222
|
For a **standalone** responsive preview (outside the built-in toolbar preview), the package exports:
|
|
@@ -239,8 +268,33 @@ import type {
|
|
|
239
268
|
Persist **`exportJson`** output as your source of truth. Top-level shape:
|
|
240
269
|
|
|
241
270
|
- `type: "email_document"`
|
|
242
|
-
- `settings` — global
|
|
243
|
-
- `rows` — layout
|
|
271
|
+
- `settings` — global shell (`width`, `backgroundColor`, `contentBackgroundColor`, `contentPadding`, `contentBorderRadius`, `fontFamily`, `rtl`, …) plus **`settings._reactEmailStudio`** (`editorSettings` snapshot).
|
|
272
|
+
- `rows` — **primary export**: each canvas section is a **`type: "row"`** with `layout`, `styles`, `columns[].blocks[]`, and **`_reactEmailStudio.row`** (preset, ratios, column props).
|
|
273
|
+
|
|
274
|
+
**Import** also accepts **`blocks[]`**, legacy **`styles`**, and partial fragments.
|
|
275
|
+
|
|
276
|
+
### Row / block fields (export, 3.8+)
|
|
277
|
+
|
|
278
|
+
| Level | Fields |
|
|
279
|
+
|-------|--------|
|
|
280
|
+
| Row | `id`, `type: "row"`, `layout`, `styles`, `props`, `columns`, `_reactEmailStudio.row` |
|
|
281
|
+
| Column | `id`, `layout`, `styles`, `props`, `blocks[]` |
|
|
282
|
+
| Block | `id`, `type`, `content`, `styles`, `props`, optional `behavior` |
|
|
283
|
+
|
|
284
|
+
Blocks use **`props`** for editor fields; **`styles`** mirror the document schema for ESP compatibility. Rich **`html`** blocks use `content.html` (and `props.content`).
|
|
285
|
+
|
|
286
|
+
### Optional `blocks[]` (import)
|
|
287
|
+
|
|
288
|
+
A flat **`blocks[]`** root (layout or content blocks) still loads; the editor wraps standalone blocks in rows. **Export** uses **`rows[]`**, not `blocks[]`.
|
|
289
|
+
|
|
290
|
+
### `loadJson` append
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
editorRef.current?.loadJson({ rows: [/* … */] }, { mode: "append" });
|
|
294
|
+
// or { blocks: […] } / a raw array — coerced before merge
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Use **`canonicalizeEmailDocument(input)`** to normalize saved JSON to the export shape without opening the editor.
|
|
244
298
|
|
|
245
299
|
Use exported **`EmailDocument`** when typing API payloads or DB columns.
|
|
246
300
|
|
package/USER_README.md
CHANGED
|
@@ -17,6 +17,23 @@ For **step-by-step integration** (Next.js, APIs, TypeScript), see **`TUTORIAL.md
|
|
|
17
17
|
- **`ref.loadJson` / `ref.exportJson`** — load or save design JSON.
|
|
18
18
|
- **`onUpload`** — return a public **HTTPS** URL for uploaded images.
|
|
19
19
|
- **`jsonToHtml`** — design JSON → full HTML for sending.
|
|
20
|
+
- **`htmlToJson`** — paste HTML (fragment or page) → `email_document` JSON for `loadJson`.
|
|
21
|
+
|
|
22
|
+
### Block JSON (3.5+)
|
|
23
|
+
|
|
24
|
+
Exported blocks use **`props`** for styling (no block-level **`styles`**). Rich **html** blocks store markup as a root-level **`content`** string; other block types keep structured `content` objects where applicable.
|
|
25
|
+
|
|
26
|
+
### Column layout (3.6+)
|
|
27
|
+
|
|
28
|
+
Per-column backgrounds, padding, and radius use **`columns: [{ props }]`** on rows and nested layouts (not **`columnStyles`**). Legacy maps still import.
|
|
29
|
+
|
|
30
|
+
### Export shape (3.8+)
|
|
31
|
+
|
|
32
|
+
**`exportJson`** writes **`rows[]`** (each section = `type: "row"` with `columns[].blocks[]`), plus **`settings._reactEmailStudio`** and per-row **`_reactEmailStudio.row`** for editor round-trip. **`blocks[]`** is still accepted on **import** only.
|
|
33
|
+
|
|
34
|
+
**Reorder sections**: drag the **⋮⋮** handle on the left of a row, or select the row and use **Move section up/down** in the right panel.
|
|
35
|
+
|
|
36
|
+
**Append designs**: `loadJson(fragment, { mode: "append" })`.
|
|
20
37
|
|
|
21
38
|
## Troubleshooting
|
|
22
39
|
|