@seliseblocks/mailcraft 0.2.7 → 0.2.9

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 ADDED
@@ -0,0 +1,99 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@seliseblocks/mailcraft` are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.2.9] — 2026-09-01
8
+
9
+ ### Fixed
10
+ - HTML import keeps a section that paints one background image as **one row**: builder sections (Beefree, Stripo — `table.row[background-image]` holding a stack of per-block tables) previously shredded into one row per block, each stamped with its own copy of the background image, so the export re-drew the image's top slice once per block. Blocks keep their per-block padding through the merge; rows with their own background, frame or image are real band boundaries and are never merged.
11
+ - HTML import reads the section cell's own background color ahead of its wrapper's — a dark hero cell inside a white content table kept `#ffffff` before, so white text over a background photo sat on a white band whenever the image hadn't loaded. Legacy `bgcolor` on a `<tr>` is now read too.
12
+ - Imported headings inherit `color` and `text-align` from the section cell the way text runs always did — a white `<h1>` whose color lived on the `<td>` imported in the default dark ink and vanished into the hero image. An own value on the heading still wins.
13
+ - A bare text run with no element of its own (`<td style="font-size:30px;font-weight:800;color:#0065b2">{{Code}}</td>`) now reads its typography off the surrounding cell — verification codes and similar merge-tag cells imported at the theme default before, dropping size, weight, color and line-height on every save.
14
+ - A card drawn across several stacked content tables (top piece `border-radius:16px 16px 0 0; border-bottom:none`, side-borders-only middles, bottom piece `0 0 16px 16px`) no longer doubles its frame: the fragments are consumed into the one canvas frame the theme claims, while horizontal edges between sections survive as separators.
15
+ - Beefree-style dividers — a content-free cell whose only drawing is a `border-top`, usually in a `width="20%"` inner table — import as the divider block they draw instead of a junk text row holding a hair space.
16
+ - Empty `<p></p>` elements no longer import as phantom padded rows.
17
+ - The inspector's color swatch normalizes `rgb()`, `rgba()` and 3-digit hex before feeding the native picker, which only accepts `#rrggbb` — imported non-hex colors showed a black swatch and opened the picker at black.
18
+ - Text size, Text color, Line spacing, Text weight and Align now reach imported (and AI-drafted) text and list blocks whose content carries its own inline styles. Text size scales the inline hierarchy proportionally (a 15/26/15px block moved to a 45px base becomes 45/78/45); the other controls take ownership of their property, the way the Font control already did. The rewrite happens only when the control is moved, lands in a single undo step, and untouched documents are never rewritten.
19
+ - The rich-text toolbar's Smaller/Larger text buttons clamp to the same range as the inspector (8–96 for text, 12–120 for headings). Previously they clamped to a private 10–64, so one "Larger text" click on a 96px block shrank it to 64.
20
+ - The Smaller/Larger text buttons no longer appear on Section box and Raw HTML blocks, where no size is rendered — clicking them only wrote an inert `size` value into the saved document.
21
+ - Imported list items now pass through the same sanitizer as every other import path: event handlers, classes and `mso-*` noise are stripped while whitelisted inline typography survives.
22
+ - The docs site's Quick-start hero follows the site's own theme toggle instead of the OS scheme, so the colour logo shows on the light page (the near-white dark-mode wordmark no longer paints on white).
23
+
24
+ ### Added
25
+ - Copy button in the code view's toolbar — puts the source pane on the clipboard, unsaved edits included, with a "Copied" confirmation. Localized in all 31 locales from existing strings.
26
+
27
+ ## [0.2.8] — 2026-09-01
28
+
29
+ ### Added
30
+ - Mobile layout modes and per-device visibility handling.
31
+ - Open Graph card generation tooling.
32
+
33
+ ### Fixed
34
+ - HTML import preserves the row → column → blocks structure.
35
+ - Docs site renders the Quick start page (`/README.html` no longer 404s).
36
+
37
+ ## [0.2.7] — 2026-09-01
38
+
39
+ ### Added
40
+ - Brand artwork SVGs and theme-aware logo rendering.
41
+
42
+ ### Fixed
43
+ - Drag and drop: dropped sections land where the indicator line shows.
44
+
45
+ ## [0.2.6] — 2026-08-31
46
+
47
+ ### Fixed
48
+ - Round-trip: saving never mutates the design.
49
+
50
+ ## [0.2.5] — 2026-08-31
51
+
52
+ ### Fixed
53
+ - Visible elevation on the settings panel.
54
+
55
+ ## [0.2.4] — 2026-08-31
56
+
57
+ ### Added
58
+ - Marketing homepage on the docs site.
59
+
60
+ ### Fixed
61
+ - Slider behaviour under RTL locales.
62
+
63
+ ## [0.2.3] — 2026-08-31
64
+
65
+ ### Added
66
+ - Full content-area border as a theme option.
67
+
68
+ ## [0.2.2] — 2026-08-31
69
+
70
+ ### Changed
71
+ - Locales load lazily, one file per language, instead of shipping all translations up front.
72
+ - Preview polish.
73
+
74
+ ## [0.2.1] — 2026-08-31
75
+
76
+ ### Changed
77
+ - Canvas and chrome polish.
78
+
79
+ ## [0.2.0] — 2026-08-31
80
+
81
+ ### Added
82
+ - TypeScript declarations ship with the package.
83
+ - Condition and Loop dynamic-content marker blocks, exported as literal `{{#if}}` / `{{#each}}` template tags.
84
+ - Expanded translations and improved AI draft functionality.
85
+
86
+ ### Removed
87
+ - Seeded example assets in the library; local library handling improved.
88
+
89
+ ## [0.1.1] — 2026-08-30
90
+
91
+ ### Added
92
+ - Documentation site; the full configuration surface documented; restyled demo.
93
+
94
+ ### Fixed
95
+ - Contributing link 404; dark scrollbar on a light page.
96
+
97
+ ## [0.1.0] — 2026-08-30
98
+
99
+ Initial release: a drag-and-drop HTML email editor packaged as a zero-dependency Web Component — HTML-only host contract, configurable top bar, `createEditor` mount API, minified single-file build, and a test suite covering the core, render layer and keyboard shortcuts.
package/DOCS.md CHANGED
@@ -8,18 +8,18 @@
8
8
  - [Why it is built this way](#why-it-is-built-this-way)
9
9
  - [How to use it](#how-to-use-it)
10
10
  - [Install](#install)
11
- - [Two ways to mount](#two-ways-to-mount)
12
- - [Framework wiring](#framework-wiring)
13
- - [Saving and restoring](#saving-and-restoring)
14
- - [Templates](#templates)
15
- - [Merge variables](#merge-variables)
16
- - [Image uploads](#image-uploads)
17
- - [Choosing what the top bar shows](#choosing-what-the-top-bar-shows)
18
- - [Keyboard shortcuts](#keyboard-shortcuts)
19
- - [The footer strip](#the-footer-strip)
20
- - [Language, direction and theme](#language-direction-and-theme)
21
- - [Matching your app's typography](#matching-your-apps-typography)
22
- - [Matching your brand color](#matching-your-brand-color)
11
+ - [Mount the editor](#mount-the-editor)
12
+ - [Wire it into a framework](#wire-it-into-a-framework)
13
+ - [Save and restore](#save-and-restore)
14
+ - [Load templates](#load-templates)
15
+ - [Add merge variables](#add-merge-variables)
16
+ - [Accept image uploads](#accept-image-uploads)
17
+ - [Choose what the top bar shows](#choose-what-the-top-bar-shows)
18
+ - [Use the keyboard shortcuts](#use-the-keyboard-shortcuts)
19
+ - [Configure the footer strip](#configure-the-footer-strip)
20
+ - [Set language, direction and theme](#set-language-direction-and-theme)
21
+ - [Match your app's typography](#match-your-apps-typography)
22
+ - [Match your brand color](#match-your-brand-color)
23
23
  - [API reference](#api-reference)
24
24
  - [How it works inside](#how-it-works-inside)
25
25
 
@@ -55,7 +55,7 @@ A user drags rows and blocks onto a canvas, edits text in place, styles it in an
55
55
 
56
56
  Four decisions shape the whole API. Each is a constraint the host would otherwise inherit.
57
57
 
58
- ### 1. HTML in, HTML out — no document format
58
+ ### 1. HTML in, HTML out — there is no document format
59
59
 
60
60
  The obvious design is to expose the editor's internal document as JSON and let hosts store that. It is also the one that ages worst: the moment a host persists that JSON, its shape becomes a public contract. Every new block type, every renamed prop, every changed default becomes a migration the host has to run against rows in its own database.
61
61
 
@@ -101,7 +101,7 @@ Validation runs *before* the provider is called, so a rejected file never reache
101
101
 
102
102
  An editor embedded in a product that already has a header, a breadcrumb and a Save button ends up with two bars and two logos stacked on each other. So the top bar is switchable down to the individual control, and can be removed entirely.
103
103
 
104
- Most of what the bar does survives without it. Undo, redo and export are element methods; the screenshot methods never needed the bar at all; and the keyboard shortcuts are bound at the window level, not on the bar, so `Ctrl/Cmd+Z`, `Shift+Ctrl/Cmd+Z` and `Ctrl/Cmd+E` keep working either way. Three panels are opened only from the bar, though — the live **preview** overlay, the **Code** modal and the **AI draft** panel — so dropping those parts does take them out of reach. The table under [Choosing what the top bar shows](#choosing-what-the-top-bar-shows) says which is which.
104
+ Most of what the bar does survives without it. Undo, redo and export are element methods; the screenshot methods never needed the bar at all; and the keyboard shortcuts are bound at the window level, not on the bar, so `Ctrl/Cmd+Z`, `Shift+Ctrl/Cmd+Z` and `Ctrl/Cmd+E` keep working either way. Three panels are opened only from the bar, though — the live **preview** overlay, the **Code** modal and the **AI draft** panel — so dropping those parts does take them out of reach. The table under [Choose what the top bar shows](#choose-what-the-top-bar-shows) says which is which.
105
105
 
106
106
  ---
107
107
 
@@ -133,7 +133,7 @@ Without a bundler:
133
133
  <script src="https://unpkg.com/@seliseblocks/mailcraft/dist/mailcraft-editor.bundle.js"></script>
134
134
  ```
135
135
 
136
- ## Two ways to mount
136
+ ## Mount the editor
137
137
 
138
138
  **As a tag**, when the container is part of your markup:
139
139
 
@@ -183,7 +183,7 @@ It is a wrapper, not a second implementation — it creates the same element and
183
183
 
184
184
  By default the editor is appended, so existing content in the container survives; pass `{ replace: true }` to empty it first.
185
185
 
186
- ## Framework wiring
186
+ ## Wire it into a framework
187
187
 
188
188
  The element is framework-agnostic; only the plumbing differs.
189
189
 
@@ -217,7 +217,7 @@ export function EmailEditor({ html, onSave }) {
217
217
 
218
218
  **Vue / Svelte** — both set DOM properties for non-string bindings automatically, so `<mailcraft-editor :toolbar="cfg">` works as written.
219
219
 
220
- ## Saving and restoring
220
+ ## Save and restore
221
221
 
222
222
  ```js
223
223
  // save
@@ -231,7 +231,7 @@ Editing continues where it left off. Anything the importer cannot classify into
231
231
 
232
232
  The editor also autosaves to `localStorage`, scoped **per browser tab**, so two tabs are two independent documents. That is a convenience for reload, not your persistence layer.
233
233
 
234
- ## Templates
234
+ ## Load templates
235
235
 
236
236
  Templates are host content **and** host UI. The editor ships no catalogue and has no Templates tab — you render your own picker and push the choice in:
237
237
 
@@ -241,7 +241,7 @@ editor.loadTemplate({ name: 'Welcome', html });
241
241
 
242
242
  Applying one is a normal undoable edit with a toast, and your string is never mutated. Ready-made examples ship in the package under `examples/templates/`, with a working picker in [`examples/vanilla.html`](examples/vanilla.html) — both host-app content, shipped in the package for you to lift but not part of its API.
243
243
 
244
- ## Merge variables
244
+ ## Add merge variables
245
245
 
246
246
  ```html
247
247
  <mailcraft-editor variables="first_name,company,unsubscribe_url"></mailcraft-editor>
@@ -267,7 +267,7 @@ The exporter balances the document as a whole: a stray end marker emits nothing,
267
267
 
268
268
  A start marker's expression field suggests the host's `variables` in a dropdown but stays free text, since conditions and loops routinely reference names that aren't inline tokens (`order.items`, a boolean flag, whatever your engine understands).
269
269
 
270
- ## Image uploads
270
+ ## Accept image uploads
271
271
 
272
272
  A provider and a `maxBytes` ceiling are both required. The package ships no files of its own: with no provider the library opens empty and holds only what is dropped into it — data URIs, kept in the local draft, which no email client renders. With a provider but no `maxBytes` every upload is refused.
273
273
 
@@ -322,7 +322,7 @@ Setting `editor.storageProvider = null` drops back to that empty local library.
322
322
 
323
323
  `examples/vanilla.html` wires a working provider over IndexedDB — latency, cursor paging, server-side folders and search, uploads that survive a reload, deletes that stay deleted. It is the shape of a real integration with `fetch` swapped out, and it is where every file in the live demo's Assets modal comes from.
324
324
 
325
- ## Choosing what the top bar shows
325
+ ## Choose what the top bar shows
326
326
 
327
327
  ```html
328
328
  <mailcraft-editor toolbar="none"></mailcraft-editor> <!-- no bar -->
@@ -340,7 +340,7 @@ The **attribute names what to keep**; the **property names what to drop**. Marku
340
340
 
341
341
  `none` is the documented spelling for "no bar"; `hidden`, `off` and `false` are accepted as the same thing, and `toolbar="all"` is the explicit form of the default. The property takes `false` for no bar, and an object where only the keys set to `false` do anything — unlisted parts stay on.
342
342
 
343
- ### What a hidden part costs you
343
+ ### The cost of a hidden part
344
344
 
345
345
  | part | with the bar gone |
346
346
  |---|---|
@@ -356,7 +356,7 @@ Screenshots are unaffected by any of this: `screenshotPng()`, `previewScreenshot
356
356
 
357
357
  `editor.core` reaches the rest (`core.openCode()`, `core.setState({ aiOpen: true })`, `core.setState({ previewOpen: true })`), but `EditorCore` is internal — its shape is free to change between versions. Keep `code`, `ai` or `preview` in the bar if you need them.
358
358
 
359
- ## Keyboard shortcuts
359
+ ## Use the keyboard shortcuts
360
360
 
361
361
  Bound at the window level while the editor is connected, so they work with any bar configuration, including none.
362
362
 
@@ -374,7 +374,7 @@ Typing is never hijacked: inside a form field, `Ctrl/Cmd+Z` is the browser's own
374
374
 
375
375
  One caveat if your app binds the same keys: the handler asks whether the event came from a text field, not whether it came from inside the editor. `Ctrl/Cmd+E` anywhere on the page opens the export dialog, and `Backspace` on a non-field element elsewhere in your UI deletes the editor's selected block. An editor kept on a route of its own never notices; one sitting beside your own keyboard-driven UI might, and the fix is to `stopPropagation()` on the keydowns you own before they reach `window`.
376
376
 
377
- ## The footer strip
377
+ ## Configure the footer strip
378
378
 
379
379
  The editor carries a one-line attribution along the bottom of the shell:
380
380
 
@@ -411,7 +411,7 @@ editor.messages = { 'footer.poweredBy': 'Powered by Acme' };
411
411
 
412
412
  Hiding the strip collapses its row — the canvas keeps every pixel it had.
413
413
 
414
- ## Language, direction and theme
414
+ ## Set language, direction and theme
415
415
 
416
416
  ```html
417
417
  <mailcraft-editor locale="de" theme="dark"></mailcraft-editor>
@@ -429,7 +429,7 @@ editor.messages = { 'action.export': 'Send to campaign' };
429
429
 
430
430
  Every key, with its English default, is listed in [Every message key](#every-message-key). English is always the floor: a key your table leaves out shows the built-in English rather than a gap, and `missingKeys(yourTable)` tells you what a full replacement still lacks.
431
431
 
432
- ## Matching your app's typography
432
+ ## Match your app's typography
433
433
 
434
434
  ```html
435
435
  <mailcraft-editor ui-font="inherit"></mailcraft-editor>
@@ -438,7 +438,7 @@ Every key, with its English default, is listed in [Every message key](#every-mes
438
438
 
439
439
  Editor chrome only — never the fonts inside the email being edited.
440
440
 
441
- ## Matching your brand color
441
+ ## Match your brand color
442
442
 
443
443
  ```html
444
444
  <mailcraft-editor accent="#e11d48"></mailcraft-editor>
package/README.md CHANGED
@@ -59,7 +59,7 @@ Exported HTML is valid input to `loadTemplate`, so saving the export *is* saving
59
59
 
60
60
  Every attribute is also a property. TypeScript declarations ship with the package. Full reference and integration recipes: **[DOCS.md](DOCS.md)**.
61
61
 
62
- ## For AI agents
62
+ ## Paste into your AI agent
63
63
 
64
64
  Everything an assistant needs to wire this up correctly:
65
65
 
package/README.md.txt CHANGED
@@ -59,7 +59,7 @@ Exported HTML is valid input to `loadTemplate`, so saving the export *is* saving
59
59
 
60
60
  Every attribute is also a property. TypeScript declarations ship with the package. Full reference and integration recipes: **[DOCS.md](DOCS.md)**.
61
61
 
62
- ## For AI agents
62
+ ## Paste into your AI agent
63
63
 
64
64
  Everything an assistant needs to wire this up correctly:
65
65