diff --git a/.changeset/banner-single-line-toggle.md b/.changeset/banner-single-line-toggle.md new file mode 100644 index 0000000000000..e7783b6b1d8e2 --- /dev/null +++ b/.changeset/banner-single-line-toggle.md @@ -0,0 +1,7 @@ +--- +'@astryxdesign/core': patch +--- + +[fix] Banner: a title-only collapsible banner now centers its header, as a title-only banner with any other control already does. `isSingleLine` counted `endContent` and the dismiss button but not the collapse toggle, so a banner whose only control was the toggle kept `align-items: flex-start` — leaving its icon and title 4px above the 28px toggle they sit beside, while the same banner with a dismiss button centered correctly. + +@freddymeta diff --git a/packages/core/src/Banner/Banner.test.tsx b/packages/core/src/Banner/Banner.test.tsx index c092c3e5b2ecd..501413bd77192 100644 --- a/packages/core/src/Banner/Banner.test.tsx +++ b/packages/core/src/Banner/Banner.test.tsx @@ -650,4 +650,44 @@ describe('Banner', () => { expect(getComputedStyle(textColumn).flexBasis).not.toBe('8rem'); }); }); + describe('single-line centering', () => { + const headerOf = (ui: React.ReactElement) => { + const {container} = render(ui); + return container.firstElementChild!.firstElementChild!; + }; + + it('centers a title-only banner that has a dismiss button', () => { + const header = headerOf( + , + ); + expect(getComputedStyle(header).alignItems).toBe('center'); + }); + + it('centers a title-only banner whose only control is the collapse toggle', () => { + const header = headerOf( + +

Details

+
, + ); + expect(getComputedStyle(header).alignItems).toBe('center'); + }); + + it('keeps a described banner top-aligned, toggle or not', () => { + const header = headerOf( + +

Details

+
, + ); + expect(getComputedStyle(header).alignItems).toBe('flex-start'); + }); + + it('keeps a banner with no controls at all top-aligned', () => { + const header = headerOf( + +

Details

+
, + ); + expect(getComputedStyle(header).alignItems).toBe('flex-start'); + }); + }); }); diff --git a/packages/core/src/Banner/Banner.tsx b/packages/core/src/Banner/Banner.tsx index 95a6ea5ca8fd8..d25ceea2fcf01 100644 --- a/packages/core/src/Banner/Banner.tsx +++ b/packages/core/src/Banner/Banner.tsx @@ -534,8 +534,11 @@ export function Banner({ // Show the end area if there are actions, dismiss, or a collapsible toggle const showEndArea = isRenderable(endContent) || isDismissable || hasToggle; // Center items vertically when there's only a title (no description) - // and the banner has action buttons - const hasActions = isRenderable(endContent) || isDismissable; + // and the banner has action buttons. The collapse toggle counts: it is the + // same 28px control as a dismiss button and shares the row with it, so a + // collapsible title-only banner is exactly the case this centers — leaving + // it out left the icon and title hanging above the toggle they sit beside. + const hasActions = isRenderable(endContent) || isDismissable || hasToggle; const isSingleLine = !isRenderable(description) && hasActions; // Non-collapsible children are always shown; collapsible ones follow the