Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .changeset/blankslate-compact-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': major
---

Blankslate: Make compact sizing and default-sized primary actions standard. Remove the `small` size; use `medium` instead.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion e2e/components/Blankslate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const stories: Array<{title: string; id: string; viewports?: Array<keyof typeof
]

const scenarios = matrix({
size: ['small', 'medium', 'large'],
size: ['medium', 'large'],
spacious: [true, false],
border: [true, false],
})
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/Blankslate/Blankslate.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
},
{
"name": "size",
"type": "'small' | 'medium' | 'large'",
"description": "The size of the componeont",
"type": "'medium' | 'large'",
"description": "The size of the component",
"defaultValue": "'medium'"
}
],
Expand Down
12 changes: 0 additions & 12 deletions packages/react/src/Blankslate/Blankslate.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,6 @@ export const Spacious = () => (
</Blankslate>
)

export const SizeSmall = () => (
<Blankslate border size="small">
<Blankslate.Visual>
<BookIcon size="medium" />
</Blankslate.Visual>
<Blankslate.Heading>Blankslate heading</Blankslate.Heading>
<Blankslate.Description>Use it to provide information when no dynamic content exists.</Blankslate.Description>
<Blankslate.PrimaryAction href="#">Primary action</Blankslate.PrimaryAction>
<Blankslate.SecondaryAction href="#">Secondary action</Blankslate.SecondaryAction>
</Blankslate>
)

export const SizeLarge = () => (
<Blankslate size="large">
<Blankslate.Visual>
Expand Down
1 change: 0 additions & 1 deletion packages/react/src/Blankslate/Blankslate.figma.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const props = {
item: figma.children('leadingVisual'),
}),
size: figma.enum('size', {
small: 'small',
medium: 'medium',
large: 'large',
}),
Expand Down
104 changes: 6 additions & 98 deletions packages/react/src/Blankslate/Blankslate.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,24 @@
}

&:where([data-size='medium']) {
--blankslate-heading-text: var(--text-title-shorthand-medium);
--blankslate-heading-margin-block: 0 var(--base-size-4);
--blankslate-description-text: var(--text-body-shorthand-large);
--blankslate-padding: var(--base-size-32);
--blankslate-action-margin-block-end: var(--base-size-16);
}

&:where([data-size='medium'][data-spacious]) {
--blankslate-padding: var(--base-size-80) var(--base-size-40);
}

&:where([data-size='small']) {
--blankslate-heading-text: var(--text-title-shorthand-small);
--blankslate-heading-margin-block: 0 var(--base-size-4);
--blankslate-description-text: var(--text-body-shorthand-medium);
--blankslate-description-margin-block: 0;
--blankslate-padding: var(--base-size-16);
--blankslate-action-margin-block-end: var(--base-size-12);
--blankslate-visual-size: var(--base-size-24);
}

&:where([data-size='small'][data-spacious]) {
&:where([data-size='medium'][data-spacious]) {
--blankslate-padding: var(--base-size-44) var(--base-size-28);
}

&:where([data-size='large']) {
--blankslate-heading-text: var(--text-title-shorthand-large);
--blankslate-heading-margin-block: var(--base-size-8) var(--base-size-4);
--blankslate-heading-text: var(--text-title-shorthand-medium);
--blankslate-heading-margin-block: 0 var(--base-size-4);
--blankslate-description-text: var(--text-body-shorthand-large);
--blankslate-description-margin-block: 0 var(--base-size-8);
--blankslate-description-margin-block: 0;
--blankslate-padding: var(--base-size-32);
--blankslate-action-margin-block-end: var(--base-size-16);
}
Expand Down Expand Up @@ -102,87 +91,6 @@
}
}

/* At the time these styles were written, 34rem was our "small" breakpoint width */
@container blankslate (max-width: 34rem) {
.Blankslate {
--blankslate-padding: var(--base-size-20);

&:where([data-size='small']) {
--blankslate-padding: var(--base-size-16);
}

&:where([data-spacious]) {
--blankslate-padding: var(--base-size-44) var(--base-size-28);
}

--blankslate-heading-text: var(--text-title-shorthand-small);
--blankslate-description-text: var(--text-body-shorthand-medium);
}

.Visual {
max-width: var(--base-size-24);
margin-bottom: var(--base-size-8);
color: var(--fgColor-muted);
}

.Action {
margin-top: var(--base-size-8);

&:first-of-type {
margin-top: var(--base-size-16);
}

&:last-of-type {
margin-bottom: calc(var(--base-size-8) / 2);
}
}
}

.Blankslate:where([data-compact-default][data-size='medium']) {
--blankslate-heading-text: var(--text-title-shorthand-small);
--blankslate-heading-margin-block: 0 var(--base-size-4);
--blankslate-description-text: var(--text-body-shorthand-medium);
--blankslate-description-margin-block: 0;
--blankslate-padding: var(--base-size-16);
--blankslate-action-margin-block-end: var(--base-size-12);
--blankslate-visual-size: var(--base-size-24);

&:where([data-spacious]) {
--blankslate-padding: var(--base-size-44) var(--base-size-28);
}
}

.Blankslate:where([data-compact-default][data-size='large']) {
--blankslate-heading-text: var(--text-title-shorthand-medium);
--blankslate-heading-margin-block: 0 var(--base-size-4);
--blankslate-description-text: var(--text-body-shorthand-large);
--blankslate-description-margin-block: 0;
--blankslate-padding: var(--base-size-32);
--blankslate-action-margin-block-end: var(--base-size-16);

&:where([data-spacious]) {
--blankslate-padding: var(--base-size-80) var(--base-size-40);
}
}

.Blankslate:where([data-compact-default]) {
& .Action {
margin-block-start: var(--base-size-16);
}

&[data-size='medium'] .Action:last-of-type {
margin-block-end: var(--base-size-12);
}

&[data-size='large'] .Action:last-of-type {
margin-block-end: var(--base-size-16);
}

& .Visual {
margin-block-end: var(--base-size-8);
}
}

.Blankslate:where([data-compact-default][data-size='large']) .Visual {
.Blankslate:where([data-size='large']) .Visual {
max-width: none;
}
2 changes: 1 addition & 1 deletion packages/react/src/Blankslate/Blankslate.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Playground.args = {
Playground.argTypes = {
size: {
controls: {
options: ['small', 'medium', 'large'],
options: ['medium', 'large'],
},
},
}
143 changes: 49 additions & 94 deletions packages/react/src/Blankslate/Blankslate.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,9 @@ import {describe, expect, it, vi} from 'vitest'
import {render} from '@testing-library/react'
import {page, userEvent} from 'vitest/browser'
import {Blankslate} from '../Blankslate'
import {FeatureFlags} from '../FeatureFlags'
import {implementsClassName} from '../utils/testing'
import classes from './Blankslate.module.css'

function getCSSStyleRules(): Array<CSSStyleRule> {
return Array.from(document.styleSheets).flatMap(sheet => {
return Array.from(sheet.cssRules).flatMap(rule => {
if (rule instanceof CSSStyleRule) {
return [rule]
}

if ('cssRules' in rule) {
return Array.from(rule.cssRules as CSSRuleList).filter((nestedRule): nestedRule is CSSStyleRule => {
return nestedRule instanceof CSSStyleRule
})
}

return []
})
})
}

function getSizePadding(size: 'small' | 'medium' | 'large', compactDefault = false) {
const rule = getCSSStyleRules().find(cssRule => {
return (
cssRule.selectorText.includes(`.${classes.Blankslate}`) &&
cssRule.selectorText.includes(`data-size="${size}"`) &&
cssRule.selectorText.includes('data-compact-default') === compactDefault &&
!cssRule.selectorText.includes('data-spacious')
)
})

return rule?.style.getPropertyValue('--blankslate-padding').trim()
}

describe('Blankslate', () => {
implementsClassName(Blankslate, classes.Blankslate)

Expand All @@ -61,43 +29,56 @@ describe('Blankslate', () => {
.toHaveAttribute('data-spacious', '')
})

it('sets reduced padding for small size variant', () => {
render(<Blankslate>Test content</Blankslate>)

expect(getSizePadding('small')).toMatch(/^var\(--base-size-16/)
})

it('keeps the existing size scale when the compact default feature is disabled', async () => {
render(<Blankslate size="small">Test content</Blankslate>)
const blankslate = page.getByText('Test content', {exact: true})

await expect.element(blankslate).toHaveAttribute('data-size', 'small')
await expect.element(blankslate).not.toHaveAttribute('data-compact-default')
})

it('uses the compact default size scale when the feature is enabled', async () => {
render(
<FeatureFlags flags={{primer_react_blankslate_compact_default: true}}>
<Blankslate>Test content</Blankslate>
</FeatureFlags>,
)
const blankslate = page.getByText('Test content', {exact: true})

await expect.element(blankslate).toHaveAttribute('data-size', 'medium')
await expect.element(blankslate).toHaveAttribute('data-compact-default', '')
expect(getSizePadding('medium', true)).toMatch(/^var\(--base-size-16/)
expect(getSizePadding('large', true)).toMatch(/^var\(--base-size-32/)
})

it('maps the legacy small size to the compact default size when the feature is enabled', async () => {
render(
<FeatureFlags flags={{primer_react_blankslate_compact_default: true}}>
<Blankslate size="small">Test content</Blankslate>
</FeatureFlags>,
)
const blankslate = page.getByText('Test content', {exact: true})
describe.each([480, 800])('in a %ipx container', width => {
it.each([undefined, 'medium', 'large'] as const)('uses the graduated size scale for size=%s', async size => {
const {container, rerender} = render(
<div style={{width}}>
<Blankslate size={size}>
<Blankslate.Visual>
<svg width="32" height="32" aria-hidden="true" />
</Blankslate.Visual>
<Blankslate.Heading>Test heading</Blankslate.Heading>
<Blankslate.Description>Test description</Blankslate.Description>
<Blankslate.PrimaryAction>Primary action</Blankslate.PrimaryAction>
<Blankslate.SecondaryAction href="#">Secondary action</Blankslate.SecondaryAction>
</Blankslate>
</div>,
)
const heading = page.getByRole('heading', {name: 'Test heading', exact: true})
const blankslate = heading.element().parentElement
const primaryAction = page.getByRole('button', {name: 'Primary action', exact: true})
const secondaryAction = page.getByRole('link', {name: 'Secondary action', exact: true})
const large = size === 'large'

await expect.element(blankslate).toHaveAttribute('data-size', large ? 'large' : 'medium')
await expect.element(blankslate).toHaveStyle({padding: large ? '32px' : '16px'})
await expect.element(heading).toHaveStyle({fontSize: large ? '20px' : '16px', marginTop: '0px'})
await expect.element(page.getByText('Test description', {exact: true})).toHaveStyle({
fontSize: large ? '16px' : '14px',
marginBottom: '0px',
})
await expect.element(container.querySelector<HTMLElement>('[data-component="Blankslate.Visual"]')).toHaveStyle({
maxWidth: large ? 'none' : '24px',
})
await expect.element(primaryAction).toHaveAttribute('data-size', 'medium')
await expect.element(primaryAction.element().parentElement).toHaveStyle({marginTop: '16px'})
await expect.element(secondaryAction.element().parentElement).toHaveStyle({
marginTop: '16px',
marginBottom: large ? '16px' : '12px',
})

rerender(
<div style={{width}}>
<Blankslate size={size} spacious>
<Blankslate.Heading>Test heading</Blankslate.Heading>
</Blankslate>
</div>,
)

await expect.element(blankslate).toHaveAttribute('data-size', 'medium')
await expect.element(heading.element().parentElement).toHaveStyle({
padding: large ? '80px 40px' : '44px 28px',
})
})
})

it('renders data-component attributes', async () => {
Expand Down Expand Up @@ -201,32 +182,6 @@ describe('Blankslate', () => {
await expect.element(page.getByRole('button', {name: 'Primary action'})).toBeInTheDocument()
})

it('uses the default button size when the compact default feature is enabled', async () => {
render(
<FeatureFlags flags={{primer_react_blankslate_compact_default: true}}>
<Blankslate size="small">
<Blankslate.PrimaryAction>Primary action</Blankslate.PrimaryAction>
</Blankslate>
</FeatureFlags>,
)

await expect
.element(page.getByRole('button', {name: 'Primary action', exact: true}))
.toHaveAttribute('data-size', 'medium')
})

it('keeps the small button size when the compact default feature is disabled', async () => {
render(
<Blankslate size="small">
<Blankslate.PrimaryAction>Primary action</Blankslate.PrimaryAction>
</Blankslate>,
)

await expect
.element(page.getByRole('button', {name: 'Primary action', exact: true}))
.toHaveAttribute('data-size', 'small')
})

it('should handle click events on the button', async () => {
const onClick = vi.fn()
render(
Expand Down
Loading
Loading