Skip to content

feat(Banner): theme target for the description - #5483

Merged
freddymeta merged 10 commits into
mainfrom
feat/banner-theme-targets
Sep 1, 2026
Merged

feat(Banner): theme target for the description#5483
freddymeta merged 10 commits into
mainfrom
feat/banner-theme-targets

Conversation

@freddymeta

@freddymeta freddymeta commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Follows #5417 — same problem, one more component.

What is unreachable today

Banner exposes three theme targets — astryx-banner (the tinted header), astryx-banner-icon, and astryx-banner-content. The header's supporting line renders with bare stylex.props, so a theme that wants to restyle it has to reach in with a structural selector:

.astryx-banner > div:nth-child(2) > div:nth-child(2) { … }

That says "the second div inside the second div", which is a guess about internals — it keeps parsing and silently stops matching the day the DOM changes.

The change

One target: astryx-banner-description.

It names a painted element with a demonstrated use. Astryx paints the description --color-text-secondary; a downstream theme of ours wants it primary, and today the only way there is re-scoping --color-text-secondary across the whole header, which repaints everything else in there that reads the token. It also owns the 2px gap under the title — the header's text column is gap: 0, and banner's rowGap is the wrap gap, not this one.

Purely additive: no existing class, data attribute or style changes, and the render is byte-identical.

What came out, and why

Two things from review, both correct:

banner-actions is gone. It named the end area, which is a layout row — flex, wrap, margin-inline-start: auto, and the negative block margin that lets its buttons overhang the header padding. Not a painted surface, so it fails the theme-target rule the same way a display: contents wrapper does. The use it was meant to serve — a header that grows around its buttons rather than letting them overhang — is padding-block on the existing banner target, which reaches the same 44→52px without exposing a private margin as contract.

The centring commit is reverted, and @cixzhang was right that it changed nothing. I checked before deleting it. Measured in Chromium, forcing both alignments on the same DOM:

                    flex-start (main)   center (my commit)
header height       44                  44
title column mid    38                  38
toggle mid          38                  38
DELTA               0                   0

The arithmetic: the title's line box is 14px × 1.4286 = 20px, and the toggle is a 28px control carrying marginBlock: -4px — so its outer height is 28 − 8 = 20px too. Both items are 20px, the row is 20px, and align-items has nothing to resolve. That negative margin exists precisely to cancel the 4px I claimed was a bug: I reasoned from the button's 28px and missed the margin two lines above it in the same stylesheet.

It would only ever have fired once a theme overrode that margin — which is to say, only through banner-actions. Removing one removed the other's reason to exist.

Verified the alternative too: padding-block 12px → 16px on banner takes a title-only header 44 → 52px with the title and control centres still equal at 0px offset.

Nothing else in the header becomes a target

The title, the two controls and the text column are deliberately left alone: the column paints nothing (display: flex; flex-direction: column; gap: 0) and the space it owns is expressible on banner-description, while the title and the controls already render the way the consuming theme wants them. The changeset says so, so the next person does not re-propose the row.

Verification

  • pnpm exec vitest run packages/core/src/Banner — 52 pass.
  • tsc --noEmit clean, lint:strict 0 errors in the touched files.
  • Chromium measurements above, against a real Storybook build.

@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview Aug 31, 2026 8:16am

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 25, 2026
@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge needs:design-review Affects visuals — Design should review labels Aug 25, 2026
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

Banner (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 427 -
Complexity N/A Very High (44) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.8KB 1.2KB

Accessibility Audit

Status: No accessibility violations detected.

Visual Regression

268 added · 0 removed. View the report

To accept these exact frames: /accept-visual 33371804626/1 <reason>

Added — After
Added — After visual regression frame

Added — After
Added — After visual regression frame

Added — After
Added — After visual regression frame


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

github-actions Bot added a commit that referenced this pull request Aug 25, 2026
github-actions Bot added a commit that referenced this pull request Aug 25, 2026
@freddymeta
freddymeta force-pushed the feat/banner-theme-targets branch from 51e8349 to 6a06cd0 Compare August 25, 2026 09:56
@freddymeta freddymeta changed the title feat(Banner): theme targets for the title, description and actions row feat(Banner): theme targets for the description, actions row and dismiss control Aug 25, 2026
@freddymeta
freddymeta marked this pull request as ready for review August 25, 2026 10:13
github-actions Bot added a commit that referenced this pull request Aug 25, 2026
The header's supporting line and its end-aligned actions row render with only
StyleX atomics, so a theme cannot reach them: `astryx-banner` stops at the
tinted header and the rest of the header is selectable only by child order.

Add `astryx-banner-description` and `astryx-banner-actions` via
`mergeProps(themeProps(...), stylex.props(...))`, documented in `docs` and
`docsZh`. Purely additive.
…lapse toggle

`isSingleLine` drives the header's vertical centering and counted `endContent`
and the dismiss button, but not the collapse toggle. A collapsible title-only
banner therefore kept `align-items: flex-start` while the same banner with a
dismiss button centered — its icon and title sat 4px above the 28px toggle
beside them. The toggle is the same control in the same row, so it counts.
@freddymeta
freddymeta force-pushed the feat/banner-theme-targets branch from 6a06cd0 to 29eabdb Compare August 26, 2026 03:11
@freddymeta freddymeta changed the title feat(Banner): theme targets for the description, actions row and dismiss control feat(Banner): theme targets for the description and actions row Aug 26, 2026
github-actions Bot added a commit that referenced this pull request Aug 26, 2026

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for narrowing this. banner-description now names a painted element with a demonstrated use, but banner-actions still exposes the flex/wrap/margin/edge-compensation row rather than a visual surface.

In Chromium, the centering commit changes zero pixels under shipped styles in light, dark, RTL, and forced colors; it only changes pixels after that private row margin is overridden. Setting padding-block on the existing banner target gets the same 44→52px result and keeps the title/control centers equal without exposing the row.

Could we keep banner-description and drop banner-actions plus the centering commit?

[Reviewed by Robohands]

github-actions Bot added a commit that referenced this pull request Aug 27, 2026
@freddymeta freddymeta changed the title feat(Banner): theme targets for the description and actions row feat(Banner): theme target for the description Aug 28, 2026
@freddymeta

Copy link
Copy Markdown
Contributor Author

Title and body refreshed — thanks for catching that; both still described the two-target, two-commit version that no longer exists.

Title is now feat(Banner): theme target for the description (singular), and the body covers what actually ships: one target, why banner-actions came out, and the Chromium measurement showing the centring commit was inert — including the arithmetic I got wrong the first time (the toggle's marginBlock: -4px already cancels the 4px I claimed to be fixing).

@freddymeta

Copy link
Copy Markdown
Contributor Author

Merged latest main (17 commits behind) — which also regenerates the visual evidence, since the report from 27 Aug had expired to a 404 and visual-acceptance was the only thing left blocking this.

Component suite re-run green on the merge. No source change in this push.

@freddymeta

Copy link
Copy Markdown
Contributor Author

/accept-visual

@github-actions

Copy link
Copy Markdown
Contributor

Visual acceptance refused: copy the exact /accept-visual <run>/<attempt> <reason> command from the report.

@freddymeta
freddymeta requested a review from cixzhang August 28, 2026 13:30

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The target itself is well placed on documented, painted anatomy, and unthemed pixels remain unchanged. One mechanical requirement is missing: visual:probe-theme:check fails because generated probe coverage does not include banner-description.

Please regenerate and commit the required probe output so the visual gate exercises the new public target.

[Reviewed by Robohands]

`visual:probe-theme:check` was failing: the generated probe theme did not
cover `astryx-banner-description`, so the visual gate could not exercise the
new public target.

The generator emits the file wholesale, so this also picks up probe coverage
that main is already missing — `carousel-scroller` with its three
`presentation:` variants (#5601) and `dropdown-menu-divider`'s `size:xl`.
Clean `origin/main` fails the same check today; no workflow runs the guard, so
the drift accumulates until a PR that touches a theming target regenerates it.
@github-actions github-actions Bot added the needs:code-review High-risk change (new package/component/API) — needs human code review before merge label Aug 31, 2026
@freddymeta

Copy link
Copy Markdown
Contributor Author

Regenerated and pushed in 2777396cb (on a merge of current main). pnpm visual:probe-theme:check is green: 272 targets, 881 selectors, and banner-description is now covered.

The generated file carries more than my target, and I want to be explicit about which is which. The generator emits probeTheme.ts wholesale, so regenerating also picks up coverage main is already missing:

Added entry Owner
banner-description this PR
carousel-scroller + presentation:popover / presentation:bottom-sheet / presentation:adaptive #5601
dropdown-menu-dividersize:xl main

I could not commit only my own entry — the file is @generated and the check regenerates it whole — so those five ride along. Clean origin/main fails this same check today, at fbfe729d1:

$ git worktree add /tmp/mainprobe origin/main && cd /tmp/mainprobe && pnpm visual:probe-theme:check
::error::The probe theme is out of date — a theming target changed without regenerating it.

The reason it drifted is that no workflow runs this guard. visual:probe-theme:check appears only in package.json; ci.yml never invokes it, and check:repo in lint.yml does not include it. So the check is only ever run by hand — as you did on this PR — and a target added without regenerating stays uncovered until someone else's PR happens to regenerate. Happy to wire it into check:repo as a separate one-line PR if you want it enforced; I have left it out of this one.

Verification

  • pnpm visual:probe-theme:check — ✅ 272 targets, 881 selectors
  • Banner suite 56/56; packages/core/src/theme/ + .github/scripts/visual-gate/ 36 files / 1077 tests, all pass
  • Negative control: deleting the astryx-banner-description line from Banner.doc.mjs makes the check fail again, so the coverage is genuinely tied to the doc entry rather than passing by construction

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this addresses my previous review: probe coverage now includes banner-description. Please add a direct Banner test pinning that target before merge; no further review needed.

[Reviewed by Robohands]

@github-actions github-actions Bot removed the needs:code-review High-risk change (new package/component/API) — needs human code review before merge label Sep 1, 2026
@freddymeta
freddymeta merged commit 917db9e into main Sep 1, 2026
27 of 28 checks passed
@github-actions
github-actions Bot deleted the feat/banner-theme-targets branch September 2, 2026 06:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. community Authored by a community contributor (not on the eng/design team)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants