Skip to content

fix(import): keep the content a compound button wraps - #476

Merged
DavidBabinec merged 3 commits into
CoreBunch:mainfrom
m-altaifi:fix/import-compound-button-children
Sep 2, 2026
Merged

fix(import): keep the content a compound button wraps#476
DavidBabinec merged 3 commits into
CoreBunch:mainfrom
m-altaifi:fix/import-compound-button-children

Conversation

@m-altaifi

Copy link
Copy Markdown
Contributor

Summary

Fixes #413.

A <button> or a .btn anchor that wrapped an icon, an inline <svg> or an <img> alongside its label imported as a label-only node. base.button is canHaveChildren: false, so the nested markup had nowhere to go and was dropped without a warning — while any image it referenced stayed behind in the Media Library, which makes the missing content hard to trace back to the import.

This handles it the way the heading and label rules in the same file already handle the same problem: keep the leaf mapping while the element holds nothing but text, and recurse into a child-capable module when it wraps elements.

  • A compound .btn anchor maps to base.link — what the plain anchor rule directly below it already does for a compound <a> — which keeps href and target. Class names ride along as classIds, so .btn styling is unaffected by the module swap.
  • A compound non-submit <button> maps to a base.container tagged button, mirroring how a wrapper <label> becomes a container tagged label.
  • Text-only buttons and anchors are untouched and still map to base.button.

Submit buttons are deliberately excluded. core/forms identifies a form's submit control by the base.submit module id (src/core/forms/snapshot.ts), so re-tagging one as a container would leave the form without a submit. A compound submit button therefore still keeps only its label — lifting that needs base.submit to accept children, which is a module change rather than an importer one, so it felt like the wrong thing to fold into this PR. Happy to follow up if you'd like it covered.

The issue also offered a warning as a fallback if preservation wasn't practical. Since the content is now preserved, no import-descendants-dropped warning was added.

Note on an existing test

svgMapping.test.ts had a case asserting the old behaviour — "a btn-classed anchor stays base.button (icon not preserved — buttons are leaves)" — which is the limitation #413 reports. It now asserts preservation, and a new case covers the text-only .btn anchor that still maps to base.button.

The docs table's a (no btn class) row also said "No" for recurse while that rule already recursed on element children; corrected in passing since the neighbouring rows changed.

Verification

  • bun run build
  • bun test
  • bun run lint
  • Docker/deployment check, if relevant — not relevant, no deployment surface touched

bun test on this branch: 6721 pass, 19 fail. All 19 failures are pre-existing on main — I ran the full suite on a clean origin/main checkout to confirm, and the failure sets are identical apart from one flaky SQLite concurrency test that failed on the baseline run and passed here. None are in src/__tests__/htmlImport, which is 195 pass, 0 fail.

Both new preservation tests were confirmed to fail without the rules.ts change and pass with it.

Checklist

  • Tests cover behavior changes.
  • Docs were updated when behavior, config, deployment, or public surfaces changed — docs/features/html-import.md mapping table + a key-details entry, and a CHANGELOG entry under 0.0.18.
  • No compatibility shim was added for old pre-release behavior.
  • No secrets, local databases, uploads, or generated artifacts are included.

M and others added 3 commits September 1, 2026 20:34
A `<button>` or a `.btn` anchor that wrapped an icon, an inline `<svg>` or
an `<img>` alongside its label imported as a label-only node. base.button
is `canHaveChildren: false`, so the nested markup had nowhere to go and was
dropped without a warning, while any image it referenced stayed behind in
the Media Library — leaving the missing content hard to trace back to the
import.

Handle it the way the heading and label rules already handle the same
problem: keep the leaf mapping while the element holds nothing but text,
and recurse into a child-capable module when it wraps elements. A compound
`.btn` anchor maps to base.link, which is what the plain anchor rule below
it already does for a compound `<a>` and which keeps href and target. A
compound non-submit `<button>` maps to a container tagged `button`. Class
names ride along as classIds, so `.btn` styling is unaffected by the swap.

Submit buttons stay on base.submit even when compound: core/forms
identifies a form's submit control by that module id, so re-tagging one as
a container would leave the form without a submit. A compound submit button
therefore still keeps only its label; lifting that needs base.submit to
accept children, which is a module change rather than an importer one.

The svgMapping case that asserted the old behaviour ("icon not preserved —
buttons are leaves") now asserts preservation, with a new case covering the
text-only anchor that still maps to base.button.

Closes CoreBunch#413
Release notes are written in the release-preparation PR from the merged
PRs, so feature and fix PRs leave CHANGELOG.md untouched.
PR 480 landed doc rows for the img rule next to the anchor and button
rows this branch rewrites; both sides are kept.
@DavidBabinec
DavidBabinec merged commit 14b933b into CoreBunch:main Sep 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: HTML import silently drops descendants inside button and a.btn elements

2 participants