@the-portland-company/canvas-editor 0.4.2 → 0.5.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 CHANGED
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 — Email-Engine spec closeout: canvas bug fixes
4
+
5
+ Verified against `Specs/Email-Engine` and `Reference/VRM-Canvas-Editor` (v1.0).
6
+ Each item below cites its spec goal id.
7
+
8
+ - `g_3fzwvq` (fixed): the canvas body column painted an opaque white
9
+ background whenever `EmailSettings.bodyBackground` was unset, instead of
10
+ showing no chosen surface color. `CanvasArea.tsx`'s body-column fallback is
11
+ now `transparent`, matching the compiled-HTML editor's already-correct
12
+ "unset until chosen" semantics.
13
+ - `g_wd6vic` / `g_1wwx0r7` (already correct, verified): container drop-zone
14
+ chrome (dashed border/padding) only renders when a container is empty or
15
+ hovered; populated containers get no extra system padding. No change
16
+ needed in `blocks/padding.ts` or the registry defaults.
17
+ - `g_sscrkb` / `g_utd4ya` (already correct, verified): `DropZone.tsx` places
18
+ a hover-revealed insert affordance in every gap of every container (root
19
+ list, Section children, Column cells), in both `center` and `side` modes.
20
+ - `g_1yfbja5` / `g_5jfut` (already correct, verified): `SortableBlock`
21
+ disables its transition while dragging and `DropZone` collapses to an 8px
22
+ strip until the pointer is directly over it, avoiding layout jank.
23
+ - `g_ax3c3i` / `g_3y02ud` (fixed): the merged heading+text rich-text
24
+ component existed (`CanvasRichText`'s `isHeading` prop, the registry's
25
+ `hiddenFromLibrary` legacy heading block, migration already in place), but
26
+ the only `CanvasRichText` mount (`CanvasArea.tsx`, inline Text editing)
27
+ never passed `isHeading`, so the H1–H4 toggle was unreachable. Now passes
28
+ `isHeading` so headings are made inside Text, as the spec requires.
29
+ - `g_1h8sbt3` / `g_qa3uoe` (already correct, verified): `ColorField`,
30
+ `CanvasSettingsPanel`, and the Footer/Section/Card renderers already read
31
+ and apply their respective background/text/link colors; no propagation gap
32
+ found.
33
+ - `g_1eyavta` (fixed): `MediaLibrary.tsx`'s upload handler discarded the
34
+ upload response's own `assetId`/`url` and relied on a subsequent list
35
+ reload to make the asset available, which could race a CDN/read-replica lag
36
+ and hand back a stale or empty entry — producing broken image links right
37
+ after upload. `handleUpload` now builds the asset from the upload response
38
+ directly and auto-inserts a single uploaded image onto the canvas.
39
+
3
40
  ## 0.4.2 — tray fits the canvas column
4
41
 
5
42
  - The tile strip shrinks and scrolls horizontally so the Side | Center toggle,
package/dist/editor.cjs CHANGED
@@ -2165,7 +2165,12 @@ function CanvasArea({
2165
2165
  ref: setNodeRef,
2166
2166
  className: "min-h-[24rem]",
2167
2167
  style: {
2168
- background: settings?.bodyBackground || "#ffffff",
2168
+ // Invisible until the user actually picks a body background (canvas
2169
+ // UX feedback #1/#6): an unset value must NOT paint white, or the
2170
+ // canvas shows a surface the user never chose and "changing the
2171
+ // background color doesn't change anything" reads as a bug when
2172
+ // white was really just the system default fighting the real color.
2173
+ background: settings?.bodyBackground || "transparent",
2169
2174
  // Padding lives on the column that paints bodyBackground so the
2170
2175
  // canvas matches the rendered email, where the same padding is
2171
2176
  // inside the coloured content table.
@@ -2248,6 +2253,7 @@ function SortableBlock({
2248
2253
  {
2249
2254
  html: effectiveProps.html || "",
2250
2255
  onChange: (html) => onInlineChange(block.id, { html }),
2256
+ isHeading: true,
2251
2257
  className: "textarea",
2252
2258
  style: {
2253
2259
  minHeight: "3rem",
@@ -3691,12 +3697,27 @@ function MediaLibrary({
3691
3697
  const handleUpload = async (files) => {
3692
3698
  if (!files || files.length === 0) return;
3693
3699
  setError(null);
3700
+ const uploaded = [];
3694
3701
  for (const file of Array.from(files)) {
3695
3702
  const result = await adapter.media.upload(file);
3696
3703
  if (!result.ok) {
3697
3704
  setError(result.error);
3698
3705
  continue;
3699
3706
  }
3707
+ uploaded.push({
3708
+ id: result.assetId,
3709
+ url: result.url,
3710
+ content_type: result.contentType,
3711
+ filename: result.filename,
3712
+ size_bytes: file.size,
3713
+ alt_text: null
3714
+ });
3715
+ }
3716
+ if (uploaded.length > 0) {
3717
+ setAssets((prev) => [...uploaded, ...(prev ?? []).filter((a) => !uploaded.some((u) => u.id === a.id))]);
3718
+ if (uploaded.length === 1 && uploaded[0].content_type.startsWith("image/")) {
3719
+ onInsert(uploaded[0]);
3720
+ }
3700
3721
  }
3701
3722
  load(search);
3702
3723
  };