@boxcc/maildeno-editor 0.0.0-stage → 0.4.14
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 +479 -0
- package/README.md +442 -2
- package/dist/DatePicker-AdfGW0Tw.js +5347 -0
- package/dist/DatePicker-aNFlsoOb.js +5347 -0
- package/dist/Dialog-By0JLN8s.js +6294 -0
- package/dist/HealthIndicator-BLID6Ty0.js +1216 -0
- package/dist/HealthIndicator-DfzqzPNw.js +1217 -0
- package/dist/PopperContent-N2nAEFeH.js +2538 -0
- package/dist/PopperContent-eLmz1Gjd.js +2578 -0
- package/dist/PreviewCanvas-D3SpILsV.js +534 -0
- package/dist/PreviewCanvas-PtW1UL1J.js +534 -0
- package/dist/RichTextEditor-D6DQqbJg.js +12218 -0
- package/dist/RichTextEditor-DDEfKPZm.js +12217 -0
- package/dist/RowPreviewChildren-BGnilx-K.js +4 -0
- package/dist/RowPreviewChildren-CalQWx1C.js +4 -0
- package/dist/RowPreviewLegacyComponent-Df_1HTly.js +403 -0
- package/dist/RowPreviewLegacyComponent-NECG3wpn.js +403 -0
- package/dist/RowPreviewRow-C2XAe5Xs.js +81 -0
- package/dist/RowPreviewRow-DG4AdMrv.js +81 -0
- package/dist/SavedRowsPanel-2JBfYdxN.js +492 -0
- package/dist/SavedRowsPanel-B6_VHQZm.js +493 -0
- package/dist/_plugin-vue_export-helper-Dj7HTbfw.js +8 -0
- package/dist/adapters/errors.d.ts +59 -0
- package/dist/adapters/localStorageAdapter.d.ts +6 -0
- package/dist/adapters/types.d.ts +151 -0
- package/dist/babel-DV7WPQI0.js +10043 -0
- package/dist/blocks/registry.d.ts +23 -0
- package/dist/blocks/types.d.ts +73 -0
- package/dist/borderRadius-CkSa1lQ9.js +75 -0
- package/dist/components/features/emailBuilder/EmailEditor.vue.d.ts +183 -0
- package/dist/composables/emailBuilder/export/logic/espLogicWrapper.d.ts +76 -0
- package/dist/composables/emailBuilder/persistence/useEmailBuilderPersistence.d.ts +38 -0
- package/dist/composables/emailBuilder/transform/pipeline/optimize.d.ts +100 -0
- package/dist/composables/system/useColorScheme.d.ts +16 -0
- package/dist/element-DQw3HLit.js +21540 -0
- package/dist/element.d.ts +6 -0
- package/dist/element.js +5 -0
- package/dist/esp/registry.d.ts +33 -0
- package/dist/estree-DY9POgc0.js +8195 -0
- package/dist/html-wb0gSX1o.js +7273 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +15032 -0
- package/dist/init.d.ts +180 -0
- package/dist/init.js +143 -0
- package/dist/maildeno-editor.css +2 -0
- package/dist/merge-tags/registry.d.ts +33 -0
- package/dist/mergeTagDefinitions-Cler19nv.js +27 -0
- package/dist/standalone-DHvJ30Td.js +3554 -0
- package/dist/theme.d.ts +206 -0
- package/dist/types/assistant.d.ts +56 -0
- package/dist/useEmailBuilder-2yCUzRx2.js +4934 -0
- package/dist/useEmailBuilder-D3uV7dwL.js +4934 -0
- package/dist/useToast-D1GgDMqQ.js +194 -0
- package/dist/utils/border.d.ts +15 -0
- package/dist/utils/borderRadius.d.ts +10 -0
- package/dist/vue.runtime.esm-bundler-D2AjRP90.js +6117 -0
- package/package.json +100 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.12
|
|
4
|
+
|
|
5
|
+
API change.
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- The **Image component** no longer shows extra space below the image, and linked images now size the same as unlinked ones. Alignment (left, center, right) still works.
|
|
9
|
+
|
|
10
|
+
## 0.4.11
|
|
11
|
+
|
|
12
|
+
API changes.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
+ Moved Button and Anchor padding from the container `<div>` to the clickable `<a>` / `<Link>` element.
|
|
16
|
+
+ Updated HTML, MJML, and React Email renderers to consistently apply padding to the link element.
|
|
17
|
+
+ Updated generated styles so Button and Anchor padding targets the .{uid}-link selector.
|
|
18
|
+
|
|
19
|
+
## 0.4.10
|
|
20
|
+
|
|
21
|
+
API change.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Reduced the **Image** panel minimum width from `8px` to `1px`.
|
|
25
|
+
|
|
26
|
+
## 0.4.9
|
|
27
|
+
|
|
28
|
+
API change.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- The **Content** tab is now the default tab in the left-hand panel.
|
|
32
|
+
|
|
33
|
+
## 0.4.8
|
|
34
|
+
|
|
35
|
+
API changes.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- The **Layout** tab is now the default tab in the left-hand panel.
|
|
39
|
+
|
|
40
|
+
### Removed
|
|
41
|
+
- Unused code in `CanvasRowDropZone`.
|
|
42
|
+
|
|
43
|
+
## 0.4.7
|
|
44
|
+
|
|
45
|
+
Public API surface. No runtime change.
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
**The document model and editor state types are exported.** `Canvas`,
|
|
50
|
+
`NestedRow`, `RowSpacer`, `Column`, `VisibilityConfig`, `BorderConfig`,
|
|
51
|
+
`GradientConfig`, `AutoSaveStatus` and `ColorMode` now come from the
|
|
52
|
+
package root.
|
|
53
|
+
|
|
54
|
+
Five of these already appeared in `EmailEditor`'s props and slot props,
|
|
55
|
+
so they were public whether or not they were exported — just unnameable.
|
|
56
|
+
A consumer destructuring the default slot got a `rows` array it could
|
|
57
|
+
read but could not write a signature for, and `tsc --declaration` failed
|
|
58
|
+
with TS2883 on anything that touched one.
|
|
59
|
+
|
|
60
|
+
`Column`, `VisibilityConfig`, `BorderConfig` and `GradientConfig` were
|
|
61
|
+
not leaked themselves, but `NestedRow` and `RowSpacer` are not usable
|
|
62
|
+
without them: being able to name a row but not the type of its `columns`
|
|
63
|
+
is only half a fix. They were module-private in `optimize.ts` and are now
|
|
64
|
+
exported.
|
|
65
|
+
|
|
66
|
+
`Canvas` is the email body's own settings — width, padding, background,
|
|
67
|
+
preheader — not an HTML canvas. Alias it on import if that reads badly.
|
|
68
|
+
|
|
69
|
+
### Fixed
|
|
70
|
+
|
|
71
|
+
**`index.ts` pointed at the wrong entry for `init()`.** The comment said
|
|
72
|
+
custom-element usage "including init()" lives at
|
|
73
|
+
`@maildeno/editor/element`. `init()` is at `@maildeno/editor/init`;
|
|
74
|
+
`/element` has `registerMaildenoEditorElement` and
|
|
75
|
+
`MaildenoEditorElement`.
|
|
76
|
+
|
|
77
|
+
**Added `main` and `module` fallbacks.** With only an `exports` map, any
|
|
78
|
+
tool predating it failed to resolve the package at all rather than
|
|
79
|
+
falling back. Both point at `dist/index.js`, same as `exports["."]`.
|
|
80
|
+
|
|
81
|
+
Verified with `tsc --strict`, `declaration: true` and
|
|
82
|
+
`skipLibCheck: false` against every value export of all three entries:
|
|
83
|
+
0 errors, down from 5.
|
|
84
|
+
|
|
85
|
+
## 0.4.6
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
|
|
89
|
+
**Rich text, the date picker and three panels now load on demand.** First
|
|
90
|
+
load drops from 440kB to 269kB gzipped, 38.8% smaller.
|
|
91
|
+
|
|
92
|
+
TipTap and ProseMirror are ~745kB — a quarter of the bundle — and
|
|
93
|
+
RichTextEditor is the only thing that pulls them. It is also how heading,
|
|
94
|
+
paragraph and list blocks render, not just how they are edited, so it
|
|
95
|
+
cannot simply be made async: the canvas would be blank until the chunk
|
|
96
|
+
landed. Those blocks now mount RichTextBlock, which paints the text
|
|
97
|
+
through RichTextStatic and swaps in the real editor when its chunk
|
|
98
|
+
resolves. Same root element and content classes, so the swap is
|
|
99
|
+
invisible. Merge tags render through a TipTap NodeView, so their markup
|
|
100
|
+
shows raw for that one frame.
|
|
101
|
+
|
|
102
|
+
This defers parsing, not downloading. The chunk is still fetched on
|
|
103
|
+
mount, so a session transfers the same bytes; what improves is time to
|
|
104
|
+
first paint and time to interactive.
|
|
105
|
+
|
|
106
|
+
DatePicker, HealthIndicator, SavedRowsPanel and PreviewCanvas are plain
|
|
107
|
+
async components — all four are already behind a v-if and none is visible
|
|
108
|
+
until the user opens something. DatePicker alone was worth 128kB: it is
|
|
109
|
+
used in exactly one place, an advanced ESP visibility rule, and pulled
|
|
110
|
+
all of @internationalized/date plus reka-ui's calendar tree into every
|
|
111
|
+
page load.
|
|
112
|
+
|
|
113
|
+
**Unreachable type declarations are no longer published.** 216 .d.ts
|
|
114
|
+
files down to 17, 200kB smaller. unplugin-dts emits a declaration for
|
|
115
|
+
every module under src/, but `exports` exposes only ".", "./element" and
|
|
116
|
+
"./init" and has no wildcard, so a consumer could never load the other
|
|
117
|
+
201 — including three that still imported @tiptap/vue-3, which stopped
|
|
118
|
+
being a dependency in 0.4.5. `scripts/prune-types.mjs` walks the import
|
|
119
|
+
graph from each entry's `types` target and removes what it never visits.
|
|
120
|
+
It fails the build if an entry is missing rather than pruning against an
|
|
121
|
+
incomplete graph.
|
|
122
|
+
|
|
123
|
+
Verified with `tsc --strict` and `skipLibCheck: false` against the whole
|
|
124
|
+
public surface, before and after: identical results.
|
|
125
|
+
|
|
126
|
+
## 0.4.5
|
|
127
|
+
|
|
128
|
+
Packaging only. No API change, no behaviour change.
|
|
129
|
+
|
|
130
|
+
### Changed
|
|
131
|
+
|
|
132
|
+
**The 15 runtime dependencies moved to devDependencies.** TipTap,
|
|
133
|
+
ProseMirror, reka-ui, @vueuse/core, prettier and @internationalized/date
|
|
134
|
+
are all bundled into `dist` at build time, so declaring them as runtime
|
|
135
|
+
dependencies made npm install a second, unused copy of each into every
|
|
136
|
+
consumer's node_modules.
|
|
137
|
+
|
|
138
|
+
`dist` imports exactly one external module — `vue` — which is already the
|
|
139
|
+
sole peerDependency. Verified across every emitted chunk, and by
|
|
140
|
+
installing the package with nothing but Vue and building a consumer:
|
|
141
|
+
32/32 scoped selectors present, no unresolved imports.
|
|
142
|
+
|
|
143
|
+
Installing the package now pulls **25 MB across 15 packages instead of
|
|
144
|
+
71 MB across 45**.
|
|
145
|
+
|
|
146
|
+
If any of these is ever externalised rather than bundled, it has to move
|
|
147
|
+
back. `dist` importing anything other than `vue` is the signal.
|
|
148
|
+
|
|
149
|
+
## 0.4.4
|
|
150
|
+
|
|
151
|
+
Packaging only. No API change, no behaviour change in the editor itself.
|
|
152
|
+
The published package drops from 8.13 MB unpacked to 5.48 MB, 32.6% smaller.
|
|
153
|
+
|
|
154
|
+
### Changed
|
|
155
|
+
|
|
156
|
+
**React Email export formats with prettier's babel-ts parser** instead of
|
|
157
|
+
the typescript parser. `prettier/plugins/typescript` is 900kB of source
|
|
158
|
+
against babel's 318kB and was the largest single file in the package.
|
|
159
|
+
Output is byte-identical on the TSX this package generates, verified
|
|
160
|
+
across generics, JSX, inline style objects and mapped children. The
|
|
161
|
+
typescript parser is the stricter of the two, which matters for arbitrary
|
|
162
|
+
user code but not for TSX `react-email.ts` generated moments earlier.
|
|
163
|
+
Saves 600kB.
|
|
164
|
+
|
|
165
|
+
**Both build passes are minified.** They have to agree: the two passes
|
|
166
|
+
share chunks by content hash, so identical output collapses to one file
|
|
167
|
+
and differing output ships two. Minifying only the element pass made the
|
|
168
|
+
package *larger* — 8.68 MB — because every prettier chunk was then
|
|
169
|
+
carried twice, once minified and once not. Saves 1.92MB with both on.
|
|
170
|
+
|
|
171
|
+
**`element-scoped-styles.css` is no longer emitted.** Nothing referenced
|
|
172
|
+
it: not `src/`, not the framework guides, not the README, not the exports
|
|
173
|
+
map. The shadow root reads those rules from the substituted string inside
|
|
174
|
+
the chunk, and Vite only extracted the file because library mode always
|
|
175
|
+
does. `dist/editor.css` is unaffected and `./style.css` still resolves.
|
|
176
|
+
Saves 72kB.
|
|
177
|
+
|
|
178
|
+
## 0.4.3
|
|
179
|
+
|
|
180
|
+
### Fixed
|
|
181
|
+
|
|
182
|
+
**Every component `<style scoped>` block was missing when installing from
|
|
183
|
+
npm and using the `EmailEditor` Vue component.** The editor rendered
|
|
184
|
+
unstyled panels — `HealthIndicator`, `DesktopOnlyNotice`, the text panel,
|
|
185
|
+
and 29 other scoped blocks — while Tailwind, the fonts and the icons all
|
|
186
|
+
applied normally. `init()` and the custom element were unaffected, and
|
|
187
|
+
building against a local `dist/` folder never reproduced it.
|
|
188
|
+
|
|
189
|
+
0.4.2 delivered those styles by prepending a self-executing snippet to the
|
|
190
|
+
entry chunk:
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
(function(){ /* … document.head.appendChild(style) … */ })();
|
|
194
|
+
import { a, c, g, … } from "./index-DhFg3uKs.js";
|
|
195
|
+
export { a as EmailEditor, … };
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`package.json` declares `sideEffects` as covering CSS files only, which
|
|
199
|
+
tells a consumer's bundler that every `.js` in the package is pure. Rollup
|
|
200
|
+
had emitted `dist/index.js` as a thin facade holding nothing but that
|
|
201
|
+
snippet and a set of re-exports — and a pure module whose exports can be
|
|
202
|
+
reached directly is one a bundler may delete outright. So consumer builds
|
|
203
|
+
dropped the file, the snippet went with it, and the CSS never ran.
|
|
204
|
+
Verified against the published 0.4.2 tarball: zero of 32 scoped selectors
|
|
205
|
+
survived a consumer build.
|
|
206
|
+
|
|
207
|
+
Whether Rollup emits that facade is a chunking decision, which is why the
|
|
208
|
+
same source built correctly in this repo and shipped broken. The styles
|
|
209
|
+
are now substituted into a value `baseStyles.ts` returns, so
|
|
210
|
+
`EmailEditor.vue` injects them on mount alongside Tailwind and the fonts.
|
|
211
|
+
Reachable from the component, they cannot be dropped without dropping the
|
|
212
|
+
component — the mechanism `shadowStyles.ts` has always used for the shadow
|
|
213
|
+
root. Confirmed surviving even under `sideEffects: false`.
|
|
214
|
+
|
|
215
|
+
Nothing changed in the public API, and no CSS import is needed.
|
|
216
|
+
|
|
217
|
+
### Changed
|
|
218
|
+
|
|
219
|
+
**A missing style substitution now fails the build instead of warning.**
|
|
220
|
+
Both build passes error out if the placeholder cannot be found in any
|
|
221
|
+
chunk. A warning in a build log was not enough to catch this before
|
|
222
|
+
publishing.
|
|
223
|
+
|
|
224
|
+
## 0.4.2
|
|
225
|
+
|
|
226
|
+
Docs only — no code changes. 0.4.1's `onSave` fix is confirmed working on the
|
|
227
|
+
`init()` path.
|
|
228
|
+
|
|
229
|
+
- **Save gating documented** in the Vanilla, React and Astro guides: `onSave`
|
|
230
|
+
is what reveals the Save button, and `handle.on("save", …)` only fires when
|
|
231
|
+
it was passed, because without it the editor never saves.
|
|
232
|
+
- **New "Reading the canvas" section** in the Nuxt and Vue guides, covering
|
|
233
|
+
`getHtml` / `getMjml` / `getReactEmail` / `getJson` via a template ref —
|
|
234
|
+
they are instance methods, not events or slot props, which was not written
|
|
235
|
+
down anywhere.
|
|
236
|
+
|
|
237
|
+
## 0.4.1
|
|
238
|
+
|
|
239
|
+
### Fixed
|
|
240
|
+
|
|
241
|
+
**`onSave` from `init()` never fired.** `save` was a `defineEmits` entry, and
|
|
242
|
+
`defineCustomElement` *replaces* `instance.emit` with a DOM-event dispatcher:
|
|
243
|
+
|
|
244
|
+
```js
|
|
245
|
+
instance.emit = (event, ...args) => { dispatch(event, args); … }
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
So `emit("save")` dispatched a CustomEvent and never called the handler the
|
|
249
|
+
host had passed. The Save button appeared (the prop was present) and the
|
|
250
|
+
callback was unreachable — while `handle.on("save", …)` worked, because that
|
|
251
|
+
listens for the DOM event.
|
|
252
|
+
|
|
253
|
+
`save` is no longer an emit. The handler is a prop the component calls
|
|
254
|
+
directly, and the component re-dispatches a `bubbles: true, composed: true`
|
|
255
|
+
CustomEvent alongside it so `handle.on("save", …)` keeps working.
|
|
256
|
+
|
|
257
|
+
`init()` sets it as **`saveHandler`**, not `onSave`: Vue's custom-element
|
|
258
|
+
wrapper routes `on*` keys to its event machinery, so `el.onSave = fn` never
|
|
259
|
+
reaches the component either. Vue hosts keep using `@save`.
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
## 0.4.0
|
|
263
|
+
|
|
264
|
+
Gating corrections. All three came from running the editor as a guest, where
|
|
265
|
+
every "can the user do this?" question has a different answer.
|
|
266
|
+
|
|
267
|
+
### Changed
|
|
268
|
+
|
|
269
|
+
**The Save button now follows an `onSave` handler**, matching how
|
|
270
|
+
`onSendTestEmail` reveals the Send-test button. Pass it and Save appears; omit
|
|
271
|
+
it and the button, the save-status indicator and the autosave timer all
|
|
272
|
+
disappear.
|
|
273
|
+
|
|
274
|
+
```vue
|
|
275
|
+
<EmailEditor @save="onSave" /> <!-- Vue: @save IS the onSave prop -->
|
|
276
|
+
```
|
|
277
|
+
```ts
|
|
278
|
+
init({ onSave(payload) { … } })
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
0.3.0 gated this on the storage adapter having `saveTemplate`, which was
|
|
282
|
+
wrong: `mergeWithDefaults` fills every missing method from the localStorage
|
|
283
|
+
defaults, so `saveTemplate` is *always* present by the time anything reads it.
|
|
284
|
+
The check could never be false. Gating on an explicit handler is both correct
|
|
285
|
+
and more discoverable.
|
|
286
|
+
|
|
287
|
+
**The saved-templates panel button is hidden when the host omits
|
|
288
|
+
`listTemplates`.** Same before-merge reasoning. A guest would otherwise be
|
|
289
|
+
offered a template library backed by localStorage that they never saved to and
|
|
290
|
+
cannot reach anywhere else. `versions: true` forces the button on, since
|
|
291
|
+
version history comes from different adapter methods.
|
|
292
|
+
|
|
293
|
+
### Guest editors
|
|
294
|
+
|
|
295
|
+
The two above make a genuine read-only editor a one-liner, and the shape
|
|
296
|
+
matters:
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
// Right — everything unlisted falls back to localStorage
|
|
300
|
+
const adapter = { loadTemplate: api.loadTemplate };
|
|
301
|
+
```
|
|
302
|
+
```ts
|
|
303
|
+
// Wrong — every other method still points at authenticated endpoints,
|
|
304
|
+
// so saving a row 401s
|
|
305
|
+
const { saveTemplate, ...adapter } = api;
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
With the first, saved rows, image uploads and drafts all keep working against
|
|
309
|
+
the visitor's own browser. Exports work fully. There is no Save button and no
|
|
310
|
+
template library.
|
|
311
|
+
|
|
312
|
+
## 0.3.0
|
|
313
|
+
|
|
314
|
+
Four fixes from real integration, three of them things only a running app
|
|
315
|
+
could surface.
|
|
316
|
+
|
|
317
|
+
### Fixed
|
|
318
|
+
|
|
319
|
+
**The editor's CSS no longer leaks into the host page.** The Vue-component
|
|
320
|
+
path injected ~183KB into `document.head` — bare `.grid`, `.flex`, `.hidden`,
|
|
321
|
+
`.block` utilities plus `html`, `body` and `h1`–`h6` element rules. In an app
|
|
322
|
+
that also uses Tailwind, the editor's copy was injected later and won on
|
|
323
|
+
source order, so the host's own layout classes started behaving like the
|
|
324
|
+
editor's.
|
|
325
|
+
|
|
326
|
+
Every rule is now prefixed with `:where(.md-editor-scope)` at build time by a
|
|
327
|
+
PostCSS pass, and the editor root carries that class. `:where()` adds no
|
|
328
|
+
specificity, so the cascade inside the editor is unchanged. `@font-face`,
|
|
329
|
+
`@property`, `@keyframes` and `@import` stay global — they are document-scoped
|
|
330
|
+
by nature, and `@property` in particular is what makes Tailwind's `--tw-*`
|
|
331
|
+
variables resolve at all. `:root`, `html` and `body` are retargeted to the
|
|
332
|
+
editor root rather than dropped, since some carry the editor's own background
|
|
333
|
+
and font stack.
|
|
334
|
+
|
|
335
|
+
Verified on a real mount: 1,121 rules scoped, zero unscoped utilities or
|
|
336
|
+
element rules remaining.
|
|
337
|
+
|
|
338
|
+
**Save is hidden when the host can't save.** Pass a `storageAdapter` without
|
|
339
|
+
`saveTemplate` and the Save button, the save-status indicator and the autosave
|
|
340
|
+
timer all disappear — a guest session no longer fires 401s in the background
|
|
341
|
+
or shows a button that always errors.
|
|
342
|
+
|
|
343
|
+
Gated on `useCanSave()` rather than checking the resolved adapter, because
|
|
344
|
+
`mergeWithDefaults` fills every missing method from the localStorage adapter,
|
|
345
|
+
so `typeof adapter.saveTemplate` is *always* a function by the time anything
|
|
346
|
+
reads it. The signal is computed from the host's partial before merging.
|
|
347
|
+
Passing no adapter at all still counts as "can save" — that is the zero-config
|
|
348
|
+
demo path.
|
|
349
|
+
|
|
350
|
+
### Added
|
|
351
|
+
|
|
352
|
+
**`ready` event.** Fires once the canvas has actually painted its initial
|
|
353
|
+
content, not when the component mounts. Hosts showing a loading placeholder
|
|
354
|
+
were removing it on mount, which is before `loadTemplate` resolves and the rows
|
|
355
|
+
hydrate — so users watched blocks appear one at a time.
|
|
356
|
+
|
|
357
|
+
```vue
|
|
358
|
+
<EmailEditor @ready="showSkeleton = false" />
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Emitted two ticks after the internal ready state flips, so the DOM for that
|
|
362
|
+
first paint exists by the time the handler runs. Fires once per mount.
|
|
363
|
+
|
|
364
|
+
### Note on layout
|
|
365
|
+
|
|
366
|
+
The editor is built around **document scroll**: its shell is `min-h-screen`
|
|
367
|
+
with a `sticky top-0` header, so the canvas grows past the viewport and the
|
|
368
|
+
page scrolls under a pinned toolbar. Giving its container a fixed height with
|
|
369
|
+
`overflow: hidden` clips everything below the fold and leaves no scroll
|
|
370
|
+
container to reach it. Give the container a minimum height, not a maximum.
|
|
371
|
+
|
|
372
|
+
The docs previously said "the editor fills its parent; give it a real height",
|
|
373
|
+
which is easy to read as "one viewport tall, overflow hidden". Reworded.
|
|
374
|
+
|
|
375
|
+
## 0.2.0
|
|
376
|
+
|
|
377
|
+
Adds the write half of the editor's API, version history, a shared row
|
|
378
|
+
library, and two host slots. Nothing in 0.1.x breaks.
|
|
379
|
+
|
|
380
|
+
### Added
|
|
381
|
+
|
|
382
|
+
**Programmatic write API.** The read side (`getHtml`, `getMjml`,
|
|
383
|
+
`getReactEmail`, `getJson`) has always been public; these are its counterpart,
|
|
384
|
+
so a host can drive the canvas from its own UI without reaching into builder
|
|
385
|
+
internals.
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
setJson(data, opts?) // opts.history: "undoable" (default) | "reset"
|
|
389
|
+
getSelection() // { id, type } | null — type is the block type
|
|
390
|
+
setSelection(id) // false if no block has that id
|
|
391
|
+
onChange(cb) // returns an unsubscribe function
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
`setJson` accepts exactly what `getJson()` returns, so `setJson(getJson())`
|
|
395
|
+
round-trips, plus the `{ canvas, content: { rows } }` shape version APIs
|
|
396
|
+
typically return. It defaults to a single undoable step. Available on the Vue
|
|
397
|
+
component ref, on `EditorHandle` from `init()`, and on the custom element.
|
|
398
|
+
|
|
399
|
+
**Version history** — `versions` prop on the component and `init()`. Replaces
|
|
400
|
+
the saved-templates panel and its header button with restore / delete /
|
|
401
|
+
delete-all / keep. Backed by five adapter methods:
|
|
402
|
+
|
|
403
|
+
```ts
|
|
404
|
+
listTemplateVersions(templateId)
|
|
405
|
+
getTemplateVersion(templateId, versionId)
|
|
406
|
+
deleteTemplateVersion(templateId, versionId)
|
|
407
|
+
deleteAllTemplateVersions(templateId) // kept versions survive
|
|
408
|
+
setTemplateVersionKept(templateId, versionId, kept)
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Each control appears only when its method exists, so an adapter that can list
|
|
412
|
+
and restore but not delete gets exactly that. `createLocalStorageAdapter`
|
|
413
|
+
implements all five, so this works with no backend.
|
|
414
|
+
|
|
415
|
+
**Shared saved rows** — `listSystemSavedRows()`. An optional read-only second
|
|
416
|
+
row library in its own tab beside the user's own. The tab appears only when
|
|
417
|
+
the call returns rows. Read-only by construction: there is no save/rename/delete
|
|
418
|
+
counterpart, because who may curate a shared library is a permissions question
|
|
419
|
+
the editor has no user model to answer.
|
|
420
|
+
|
|
421
|
+
**Assistant slot.** The editor supplies a drawer, its trigger, open/close
|
|
422
|
+
state, escape handling and focus return; the host supplies the contents.
|
|
423
|
+
|
|
424
|
+
```vue
|
|
425
|
+
<EmailEditor><template #assistant="{ editor }">…</template></EmailEditor>
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
```ts
|
|
429
|
+
init({ assistant: { mount(el, editor) {…}, unmount(el) {} } })
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
There is no AI in this package. Prompts, endpoints and diff strategy belong to
|
|
433
|
+
whoever is building the product. `mount` runs on first open rather than at
|
|
434
|
+
startup, so a drawer nobody opens costs nothing.
|
|
435
|
+
|
|
436
|
+
**`header-actions` slot.** Host controls beside Save, receiving
|
|
437
|
+
`{ templateId, isSaving, saveStatus }`. Renders nothing when unused.
|
|
438
|
+
|
|
439
|
+
**`brandName`** prop and `init()` option — the "Powered by" line in the
|
|
440
|
+
desktop-only notice. Pass `""` to hide the line entirely.
|
|
441
|
+
|
|
442
|
+
**New exports:** `EditorWriteApi`, `AssistantMount`, `TemplateSummary`,
|
|
443
|
+
`TemplateVersionSummary`.
|
|
444
|
+
|
|
445
|
+
### Fixed
|
|
446
|
+
|
|
447
|
+
**Published types were broken.** `dist/index.d.ts` re-exported `EmailEditor`
|
|
448
|
+
from a path that was never emitted. Consumers with `skipLibCheck: true` (Nuxt's
|
|
449
|
+
default) got `any` — no prop typing, no autocomplete, no error on a misspelled
|
|
450
|
+
prop; with it off, a hard `TS2307`.
|
|
451
|
+
|
|
452
|
+
Two independent causes, both failing silently:
|
|
453
|
+
|
|
454
|
+
1. `vite-plugin-dts` needs `processor: "vue"` to emit SFC declarations. Its own
|
|
455
|
+
warning only fires when the entry or an include glob contains `.vue`, and
|
|
456
|
+
neither did.
|
|
457
|
+
2. `unplugin-dts` gets Vue support from an optional peer on
|
|
458
|
+
`@vue/language-core ^3.1.5`. The playground's `vue-tsc ^2.1.0` hoisted v2 to
|
|
459
|
+
the monorepo root, failing the range check.
|
|
460
|
+
|
|
461
|
+
Fixed by setting `processor: "vue"` and aligning the playground to
|
|
462
|
+
`vue-tsc ^3.3.11`. Declaration coverage went 0 → 122 files.
|
|
463
|
+
|
|
464
|
+
**The typecheck wasn't checking components.** 34 SFCs used `<script setup>`
|
|
465
|
+
without `lang="ts"`, so `vue-shims.d.ts` declared every `*.vue` import as
|
|
466
|
+
`DefineComponent<{}, {}, any>` — which untyped all 121 components as
|
|
467
|
+
collateral. Converted, shim removed, and the 82 latent type errors it was
|
|
468
|
+
hiding are fixed.
|
|
469
|
+
|
|
470
|
+
**`getSelection().type` returned `"component"`** for every block. The tree
|
|
471
|
+
stores the structural kind in `type` and the block kind in `componentType`;
|
|
472
|
+
this returns the latter, which is what the field exists for.
|
|
473
|
+
|
|
474
|
+
### Removed
|
|
475
|
+
|
|
476
|
+
- `optimizeAI.ts` — AI-facing snapshot stripping, unreferenced and belonging to
|
|
477
|
+
a host rather than the editor.
|
|
478
|
+
- `PropertyNumber.vue` — superseded by `PropertyNumberSlider`, unreferenced.
|
|
479
|
+
|