diff --git a/.changeset/clever-birds-press.md b/.changeset/clever-birds-press.md new file mode 100644 index 00000000000..e4d6d63354c --- /dev/null +++ b/.changeset/clever-birds-press.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +Add `variant` prop to Heading for small, medium and large styles diff --git a/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Default-linux.png b/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Default-linux.png new file mode 100644 index 00000000000..395d4eeef2c Binary files /dev/null and b/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Default-linux.png differ diff --git a/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Large-linux.png b/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Large-linux.png new file mode 100644 index 00000000000..d4e845c7341 Binary files /dev/null and b/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Large-linux.png differ diff --git a/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Medium-linux.png b/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Medium-linux.png new file mode 100644 index 00000000000..bf82b6f4a5a Binary files /dev/null and b/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Medium-linux.png differ diff --git a/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Small-linux.png b/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Small-linux.png new file mode 100644 index 00000000000..377508c4519 Binary files /dev/null and b/.playwright/snapshots/components/Heading.test.ts-snapshots/Heading-Small-linux.png differ diff --git a/e2e/components/Heading.test.ts b/e2e/components/Heading.test.ts index 1c573a8b6e7..9d13fb2110a 100644 --- a/e2e/components/Heading.test.ts +++ b/e2e/components/Heading.test.ts @@ -1,33 +1,74 @@ import {test, expect} from '@playwright/test' import {visit} from '../test-helpers/storybook' -import {themes} from '../test-helpers/themes' test.describe('Heading', () => { test.describe('Default', () => { - for (const theme of themes) { - test.describe(theme, () => { - test('default @vrt', async ({page}) => { - await visit(page, { - id: 'components-heading--default', - globals: { - colorScheme: theme, - }, - }) - - // Default state - expect(await page.screenshot()).toMatchSnapshot(`Heading.Default.${theme}.png`) - }) - - test('axe @aat', async ({page}) => { - await visit(page, { - id: 'components-heading--default', - globals: { - colorScheme: theme, - }, - }) - await expect(page).toHaveNoViolations() - }) - }) - } + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-heading--default', + }) + + // Default state + expect(await page.screenshot()).toMatchSnapshot(`Heading.Default.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-heading--default', + }) + await expect(page).toHaveNoViolations() + }) + }) + + test.describe('Small', () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-heading-features--small', + }) + + expect(await page.screenshot()).toMatchSnapshot(`Heading.Small.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-heading-features--small', + }) + await expect(page).toHaveNoViolations() + }) + }) + + test.describe('Medium', () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-heading-features--medium', + }) + + expect(await page.screenshot()).toMatchSnapshot(`Heading.Medium.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-heading-features--medium', + }) + await expect(page).toHaveNoViolations() + }) + }) + + test.describe('Large', () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-heading-features--large', + }) + + // Default state + expect(await page.screenshot()).toMatchSnapshot(`Heading.Large.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-heading-features--large', + }) + await expect(page).toHaveNoViolations() + }) }) }) diff --git a/packages/react/src/Heading/Heading.docs.json b/packages/react/src/Heading/Heading.docs.json index 5a63b0dd836..05a9a0214dd 100644 --- a/packages/react/src/Heading/Heading.docs.json +++ b/packages/react/src/Heading/Heading.docs.json @@ -14,6 +14,10 @@ "name": "as", "type": "React.ElementType", "defaultValue": "\"h2\"" + }, + { + "name": "variant", + "type": "'large' | 'medium' | 'small'" } ] } diff --git a/packages/react/src/Heading/Heading.features.stories.tsx b/packages/react/src/Heading/Heading.features.stories.tsx new file mode 100644 index 00000000000..59dd2c6cb80 --- /dev/null +++ b/packages/react/src/Heading/Heading.features.stories.tsx @@ -0,0 +1,24 @@ +import React from 'react' +import type {StoryFn} from '@storybook/react' +import Heading from './Heading' + +export default { + title: 'Components/Heading/Features', +} + +export const TestSx: StoryFn = () => ( + + Heading with sx override + +) + +export const Small: StoryFn = () => Small heading + +export const Medium: StoryFn = () => Medium heading + +export const Large: StoryFn = () => Large heading diff --git a/packages/react/src/Heading/Heading.stories.tsx b/packages/react/src/Heading/Heading.stories.tsx index 6e1cb334638..ecaa9062e98 100644 --- a/packages/react/src/Heading/Heading.stories.tsx +++ b/packages/react/src/Heading/Heading.stories.tsx @@ -6,6 +6,7 @@ export default { title: 'Components/Heading', component: Heading, } as Meta + export const Default: StoryFn = () => Default H2 Heading export const Playground: StoryFn = args => Heading @@ -17,8 +18,14 @@ Playground.args = { Playground.argTypes = { as: { control: { - type: 'select', - options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + type: 'radio', + }, + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + }, + variant: { + control: { + type: 'radio', }, + options: ['large', 'medium', 'small'], }, } diff --git a/packages/react/src/Heading/Heading.tsx b/packages/react/src/Heading/Heading.tsx index 048057004bd..78c14c77f58 100644 --- a/packages/react/src/Heading/Heading.tsx +++ b/packages/react/src/Heading/Heading.tsx @@ -9,15 +9,28 @@ import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../uti type StyledHeadingProps = { as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' + variant?: 'large' | 'medium' | 'small' } & SxProp const StyledHeading = styled.h2` font-weight: ${get('fontWeights.bold')}; font-size: ${get('fontSizes.5')}; margin: 0; + + &:where([data-variant='large']) { + font: var(--text-title-shorthand-large, 600 32px / 1.5 ${get('fonts.normal')}); + } + + &:where([data-variant='medium']) { + font: var(--text-title-shorthand-medium, 600 20px / 1.6 ${get('fonts.normal')}); + } + + &:where([data-variant='small']) { + font: var(--text-title-shorthand-small, 600 16px / 1.5 ${get('fonts.normal')}); + } ${sx}; ` -const Heading = forwardRef(({as: Component = 'h2', ...props}, forwardedRef) => { +const Heading = forwardRef(({as: Component = 'h2', variant, ...props}, forwardedRef) => { const innerRef = React.useRef(null) useRefObjectAsForwardedRef(forwardedRef, innerRef) @@ -43,6 +56,7 @@ const Heading = forwardRef(({as: Component = 'h2', ...props}, forwardedRef) => { {...props} // @ts-ignore shh ref={innerRef} + data-variant={variant} /> ) }) as PolymorphicForwardRefComponent<'h2', StyledHeadingProps> diff --git a/packages/react/src/NavList/__snapshots__/NavList.test.tsx.snap b/packages/react/src/NavList/__snapshots__/NavList.test.tsx.snap index dfae7671884..c46f758c1af 100644 --- a/packages/react/src/NavList/__snapshots__/NavList.test.tsx.snap +++ b/packages/react/src/NavList/__snapshots__/NavList.test.tsx.snap @@ -480,6 +480,18 @@ exports[`NavList renders with groups 1`] = ` color: var(--fgColor-muted,var(--color-fg-muted,#656d76)); } +.c3:where([data-variant='large']) { + font: var(--text-title-shorthand-large,600 32px / 1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"); +} + +.c3:where([data-variant='medium']) { + font: var(--text-title-shorthand-medium,600 20px / 1.6 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"); +} + +.c3:where([data-variant='small']) { + font: var(--text-title-shorthand-small,600 16px / 1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"); +} + .c0 { margin: 0; padding-inline-start: 0;