Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/banner-theme-targets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@astryxdesign/core': patch
---

[feat] Banner: the header's supporting line now carries a stable theme target, `astryx-banner-description`. Only the header, the status icon and the content panel were themeable before, so a theme restyling the description — its colour, its type, or the space between it and the title — had to reach in with a structural selector like `.astryx-banner > div:nth-child(2) > div:nth-child(2)`. Purely additive: no existing class, data attribute, or style changes.

Nothing else in the header becomes a target. The end area is a layout row — flex, wrap, and the edge compensation that lets its buttons overhang the header padding — not a painted surface, and a theme that wants the header to grow around its buttons instead of letting them overhang sets `padding-block` on the existing `banner` target, which reaches the same height without exposing a private margin. The title, the two controls and the text column are likewise 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.

@freddymeta
4 changes: 4 additions & 0 deletions packages/core/src/Banner/Banner.doc.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export const docs = {
targets: [
{className: 'astryx-banner', visualProps: ['container', 'status']},
{className: 'astryx-banner-icon', visualProps: ['status']},
{className: 'astryx-banner-description'},
{className: 'astryx-banner-content', visualProps: ['container', 'status']},
],
vars: [
Expand Down Expand Up @@ -199,6 +200,9 @@ export const docsZh = {
'status',
],
},
{
className: 'astryx-banner-description',
},
{
className: 'astryx-banner-content',
visualProps: [
Expand Down
13 changes: 12 additions & 1 deletion packages/core/src/Banner/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
* - Status icon (themeProps 'banner-icon'): the target rides on the default
* <Icon> itself — the element that paints — so 'status:X' overrides reach
* the glyph (#4166); for a custom `icon` node it stays on the layout wrapper
* - Description (themeProps 'banner-description'): the supporting line owns its
* own colour and type, and the space between it and the title
* - The end area carries no target: it is a layout row (flex, wrap, edge
* compensation) rather than a painted surface, and a theme that wants the
* header to grow around its buttons sets `padding-block` on 'banner'
* - No left border accent — color is expressed through the full header background
* - Each visual area owns its own border-radius (no overflow:clip on the container)
* - Children are collapsible by default: a toggle appears in the header end
Expand Down Expand Up @@ -631,7 +636,13 @@ export function Banner({
)}>
<div {...stylex.props(styles.title)}>{title}</div>
{isRenderable(description) && (
<div {...stylex.props(styles.description)}>{description}</div>
<div
{...mergeProps(
themeProps('banner-description'),
stylex.props(styles.description),
)}>
{description}
</div>
)}
</div>
{showEndArea && (
Expand Down
42 changes: 41 additions & 1 deletion packages/themes/probe/src/probeTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// test fixture. Regenerate with: pnpm visual:probe-theme
//
// defineTheme takes six things and this covers all six:
// components 270 targets, 875 selectors (generated from the docs)
// components 272 targets, 881 selectors (generated from the docs)
// tokens custom properties, read back off the themed element
// icons every registry entry swapped for a marked glyph
// indicators check / radio / checkbox swapped — the swap that reaches furthest
Expand Down Expand Up @@ -578,6 +578,14 @@ export const probeTheme = defineTheme({
outlineColor: 'hsl(62.1 85% 25%)',
},
},
'banner-description': {
base: {
backgroundColor: 'hsl(347.7 94% 62%)',
color: 'hsl(118.1 87% 12%)',
borderColor: 'hsl(166.3 80% 25%)',
outlineColor: 'hsl(35.6 93% 25%)',
},
},
'banner-icon': {
base: {
backgroundColor: 'hsl(262.3 84% 51%)',
Expand Down Expand Up @@ -974,6 +982,14 @@ export const probeTheme = defineTheme({
outlineColor: 'hsl(157.5 84% 25%)',
},
},
'carousel-scroller': {
base: {
backgroundColor: 'hsl(330.8 89% 63%)',
color: 'hsl(272.4 89% 12%)',
borderColor: 'hsl(38.3 84% 25%)',
outlineColor: 'hsl(243.2 82% 25%)',
},
},
center: {
base: {
backgroundColor: 'hsl(344.5 75% 59%)',
Expand Down Expand Up @@ -2031,6 +2047,24 @@ export const probeTheme = defineTheme({
borderColor: 'hsl(170.7 73% 25%)',
outlineColor: 'hsl(74.0 75% 25%)',
},
'presentation:popover': {
backgroundColor: 'hsl(152.7 88% 51%)',
color: 'hsl(290.9 87% 12%)',
borderColor: 'hsl(252.4 93% 25%)',
outlineColor: 'hsl(80.4 87% 25%)',
},
'presentation:bottom-sheet': {
backgroundColor: 'hsl(211.4 72% 62%)',
color: 'hsl(32.5 82% 12%)',
borderColor: 'hsl(244.1 72% 25%)',
outlineColor: 'hsl(196.5 89% 25%)',
},
'presentation:adaptive': {
backgroundColor: 'hsl(64.2 82% 63%)',
color: 'hsl(35.5 86% 12%)',
borderColor: 'hsl(42.5 73% 25%)',
outlineColor: 'hsl(88.3 82% 25%)',
},
},
'dropdown-menu-divider': {
base: {
Expand Down Expand Up @@ -4360,6 +4394,12 @@ export const probeTheme = defineTheme({
borderColor: 'hsl(22.0 83% 25%)',
outlineColor: 'hsl(220.9 77% 25%)',
},
'size:xl': {
backgroundColor: 'hsl(66.5 82% 64%)',
color: 'hsl(228.9 83% 12%)',
borderColor: 'hsl(259.5 74% 25%)',
outlineColor: 'hsl(299.9 71% 25%)',
},
'shade:default': {
backgroundColor: 'hsl(94.7 82% 60%)',
color: 'hsl(304.2 86% 12%)',
Expand Down
Loading