Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
5 changes: 5 additions & 0 deletions .changeset/odd-rings-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

Update Banner to use CSS Modules behind feature flag
57 changes: 57 additions & 0 deletions e2e/components/Banner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,24 @@ test.describe('Banner', () => {
id: story.id,
globals: {
colorScheme: theme,
featureFlags: {
primer_react_css_modules_team: true,
},
},
})

// Default state
expect(await page.screenshot()).toMatchSnapshot(`Banner.${story.title}.${theme}.png`)
})

test('default (styled-components) @vrt', async ({page}) => {
await visit(page, {
id: story.id,
globals: {
colorScheme: theme,
featureFlags: {
primer_react_css_modules_team: false,
},
},
})

Expand All @@ -84,6 +102,22 @@ test.describe('Banner', () => {
id: story.id,
globals: {
colorScheme: theme,
featureFlags: {
primer_react_css_modules_team: true,
},
},
})
await expect(page).toHaveNoViolations()
})

test('axe (styled-components) @aat', async ({page}) => {
await visit(page, {
id: story.id,
globals: {
colorScheme: theme,
featureFlags: {
primer_react_css_modules_team: false,
},
},
})
await expect(page).toHaveNoViolations()
Expand All @@ -96,6 +130,29 @@ test.describe('Banner', () => {
test(`${name} @vrt`, async ({page}) => {
await visit(page, {
id: story.id,
globals: {
featureFlags: {
primer_react_css_modules_team: true,
},
},
})
const width = viewports[name]

await page.setViewportSize({
width,
height: 667,
})
expect(await page.screenshot()).toMatchSnapshot(`Banner.${story.title}.${name}.png`)
})

test(`${name} (styled-components) @vrt`, async ({page}) => {
await visit(page, {
id: story.id,
globals: {
featureFlags: {
primer_react_css_modules_team: false,
},
},
})
const width = viewports[name]

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,4 @@
"lint-staged": {
"**/*.{js,ts,tsx,md,mdx}": "npm run lint"
}
}
}
5 changes: 5 additions & 0 deletions packages/react/src/Banner/Banner.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
"type": "string",
"description": "Provide an optional label to override the default name for the Banner landmark region"
},
{
"name": "className",
"type": "string",
"description": "Provide an optional className to add to the outermost element rendered by the Banner"
},
{
"name": "description",
"type": "React.ReactNode",
Expand Down
194 changes: 194 additions & 0 deletions packages/react/src/Banner/Banner.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
.Banner {
display: grid;
padding: var(--base-size-8, var(--base-size-8));
background-color: var(--banner-bgColor);
border: var(--borderWidth-thin, 1px) solid var(--banner-borderColor);
border-radius: var(--borderRadius-medium);
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: start;

@supports (container-type: inline-size) {
container: banner / inline-size;
}

&[data-variant='critical'] {
--banner-bgColor: var(--bgColor-danger-muted);
--banner-borderColor: var(--borderColor-danger-muted);
--banner-icon-fgColor: var(--fgColor-danger);
}

&[data-variant='info'] {
--banner-bgColor: var(--bgColor-accent-muted);
--banner-borderColor: var(--borderColor-accent-muted);
--banner-icon-fgColor: var(--fgColor-accent);
}

&[data-variant='success'] {
--banner-bgColor: var(--bgColor-success-muted);
--banner-borderColor: var(--borderColor-success-muted);
--banner-icon-fgColor: var(--fgColor-success);
}

&[data-variant='upsell'] {
--banner-bgColor: var(--bgColor-upsell-muted);
--banner-borderColor: var(--borderColor-upsell-muted);
--banner-icon-fgColor: var(--fgColor-upsell);
}

&[data-variant='warning'] {
--banner-bgColor: var(--bgColor-attention-muted);
--banner-borderColor: var(--borderColor-attention-muted);
--banner-icon-fgColor: var(--fgColor-attention);
}
}

/* BannerContainer -------------------------------------------------------- */

.BannerContainer {
font-size: var(--text-body-size-medium, 0.875rem);
Comment thread
joshblack marked this conversation as resolved.
Outdated
align-items: start;
line-height: var(--text-body-lineHeight-medium, calc(20 / 14));
row-gap: var(--base-size-4, 0.25rem);
column-gap: var(--base-size-4, 0.25rem);
}

.Banner :where(.BannerContainer) {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}

.Banner[data-dismissible] .BannerContainer {
display: grid;
grid-template-columns: auto;
grid-template-rows: auto;
}

/* BannerContent ---------------------------------------------------------- */

.BannerContent {
display: grid;
row-gap: var(--base-size-4, 0.25rem);
grid-column-start: 1;
margin-block: var(--base-size-8, var(--base-size-8));
}

.Banner[data-title-hidden] .BannerContent {
margin-block: var(--base-size-6, var(--base-size-6));
}

@media screen and (min-width: 544px) {
.BannerContent {
flex: 1 1 0%;
}
}

.BannerTitle {
margin: 0;
font-size: inherit;
font-weight: var(--base-text-weight-semibold, 600);
}

/* BannerIcon ------------------------------------------------------------- */

.BannerIcon {
display: grid;
place-items: center;
padding: var(--base-size-8, var(--base-size-8));
Comment thread
joshblack marked this conversation as resolved.
Outdated
}

.BannerIcon svg {
/* 20px is the line box height of the trailing action buttons */
height: var(--base-size-20, 1.25rem);
color: var(--banner-icon-fgColor);
fill: var(--banner-icon-fgColor);
}

.Banner[data-title-hidden] .BannerIcon svg {
height: var(--base-size-16, 1rem);
}

/* BannerDismiss ---------------------------------------------------------- */

.BannerDismiss {
display: grid;
place-items: center;
padding: var(--base-size-8, var(--base-size-8));
margin-inline-start: var(--base-size-4, var(--base-size-4));
Comment thread
joshblack marked this conversation as resolved.
Outdated
}

.BannerDismiss svg {
color: var(--banner-icon-fgColor);
}

/* BannerActions ---------------------------------------------------------- */

.BannerActionsContainer {
display: flex;
column-gap: var(--base-size-12, 0.5rem);
align-items: center;
}

.BannerActions :where([data-primary-action='trailing']) {
display: none;
}

@media screen and (min-width: 544px) {
Comment thread
joshblack marked this conversation as resolved.
Outdated
.BannerActions :where([data-primary-action='trailing']) {
display: flex;
}

.BannerActions :where([data-primary-action='leading']) {
display: none;
}
}

.Banner[data-dismissible] .BannerActions {
margin-block-end: var(--base-size-6, var(--base-size-6));
Comment thread
joshblack marked this conversation as resolved.
Outdated
}

.Banner[data-dismissible] .BannerActionsContainer[data-primary-action='trailing'] {
display: none;
}

.Banner[data-dismissible] .BannerActionsContainer[data-primary-action='leading'] {
display: flex;
}

/* Layout ------------------------------------------------------------------- */

/* stylelint-disable-next-line plugin/no-unsupported-browser-features */
@container banner (max-width: 500px) {
.BannerContainer {
display: grid;
grid-template-rows: auto auto;
}

.BannerActions {
margin-block-end: var(--base-size-6);
}

.BannerActions [data-primary-action='trailing'] {
display: none;
}

.BannerActions [data-primary-action='leading'] {
display: flex;
}
}

/* stylelint-disable-next-line plugin/no-unsupported-browser-features */
@container banner (min-width: 500px) {
.BannerContainer {
display: grid;
grid-template-columns: auto auto;
}

.BannerActions [data-primary-action='trailing'] {
display: flex;
}

.BannerActions [data-primary-action='leading'] {
display: none;
}
}
5 changes: 5 additions & 0 deletions packages/react/src/Banner/Banner.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ describe('Banner', () => {
expect(screen.getByRole('heading', {name: 'test'})).toBeInTheDocument()
})

it('should support a custom `className` on the outermost element', () => {
const {container} = render(<Banner title="test" className="test" />)
expect(container.firstChild).toHaveClass('test')
})

it('should label the landmark element with the corresponding variant label text', () => {
render(<Banner title="test" />)
expect(screen.getByRole('region')).toEqual(screen.getByLabelText('Information'))
Expand Down
Loading