From 08589ce6cdd6a11814343e004c85e88546e8e899 Mon Sep 17 00:00:00 2001 From: marcoskolodny Date: Wed, 13 Nov 2024 14:10:28 +0100 Subject: [PATCH] update all cards, add unit tests and add titleAs/pretitleAs controls in stories --- src/__stories__/data-card-story.tsx | 17 ++ src/__stories__/display-data-card-story.tsx | 17 ++ src/__stories__/display-media-card-story.tsx | 17 ++ src/__stories__/media-card-story.tsx | 17 ++ src/__stories__/naked-card-story.tsx | 17 ++ src/__stories__/poster-card-story.tsx | 17 ++ src/__tests__/data-card-test.tsx | 153 +++++++----- src/__tests__/display-data-card-test.tsx | 153 +++++++----- src/__tests__/display-media-card-test.tsx | 159 ++++++++----- src/__tests__/media-card-test.tsx | 168 ++++++++------ src/__tests__/naked-card-test.tsx | 168 ++++++++------ src/__tests__/poster-card-test.tsx | 168 ++++++++------ src/card.tsx | 231 ++++++++++++++----- 13 files changed, 848 insertions(+), 454 deletions(-) diff --git a/src/__stories__/data-card-story.tsx b/src/__stories__/data-card-story.tsx index d0602c45e..aeced7f28 100644 --- a/src/__stories__/data-card-story.tsx +++ b/src/__stories__/data-card-story.tsx @@ -17,6 +17,7 @@ import { import {Placeholder} from '../placeholder'; import avatarImg from './images/avatar.jpg'; +import type {HeadingType} from '../utils/types'; import type {AspectRatio} from '../card'; import type {TagType} from '..'; @@ -29,7 +30,9 @@ type DataCardArgs = { headlineType: TagType; headline: string; pretitle: string; + pretitleAs: HeadingType; title: string; + titleAs: HeadingType; subtitle: string; description: string; ariaLabel: string; @@ -47,7 +50,9 @@ export const Default: StoryComponent = ({ headline, headlineType, pretitle, + pretitleAs, title, + titleAs, subtitle, description, ariaLabel, @@ -99,7 +104,9 @@ export const Default: StoryComponent = ({ asset={assetElement} headline={headline && {headline}} pretitle={pretitle} + pretitleAs={pretitleAs} title={title} + titleAs={titleAs} subtitle={subtitle} description={description} extra={extra ? : undefined} @@ -142,7 +149,9 @@ Default.args = { headlineType: 'promo', headline: 'Priority', pretitle: 'Pretitle', + pretitleAs: 'span', title: 'Title', + titleAs: 'h3', subtitle: 'Subtitle', description: 'This is a description for the card', extra: false, @@ -177,6 +186,14 @@ Default.argTypes = { }, }, }, + pretitleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, + titleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, }; export const Group: StoryComponent = () => { diff --git a/src/__stories__/display-data-card-story.tsx b/src/__stories__/display-data-card-story.tsx index 8cd8a30ab..bb44a1b51 100644 --- a/src/__stories__/display-data-card-story.tsx +++ b/src/__stories__/display-data-card-story.tsx @@ -20,6 +20,7 @@ import { import {Placeholder} from '../placeholder'; import avatarImg from './images/avatar.jpg'; +import type {HeadingType} from '../utils/types'; import type {AspectRatio} from '../card'; import type {TagType} from '..'; @@ -32,7 +33,9 @@ type DisplayDataCardArgs = { headlineType: TagType; headline: string; pretitle: string; + pretitleAs: HeadingType; title: string; + titleAs: HeadingType; description: string; extra: boolean; closable: boolean; @@ -57,7 +60,9 @@ export const Default: StoryComponent = ({ headline, headlineType, pretitle, + pretitleAs, title, + titleAs, description, extra, actions = 'button', @@ -141,7 +146,9 @@ export const Default: StoryComponent = ({ asset={assetElement} headline={headline ? {headline} : undefined} pretitle={pretitle} + pretitleAs={pretitleAs} title={title} + titleAs={titleAs} description={description} aspectRatio={aspectRatioValue as AspectRatio} extra={extra ? : undefined} @@ -158,7 +165,9 @@ Default.args = { headlineType: 'promo', headline: 'Priority', pretitle: 'Pretitle', + pretitleAs: 'span', title: 'Title', + titleAs: 'h3', description: 'This is a description for the card', extra: false, actions: 'button', @@ -201,6 +210,14 @@ Default.argTypes = { }, }, }, + pretitleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, + titleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, }; export const Group: StoryComponent = () => { diff --git a/src/__stories__/display-media-card-story.tsx b/src/__stories__/display-media-card-story.tsx index 42e6ae96f..554717bf7 100644 --- a/src/__stories__/display-media-card-story.tsx +++ b/src/__stories__/display-media-card-story.tsx @@ -23,6 +23,7 @@ import avatarImg from './images/avatar.jpg'; import beachVideo from './videos/beach.mp4'; import beachImg from './images/beach.jpg'; +import type {HeadingType} from '../utils/types'; import type {TagType} from '..'; export default { @@ -39,7 +40,9 @@ type DisplayMediaCardArgs = { background: 'image' | 'video'; headline: string; pretitle: string; + pretitleAs: HeadingType; title: string; + titleAs: HeadingType; description: string; extra: boolean; closable: boolean; @@ -65,7 +68,9 @@ export const Default: StoryComponent = ({ headlineType, background, pretitle, + pretitleAs, title, + titleAs, description, extra, actions = 'button', @@ -153,7 +158,9 @@ export const Default: StoryComponent = ({ asset={assetElement} headline={headline ? {headline} : undefined} pretitle={pretitle} + pretitleAs={pretitleAs} title={title} + titleAs={titleAs} description={description} {...interactiveActions} aria-label="Display media card label" @@ -174,7 +181,9 @@ Default.args = { background: 'image', headline: 'Priority', pretitle: 'Pretitle', + pretitleAs: 'span', title: 'Title', + titleAs: 'h3', description: 'This is a description for the card', extra: false, actions: 'button', @@ -215,6 +224,14 @@ Default.argTypes = { options: ['1:1', '16:9', '7:10', '9:10', 'auto'], control: {type: 'select'}, }, + pretitleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, + titleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, }; Default.parameters = {fullScreen: true}; diff --git a/src/__stories__/media-card-story.tsx b/src/__stories__/media-card-story.tsx index 6fa815fe4..745abc95b 100644 --- a/src/__stories__/media-card-story.tsx +++ b/src/__stories__/media-card-story.tsx @@ -21,6 +21,7 @@ import tennisImg from './images/tennis.jpg'; import beachVideo from './videos/beach.mp4'; import avatarImg from './images/avatar.jpg'; +import type {HeadingType} from '../utils/types'; import type {TagType} from '..'; export default { @@ -36,7 +37,9 @@ type Args = { headlineType: TagType; headline: string; pretitle: string; + pretitleAs: HeadingType; title: string; + titleAs: HeadingType; subtitle: string; description: string; extra: boolean; @@ -50,7 +53,9 @@ export const Default: StoryComponent = ({ headline, headlineType, pretitle, + pretitleAs, title, + titleAs, subtitle, description, actions = 'button', @@ -99,7 +104,9 @@ export const Default: StoryComponent = ({ dataAttributes={{testid: 'media-card'}} headline={headline && {headline}} pretitle={pretitle} + pretitleAs={pretitleAs} title={title} + titleAs={titleAs} subtitle={subtitle} description={description} asset={assetElement} @@ -153,7 +160,9 @@ Default.args = { headlineType: 'promo', headline: 'Priority', pretitle: 'Pretitle', + pretitleAs: 'span', title: 'Title', + titleAs: 'h3', subtitle: 'Subtitle', description: 'This is a description for the card', extra: false, @@ -179,6 +188,14 @@ Default.argTypes = { options: ['button', 'link', 'button and link', 'onPress', 'href', 'to', 'none'], control: {type: 'select'}, }, + pretitleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, + titleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, }; export const Group: StoryComponent = () => { diff --git a/src/__stories__/naked-card-story.tsx b/src/__stories__/naked-card-story.tsx index cac8979fd..e6b6d8c4d 100644 --- a/src/__stories__/naked-card-story.tsx +++ b/src/__stories__/naked-card-story.tsx @@ -23,6 +23,7 @@ import beachVideo from './videos/beach.mp4'; import {SmallNakedCard} from '../card'; import avatarImg from './images/avatar.jpg'; +import type {HeadingType} from '../utils/types'; import type {TagType} from '..'; export default { @@ -41,7 +42,9 @@ type Args = { headlineType: TagType; headline: string; pretitle: string; + pretitleAs: HeadingType; title: string; + titleAs: HeadingType; subtitle: string; description: string; extra: boolean; @@ -55,7 +58,9 @@ export const Default: StoryComponent = ({ headline, headlineType, pretitle, + pretitleAs, title, + titleAs, subtitle, description, actions = 'button', @@ -106,7 +111,9 @@ export const Default: StoryComponent = ({ dataAttributes={{testid: 'naked-card'}} headline={headline && {headline}} pretitle={pretitle} + pretitleAs={pretitleAs} title={title} + titleAs={titleAs} subtitle={subtitle} description={description} media={ @@ -160,7 +167,9 @@ Default.args = { headlineType: 'promo', headline: 'Priority', pretitle: 'Pretitle', + pretitleAs: 'span', title: 'Title', + titleAs: 'h3', subtitle: 'Subtitle', description: 'This is a description for the card', extra: false, @@ -186,6 +195,14 @@ Default.argTypes = { options: ['button', 'link', 'button and link', 'onPress', 'href', 'to', 'none'], control: {type: 'select'}, }, + pretitleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, + titleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, }; type SmallArgs = { diff --git a/src/__stories__/poster-card-story.tsx b/src/__stories__/poster-card-story.tsx index d134708ef..238a44c0f 100644 --- a/src/__stories__/poster-card-story.tsx +++ b/src/__stories__/poster-card-story.tsx @@ -20,6 +20,7 @@ import avatarImg from './images/avatar.jpg'; import beachVideo from './videos/beach.mp4'; import beachImg from './images/beach.jpg'; +import type {HeadingType} from '../utils/types'; import type {TagType} from '..'; export default { @@ -39,7 +40,9 @@ type PosterCardArgs = { headlineType: TagType; headline: string; pretitle: string; + pretitleAs: HeadingType; title: string; + titleAs: HeadingType; subtitle: string; description: string; extra: boolean; @@ -63,7 +66,9 @@ export const Default: StoryComponent = ({ headline, headlineType, pretitle, + pretitleAs, title, + titleAs, subtitle, description, extra, @@ -144,7 +149,9 @@ export const Default: StoryComponent = ({ asset={assetElement} headline={headline ? {headline} : undefined} pretitle={pretitle} + pretitleAs={pretitleAs} title={title} + titleAs={titleAs} subtitle={subtitle} description={description} extra={extra ? : undefined} @@ -169,7 +176,9 @@ Default.args = { variant: 'default', headline: 'Priority', pretitle: 'Pretitle', + pretitleAs: 'span', title: 'Title', + titleAs: 'h3', subtitle: 'Subtitle', description: 'This is a description for the card', extra: false, @@ -226,6 +235,14 @@ Default.argTypes = { options: ['onPress', 'href', 'to', 'none'], control: {type: 'select'}, }, + pretitleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, + titleAs: { + options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span'], + control: {type: 'select'}, + }, }; Default.parameters = {fullScreen: true}; diff --git a/src/__tests__/data-card-test.tsx b/src/__tests__/data-card-test.tsx index 2056c341b..4b4dc2cf1 100644 --- a/src/__tests__/data-card-test.tsx +++ b/src/__tests__/data-card-test.tsx @@ -8,71 +8,104 @@ import Stack from '../stack'; import {Text2} from '../text'; import userEvent from '@testing-library/user-event'; -test('DataCard "href" label', async () => { - render( - - Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); +const titleFirst = 'Title Headline Pretitle Description Extra line 1Extra line 2'; +const pretitleFirst = 'Pretitle Headline Title Description Extra line 1Extra line 2'; - await screen.findByRole('link', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DataCard "href" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('DataCard "to" label', async () => { - render( - - Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('link', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DataCard "to" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('DataCard "onPress" label', async () => { - render( - - {}} - headline={Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('button', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DataCard "onPress" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + {}} + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); + + await screen.findByRole('button', {name: expectedLabel}); + } +); test('DataCard onClose custom label', async () => { const closeSpy = jest.fn(); diff --git a/src/__tests__/display-data-card-test.tsx b/src/__tests__/display-data-card-test.tsx index 49e33ffc0..e0420f5df 100644 --- a/src/__tests__/display-data-card-test.tsx +++ b/src/__tests__/display-data-card-test.tsx @@ -8,71 +8,104 @@ import Stack from '../stack'; import {Text2} from '../text'; import userEvent from '@testing-library/user-event'; -test('DisplayDataCard "href" label', async () => { - render( - - Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); +const titleFirst = 'Title Headline Pretitle Description Extra line 1Extra line 2'; +const pretitleFirst = 'Pretitle Headline Title Description Extra line 1Extra line 2'; - await screen.findByRole('link', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DisplayDataCard "href" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('DisplayDataCard "to" label', async () => { - render( - - Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('link', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DisplayDataCard "to" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('DisplayDataCard "onPress" label', async () => { - render( - - {}} - headline={Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('button', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DisplayDataCard "onPress" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + {}} + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); + + await screen.findByRole('button', {name: expectedLabel}); + } +); test('DisplayDataCard onClose custom label', async () => { const closeSpy = jest.fn(); diff --git a/src/__tests__/display-media-card-test.tsx b/src/__tests__/display-media-card-test.tsx index da8d978d2..24db7b989 100644 --- a/src/__tests__/display-media-card-test.tsx +++ b/src/__tests__/display-media-card-test.tsx @@ -8,74 +8,107 @@ import Stack from '../stack'; import {Text2} from '../text'; import userEvent from '@testing-library/user-event'; -test('DisplayMediaCard "href" label', async () => { - render( - - Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); +const titleFirst = 'Title Headline Pretitle Description Extra line 1Extra line 2'; +const pretitleFirst = 'Pretitle Headline Title Description Extra line 1Extra line 2'; - await screen.findByRole('link', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DisplayMediaCard "href" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('DisplayMediaCard "to" label', async () => { - render( - - Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('link', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DisplayMediaCard "to" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('DisplayMediaCard "onPress" label', async () => { - render( - - {}} - backgroundImage="https://source.unsplash.com/900x900/" - headline={Headline} - pretitle="Pretitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('button', {name: 'Title Headline Pretitle Description Extra line 1Extra line 2'}); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'DisplayMediaCard "onPress" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + {}} + backgroundImage="https://source.unsplash.com/900x900/" + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); + + await screen.findByRole('button', {name: expectedLabel}); + } +); test('DisplayMediaCard onClose custom label', async () => { const closeSpy = jest.fn(); diff --git a/src/__tests__/media-card-test.tsx b/src/__tests__/media-card-test.tsx index 35776af9d..710d23fe1 100644 --- a/src/__tests__/media-card-test.tsx +++ b/src/__tests__/media-card-test.tsx @@ -9,83 +9,107 @@ import Image from '../image'; import {Text2} from '../text'; import userEvent from '@testing-library/user-event'; -test('MediaCard "href" label', async () => { - render( - - } - headline={Headline} - pretitle="Pretitle" - subtitle="Subtitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); +const titleFirst = 'Title Headline Pretitle Description Extra line 1Extra line 2'; +const pretitleFirst = 'Pretitle Headline Title Description Extra line 1Extra line 2'; - await screen.findByRole('link', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'MediaCard "href" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + } + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('MediaCard "to" label', async () => { - render( - - } - headline={Headline} - pretitle="Pretitle" - subtitle="Subtitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('link', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'MediaCard "to" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + } + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('MediaCard "onPress" label', async () => { - render( - - {}} - media={} - headline={Headline} - pretitle="Pretitle" - subtitle="Subtitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('button', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'MediaCard "onPress" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + {}} + media={} + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); + + await screen.findByRole('button', {name: expectedLabel}); + } +); test('MediaCard onClose custom label', async () => { const closeSpy = jest.fn(); diff --git a/src/__tests__/naked-card-test.tsx b/src/__tests__/naked-card-test.tsx index 4cdce0b34..d68672fa0 100644 --- a/src/__tests__/naked-card-test.tsx +++ b/src/__tests__/naked-card-test.tsx @@ -9,83 +9,107 @@ import Image from '../image'; import {Text2} from '../text'; import userEvent from '@testing-library/user-event'; -test('NakedCard "href" label', async () => { - render( - - } - headline={Headline} - pretitle="Pretitle" - subtitle="Subtitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); +const titleFirst = 'Title Headline Pretitle Description Extra line 1Extra line 2'; +const pretitleFirst = 'Pretitle Headline Title Description Extra line 1Extra line 2'; - await screen.findByRole('link', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'NakedCard "href" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + } + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('NakedCard "to" label', async () => { - render( - - } - headline={Headline} - pretitle="Pretitle" - subtitle="Subtitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('link', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'NakedCard "to" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + } + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('NakedCard "onPress" label', async () => { - render( - - {}} - media={} - headline={Headline} - pretitle="Pretitle" - subtitle="Subtitle" - title="Title" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('button', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'NakedCard "onPress" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + {}} + media={} + headline={Headline} + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); + + await screen.findByRole('button', {name: expectedLabel}); + } +); test('NakedCard onClose custom label', async () => { const closeSpy = jest.fn(); diff --git a/src/__tests__/poster-card-test.tsx b/src/__tests__/poster-card-test.tsx index bca1d5ef1..af50daef4 100644 --- a/src/__tests__/poster-card-test.tsx +++ b/src/__tests__/poster-card-test.tsx @@ -7,83 +7,107 @@ import Stack from '../stack'; import {Text2} from '../text'; import userEvent from '@testing-library/user-event'; -test('PosterCard "href" label', async () => { - render( - - - Extra line 1 - Extra line 2 - - } - /> - - ); +const titleFirst = 'Title Headline Pretitle Description Extra line 1Extra line 2'; +const pretitleFirst = 'Pretitle Headline Title Description Extra line 1Extra line 2'; - await screen.findByRole('link', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'PosterCard "href" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('PosterCard "to" label', async () => { - render( - - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('link', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'PosterCard "to" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + + Extra line 1 + Extra line 2 + + } + /> + + ); -test('PosterCard "onPress" label', async () => { - render( - - {}} - isInverse - headline="Headline" - pretitle="Pretitle" - title="Title" - subtitle="Subtitle" - description="Description" - extra={ - - Extra line 1 - Extra line 2 - - } - /> - - ); + await screen.findByRole('link', {name: expectedLabel}); + } +); - await screen.findByRole('button', { - name: 'Title Headline Pretitle Subtitle Description Extra line 1Extra line 2', - }); -}); +test.each` + pretitleAs | titleAs | expectedLabel + ${undefined} | ${undefined} | ${titleFirst} + ${'h1'} | ${'h2'} | ${pretitleFirst} + ${'h2'} | ${'h1'} | ${titleFirst} +`( + 'PosterCard "onPress" label with pretitleAs={$pretitleAs} and titleAs={$titleAs}', + async ({pretitleAs, titleAs, expectedLabel}) => { + render( + + {}} + isInverse + headline="Headline" + pretitle="Pretitle" + pretitleAs={pretitleAs} + title="Title" + titleAs={titleAs} + description="Description" + extra={ + + Extra line 1 + Extra line 2 + + } + /> + + ); + + await screen.findByRole('button', {name: expectedLabel}); + } +); test('PosterCard onClose custom label', async () => { const closeSpy = jest.fn(); diff --git a/src/card.tsx b/src/card.tsx index c0c50a78e..535797545 100644 --- a/src/card.tsx +++ b/src/card.tsx @@ -27,20 +27,21 @@ import {getPrefixedDataAttributes} from './utils/dom'; import {isRunningAcceptanceTest} from './utils/platform'; import {applyCssVars} from './utils/css'; import * as tokens from './text-tokens'; +import { + isBiggerHeading, + type DataAttributes, + type HeadingType, + type IconProps, + type RendersElement, + type RendersNullableElement, + type TrackingEvent, +} from './utils/types'; import type {Variant} from './theme-variant-context'; import type {PressHandler} from './touchable'; import type {VideoElement, VideoSource} from './video'; import type {ButtonLink, ButtonPrimary, ButtonSecondary} from './button'; import type {ExclusifyUnion} from './utils/utility-types'; -import type { - DataAttributes, - HeadingType, - IconProps, - RendersElement, - RendersNullableElement, - TrackingEvent, -} from './utils/types'; const useInnerText = () => { const [text, setText] = React.useState(''); @@ -369,6 +370,7 @@ type CardContentProps = { headline?: string | RendersNullableElement; headlineRef?: (instance: HTMLElement | null) => void; pretitle?: string; + pretitleAs?: HeadingType; pretitleLinesMax?: number; title?: string; titleAs?: HeadingType; @@ -387,6 +389,7 @@ const CardContent = ({ headline, headlineRef, pretitle, + pretitleAs, pretitleLinesMax, title, titleAs = 'h3', @@ -405,31 +408,81 @@ const CardContent = ({
{/** using flex instead of nested Stacks, this way we can rearrange texts so the DOM structure makes more sense for screen reader users */}
- {title && ( -
- - {title} - -
- )} - {headline && ( - // assuming that the headline will always be followed by one of: pretitle, title, subtitle, description -
- {typeof headline === 'string' ? {headline} : headline} -
- )} - {pretitle && ( -
- - {pretitle} - -
+ {isBiggerHeading(titleAs, pretitleAs) ? ( + <> + {title && ( +
+ + {title} + +
+ )} + {headline && ( + // assuming that the headline will always be followed by one of: pretitle, title, subtitle, description +
+ {typeof headline === 'string' ? {headline} : headline} +
+ )} + {pretitle && ( +
+ + {pretitle} + +
+ )} + + ) : ( + <> + <> + {pretitle && ( +
+ + {pretitle} + +
+ )} + {headline && ( + // assuming that the headline will always be followed by one of: pretitle, title, subtitle, description +
+ {typeof headline === 'string' ? ( + {headline} + ) : ( + headline + )} +
+ )} + {title && ( +
+ + {title} + +
+ )} + + )} {subtitle && (
@@ -502,6 +555,7 @@ interface MediaCardBaseProps { asset?: React.ReactElement; headline?: string | RendersNullableElement; pretitle?: string; + pretitleAs?: HeadingType; pretitleLinesMax?: number; title?: string; titleAs?: HeadingType; @@ -535,6 +589,7 @@ export const MediaCard = React.forwardRef( asset, headline, pretitle, + pretitleAs, pretitleLinesMax, subtitle, subtitleLinesMax, @@ -561,7 +616,12 @@ export const MediaCard = React.forwardRef( const ariaLabel = ariaLabelProp || - [title, headlineText, pretitle, subtitle, description, extraText].filter(Boolean).join(' '); + (isBiggerHeading(titleAs, pretitleAs) + ? [title, headlineText, pretitle, subtitle, description, extraText] + : [pretitle, headlineText, title, subtitle, description, extraText] + ) + .filter(Boolean) + .join(' '); return ( ( headline={headline} headlineRef={headlineRef} pretitle={pretitle} + pretitleAs={pretitleAs} pretitleLinesMax={pretitleLinesMax} title={title} titleAs={titleAs} @@ -633,6 +694,7 @@ export const NakedCard = React.forwardRef( asset, headline, pretitle, + pretitleAs, pretitleLinesMax, subtitle, subtitleLinesMax, @@ -660,7 +722,12 @@ export const NakedCard = React.forwardRef( const ariaLabel = ariaLabelProp || - [title, headlineText, pretitle, subtitle, description, extraText].filter(Boolean).join(' '); + (isBiggerHeading(titleAs, pretitleAs) + ? [title, headlineText, pretitle, subtitle, description, extraText] + : [pretitle, headlineText, title, subtitle, description, extraText] + ) + .filter(Boolean) + .join(' '); return ( ( headline={headline} headlineRef={headlineRef} pretitle={pretitle} + pretitleAs={pretitleAs} pretitleLinesMax={pretitleLinesMax} title={title} titleAs={titleAs} @@ -857,6 +925,7 @@ interface DataCardBaseProps { asset?: React.ReactElement; headline?: string | RendersNullableElement; pretitle?: string; + pretitleAs?: HeadingType; pretitleLinesMax?: number; title?: string; titleAs?: HeadingType; @@ -891,6 +960,7 @@ export const DataCard = React.forwardRef( asset, headline, pretitle, + pretitleAs, pretitleLinesMax, title, titleAs = 'h3', @@ -921,7 +991,12 @@ export const DataCard = React.forwardRef( const ariaLabel = ariaLabelProp || - [title, headlineText, pretitle, description, extraText].filter(Boolean).join(' '); + (isBiggerHeading(titleAs, pretitleAs) + ? [title, headlineText, pretitle, subtitle, description, extraText] + : [pretitle, headlineText, title, subtitle, description, extraText] + ) + .filter(Boolean) + .join(' '); return ( ( headline={headline} headlineRef={headlineRef} pretitle={pretitle} + pretitleAs={pretitleAs} pretitleLinesMax={pretitleLinesMax} title={title} titleAs={titleAs} @@ -1136,8 +1212,10 @@ export const SnapCard = React.forwardRef( interface DisplayCardContentProps { title?: React.ReactNode; + titleAs?: HeadingType; headline?: React.ReactNode; pretitle?: React.ReactNode; + pretitleAs?: HeadingType; subtitle?: React.ReactNode; description?: React.ReactNode; extra?: React.ReactNode; @@ -1147,8 +1225,10 @@ interface DisplayCardContentProps { const DisplayCardContent = ({ title, + titleAs = 'h3', headline, pretitle, + pretitleAs, subtitle, description, extra, @@ -1158,21 +1238,44 @@ const DisplayCardContent = ({ // using flex instead of nested Stacks, this way we can rearrange texts so the DOM structure makes more sense for screen reader users return (
- {title && ( -
- {title} -
- )} - {headline && ( - // assuming that the headline will always be followed by one of: pretitle, title, subtitle, description -
- {headline} -
- )} - {pretitle && ( -
- {pretitle} -
+ {isBiggerHeading(titleAs, pretitleAs) ? ( + <> + {title && ( +
+ {title} +
+ )} + {headline && ( + // assuming that the headline will always be followed by one of: pretitle, title, subtitle, description +
+ {headline} +
+ )} + {pretitle && ( +
+ {pretitle} +
+ )} + + ) : ( + <> + {pretitle && ( +
+ {pretitle} +
+ )} + {headline && ( + // assuming that the headline will always be followed by one of: pretitle, title, subtitle, description +
+ {headline} +
+ )} + {title && ( +
+ {title} +
+ )} + )} {subtitle && ( @@ -1212,6 +1315,7 @@ interface CommonDisplayCardProps { dataAttributes?: DataAttributes; headline?: React.ReactComponentElement; pretitle?: string; + pretitleAs?: HeadingType; pretitleLinesMax?: number; title: string; titleAs?: HeadingType; @@ -1275,6 +1379,7 @@ const DisplayCard = React.forwardRef( asset, headline, pretitle, + pretitleAs, pretitleLinesMax, title, titleAs = 'h3', @@ -1323,7 +1428,12 @@ const DisplayCard = React.forwardRef( const ariaLabel = ariaLabelProp || - [title, headlineText, pretitle, description, extraText].filter(Boolean).join(' '); + (isBiggerHeading(titleAs, pretitleAs) + ? [title, headlineText, pretitle, description, extraText] + : [pretitle, headlineText, title, description, extraText] + ) + .filter(Boolean) + .join(' '); return ( ( ) : undefined } + titleAs={titleAs} headline={headline} pretitle={ pretitle ? ( @@ -1425,6 +1536,7 @@ const DisplayCard = React.forwardRef( ) : undefined } + pretitleAs={pretitleAs} description={ description ? ( ; pretitle?: string; + pretitleAs?: HeadingType; pretitleLinesMax?: number; title?: string; titleAs?: HeadingType; @@ -1568,6 +1681,7 @@ export const PosterCard = React.forwardRef( asset, headline, pretitle, + pretitleAs, pretitleLinesMax, title, titleAs = 'h3', @@ -1633,7 +1747,12 @@ export const PosterCard = React.forwardRef( const ariaLabel = ariaLabelProp || - [title, headlineText, pretitle, subtitle, description, extraText].filter(Boolean).join(' '); + (isBiggerHeading(titleAs, pretitleAs) + ? [title, headlineText, pretitle, subtitle, description, extraText] + : [pretitle, headlineText, title, subtitle, description, extraText] + ) + .filter(Boolean) + .join(' '); return ( ( ) : undefined } + titleAs={titleAs} headline={headline} pretitle={ pretitle ? ( @@ -1738,6 +1858,7 @@ export const PosterCard = React.forwardRef( ) : undefined } + pretitleAs={pretitleAs} subtitle={ subtitle ? (