diff --git a/.changeset/banner-theme-targets.md b/.changeset/banner-theme-targets.md new file mode 100644 index 0000000000000..924e9c2df2293 --- /dev/null +++ b/.changeset/banner-theme-targets.md @@ -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 diff --git a/packages/core/src/Banner/Banner.doc.mjs b/packages/core/src/Banner/Banner.doc.mjs index 69448259d2f43..a432b6e52ebbe 100644 --- a/packages/core/src/Banner/Banner.doc.mjs +++ b/packages/core/src/Banner/Banner.doc.mjs @@ -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: [ @@ -199,6 +200,9 @@ export const docsZh = { 'status', ], }, + { + className: 'astryx-banner-description', + }, { className: 'astryx-banner-content', visualProps: [ diff --git a/packages/core/src/Banner/Banner.tsx b/packages/core/src/Banner/Banner.tsx index caad611962d1e..864908e76f01d 100644 --- a/packages/core/src/Banner/Banner.tsx +++ b/packages/core/src/Banner/Banner.tsx @@ -15,6 +15,11 @@ * - Status icon (themeProps 'banner-icon'): the target rides on the default * 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 @@ -631,7 +636,13 @@ export function Banner({ )}>
{title}
{isRenderable(description) && ( -
{description}
+
+ {description} +
)} {showEndArea && ( diff --git a/packages/themes/probe/src/probeTheme.ts b/packages/themes/probe/src/probeTheme.ts index 7b13ef022d4b1..24e930c3f26dc 100644 --- a/packages/themes/probe/src/probeTheme.ts +++ b/packages/themes/probe/src/probeTheme.ts @@ -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 @@ -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%)', @@ -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%)', @@ -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: { @@ -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%)',