Fix two reconciler bugs surfaced by Step 6 smoke testing#22
Merged
Conversation
Both pre-date the inspector field-as-data refactor (verified by tracing the original closure call paths to the same broken outcomes). Surfaced when smoke-testing PR #21 against `x-icon` and the layout dimension fields. ## 1. Stale SVG markup after clearing inspector field (canvas.cljs) `patch-element!` derived `raw-html?` from `(some? (:inner-html node))` of the *new* node. When the user cleared an x-icon's SVG editor, the new value became nil → `raw-html?` flipped to false → the `(when raw-html? (rec/set-inner-html! …))` branch was skipped → the live DOM kept the old innerHTML. Visible as: clearing the textarea in the inspector seemed to do nothing on the canvas. Fix: derive `raw-html?` from the tag's `:raw-html-slot?` meta (the `meta/augment` flag that distinguishes raw-html-slot tags like x-icon from structured-slot tags). The reconciler now manages inner-html for the lifetime of any raw-html-slot node, regardless of whether the current value is set or cleared. ## 2. Bare numeric width / height ignored (reconcile.cljs) `layout->css` emitted named width / height via raw `(str "width:" v)` without unit coercion. Typing `200` into an inspector layout field landed in the doc as the string `"200"`, the reconciler emitted `width:200;`, the browser dropped it as invalid CSS. Only `200px` worked. Meanwhile the `:free` placement's x/y/w/h have always gone through `as-length` which adds `px` to numeric *number* values, but `as-length` itself didn't recognise bare numeric *strings*. Two coordinated fixes: - `as-length` now recognises a bare numeric string (matched by `numeric-string-re` — optionally negative integer or decimal) and applies the same `px` default the number branch uses. Unit'd strings (`50%`, `10rem`, `auto`) still pass through. - `layout->css`'s named branch routes width / height through `as-length`, so `width "200"` → `width:200px;` and `width 200` → `width:200px;` both produce valid CSS. Padding / margin keep their string-only behaviour because their multi-value forms (`10px 20px`, `1em 2em 3em 4em`) don't fit `as-length`'s single-value contract — left for a future variant if needed. Adds 5 reconciler tests covering bare-numeric-string, actual- number, unit'd-string, and height-with-bare-numeric paths. The existing layout-css tests pass unchanged (string-with-unit behaviour is preserved). CI gates green; 718 / 0 failures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 1, 2026
Merged
avanelsas
added a commit
that referenced
this pull request
May 2, 2026
* Release v0.3.0 — minor release with multi-step actions, State panel, inline binding chip, templates revamp + Hickey-style export pipeline refactor Promotes the [Unreleased] section in CHANGELOG.md to a tagged [0.3.0] — 2026-05-02 entry, adds the standard ### Verified block, and refreshes the comparison links at the bottom. package.json's version bumps 0.2.0 → 0.3.0 to match. This is a minor (not patch) release because PRs #16-#19, #21 add substantial editor surfaces (multi-step actions, live State panel, inline binding chip, templates panel revamp with five new starters, inspector field-as-data foundation), and PRs #20 / #23 / #24 / #25 land the full Hickey-style refactor of the export pipeline (clj-form data values for every codegen path; lower-document as the canonical lowered model every plugin consumes). PRs #15 and #22 fix three reconciler bugs along the way. Saved project files are unchanged; every export target stays at parity. Verified locally: - 747 tests / 2243 assertions / 0 failures / 0 errors. - npx shadow-cljs release app — 0 warnings under Closure Advanced. - clj-kondo --lint src test scripts — 0 errors, 0 warnings. - cljfmt check — all files formatted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * CHANGELOG: tighten v0.3.0 entry Drop the per-PR detail in favour of a brief summary. Each bullet is one line / one short paragraph; the inline rationales and namespace-level notes move out of the changelog (commit messages and PR descriptions are the canonical record for those). Net: 165 lines of v0.3.0 entry → 60 lines. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two pre-existing reconciler bugs surfaced while smoke-testing PR #21
(Step 6 inspector field-as-data). Both pre-date that refactor —
verified by tracing the original closure call paths to the same
broken outcomes. Held off PR #21 to keep its scope clean
(inspector field-as-data only); landing here as a focused fix
PR alongside.
One commit, all four CI gates green, 739 tests passing
(734 baseline + 5 new).
Bugs fixed
1. Stale SVG markup after clearing inspector field —
canvas.cljspatch-element!derivedraw-html?from(some? (:inner-html node))of the new node. When the user cleared an x-icon's SVG editor,
the new value became nil →
raw-html?flipped to false → the(when raw-html? (rec/set-inner-html! …))branch was skipped →the live DOM kept the old innerHTML. Visible as: clearing the
inspector textarea seemed to do nothing on the canvas.
Fix: derive
raw-html?from the tag's:raw-html-slot?meta(the
meta/augmentflag that distinguishes raw-html-slot tagslike x-icon from structured-slot tags). The reconciler now
manages inner-html for the lifetime of any raw-html-slot node,
regardless of whether the current value is set or cleared.
2. Bare numeric width / height ignored —
reconcile.cljslayout->cssemitted named width / height via raw(str "width:" v)without unit coercion. Typing
200into an inspector layoutfield landed in the doc as the string
"200", the reconcileremitted
width:200;, the browser dropped it as invalid CSS.Only
200pxworked.Meanwhile the
:freeplacement's x/y/w/h have always gonethrough
as-lengthwhich addspxto numeric number values,but
as-lengthitself didn't recognise bare numeric strings.Two coordinated fixes:
as-lengthnow recognises a bare numeric string (matched bynumeric-string-re— optionally negative integer or decimal)and applies the same
pxdefault the number branch uses.Unit'd strings (
50%,10rem,auto) still pass through.layout->css's named branch routes width / height throughas-length, sowidth \"200\"→width:200px;andwidth 200→width:200px;both produce valid CSS. Padding /margin keep their string-only behaviour because their multi-
value forms (
10px 20px,1em 2em 3em 4em) don't fitas-length's single-value contract — left for a futurevariant if needed.
Test plan
clj-kondo --lint src test scripts— 0 errors, 0 warningscljfmt check— cleannpx shadow-cljs compile test— 739 tests, 0 failures, 0 errorsnpx shadow-cljs release app— 0 warningsx-icononto canvas, paste an SVG, clear thetextarea — icon should disappear (regression-tests bug 1).
200in the layout widthfield — width should apply (regression-tests bug 2). Then
type
200px,50%,10rem— all should still work.Related
🤖 Generated with Claude Code