diff --git a/.changeset/add-card-component.md b/.changeset/add-card-component.md new file mode 100644 index 00000000000..5e6917a58f0 --- /dev/null +++ b/.changeset/add-card-component.md @@ -0,0 +1,5 @@ +--- +'@primer/react': minor +--- + +Add Card component with subcomponents: Card.Icon, Card.Image, Card.Heading, Card.Description, Card.Menu, and Card.Metadata diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-colorblind-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-colorblind-linux.png new file mode 100644 index 00000000000..9d513c74652 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-dimmed-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-dimmed-linux.png new file mode 100644 index 00000000000..692774fea4f Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-high-contrast-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-high-contrast-linux.png new file mode 100644 index 00000000000..ac8caa19164 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-linux.png new file mode 100644 index 00000000000..9d513c74652 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-tritanopia-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-tritanopia-linux.png new file mode 100644 index 00000000000..9d513c74652 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-colorblind-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-colorblind-linux.png new file mode 100644 index 00000000000..171b4a01008 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-high-contrast-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-high-contrast-linux.png new file mode 100644 index 00000000000..501b37ef7e1 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-linux.png new file mode 100644 index 00000000000..171b4a01008 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-tritanopia-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-tritanopia-linux.png new file mode 100644 index 00000000000..171b4a01008 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-Default-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-colorblind-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-colorblind-linux.png new file mode 100644 index 00000000000..a97c5a601a1 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-dimmed-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-dimmed-linux.png new file mode 100644 index 00000000000..8006e1d1b0f Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-high-contrast-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-high-contrast-linux.png new file mode 100644 index 00000000000..5945b1e9c8b Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-linux.png new file mode 100644 index 00000000000..a97c5a601a1 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-tritanopia-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-tritanopia-linux.png new file mode 100644 index 00000000000..a97c5a601a1 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-colorblind-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-colorblind-linux.png new file mode 100644 index 00000000000..566e499e531 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-high-contrast-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-high-contrast-linux.png new file mode 100644 index 00000000000..a7955375071 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-linux.png new file mode 100644 index 00000000000..566e499e531 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-tritanopia-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-tritanopia-linux.png new file mode 100644 index 00000000000..566e499e531 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Image-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-colorblind-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-colorblind-linux.png new file mode 100644 index 00000000000..2c95e8e73af Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-dimmed-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-dimmed-linux.png new file mode 100644 index 00000000000..d2163d1b387 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-high-contrast-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-high-contrast-linux.png new file mode 100644 index 00000000000..4696164a49f Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-linux.png new file mode 100644 index 00000000000..2c95e8e73af Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-tritanopia-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-tritanopia-linux.png new file mode 100644 index 00000000000..2c95e8e73af Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-colorblind-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-colorblind-linux.png new file mode 100644 index 00000000000..d328d643452 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-high-contrast-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-high-contrast-linux.png new file mode 100644 index 00000000000..8f2efddc18d Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-linux.png new file mode 100644 index 00000000000..d328d643452 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-linux.png differ diff --git a/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-tritanopia-linux.png b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-tritanopia-linux.png new file mode 100644 index 00000000000..d328d643452 Binary files /dev/null and b/.playwright/snapshots/components/Card.test.ts-snapshots/Card-With-Metadata-light-tritanopia-linux.png differ diff --git a/e2e/components/Card.test.ts b/e2e/components/Card.test.ts new file mode 100644 index 00000000000..87e3c1a2c36 --- /dev/null +++ b/e2e/components/Card.test.ts @@ -0,0 +1,59 @@ +import {test, expect} from '@playwright/test' +import {visit} from '../test-helpers/storybook' +import {themes} from '../test-helpers/themes' + +test.describe('Card', () => { + test.describe('Default', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-card--default', + globals: { + colorScheme: theme, + }, + }) + + // Default state + expect(await page.screenshot()).toMatchSnapshot(`Card.Default.${theme}.png`) + }) + }) + } + }) + + test.describe('With Image', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-card--with-image', + globals: { + colorScheme: theme, + }, + }) + + // Default state + expect(await page.screenshot()).toMatchSnapshot(`Card.With Image.${theme}.png`) + }) + }) + } + }) + + test.describe('With Metadata', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-card--with-metadata', + globals: { + colorScheme: theme, + }, + }) + + // Default state + expect(await page.screenshot()).toMatchSnapshot(`Card.With Metadata.${theme}.png`) + }) + }) + } + }) +}) diff --git a/packages/react/src/Card/Card.module.css b/packages/react/src/Card/Card.module.css new file mode 100644 index 00000000000..cd19688f8f9 --- /dev/null +++ b/packages/react/src/Card/Card.module.css @@ -0,0 +1,97 @@ +.Card { + display: grid; + position: relative; + border-radius: var(--borderRadius-large); + overflow: hidden; + grid-auto-rows: max-content auto; + border: var(--borderWidth-thin) solid var(--borderColor-default); + box-shadow: var(--shadow-resting-small); + background-color: var(--bgColor-default); +} + +.CardHeader { + display: block; + width: 100%; + height: auto; + /* stylelint-disable primer/spacing */ + padding: var(--stack-padding-spacious) var(--stack-padding-spacious) var(--stack-padding-normal) + var(--stack-padding-spacious); + /* stylelint-enable primer/spacing */ +} + +.CardHeaderEdgeToEdge { + padding: 0; + margin-bottom: var(--base-size-16); +} + +.CardImage { + display: block; + width: 100%; + height: auto; +} + +.CardIcon { + display: flex; + align-items: center; + justify-content: center; + width: var(--base-size-32); + height: var(--base-size-32); + border-radius: var(--borderRadius-medium); + background-color: var(--bgColor-muted); + color: var(--fgColor-muted); +} + +.CardBody { + display: grid; + gap: var(--base-size-16); + /* stylelint-disable-next-line primer/spacing */ + padding: 0 var(--stack-padding-spacious) var(--stack-padding-spacious) var(--stack-padding-spacious); +} + +.CardContent { + display: grid; + gap: var(--base-size-8); +} + +.CardHeading { + font-size: var(--text-body-size-large); + font-weight: var(--base-text-weight-semibold); + color: var(--fgColor-default); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin: 0; +} + +.CardDescription { + font-size: var(--text-body-size-medium); + color: var(--fgColor-muted); + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + line-clamp: 2; + margin: 0; +} + +.CardMetadataContainer { + display: flex; + align-items: center; + gap: var(--base-size-16); + font-size: var(--text-body-size-medium); + color: var(--fgColor-muted); +} + +.CardMetadataItem { + display: flex; + align-items: center; + gap: var(--base-size-8); + font: var(--text-body-shorthand-small); +} + +.CardMenu { + position: absolute; + top: var(--base-size-16); + right: var(--base-size-16); + z-index: 1; +} diff --git a/packages/react/src/Card/Card.stories.tsx b/packages/react/src/Card/Card.stories.tsx new file mode 100644 index 00000000000..32d51819fbb --- /dev/null +++ b/packages/react/src/Card/Card.stories.tsx @@ -0,0 +1,66 @@ +import type {Meta} from '@storybook/react-vite' +import {RocketIcon, RepoIcon, StarIcon} from '@primer/octicons-react' +import {Card} from './index' + +const meta = { + title: 'Components/Card', + component: Card, +} satisfies Meta + +export default meta + +export const Default = () => { + return ( +
+ + + Card Heading + This is a description of the card providing supplemental information. + Updated 2 hours ago + +
+ ) +} + +export const WithImage = () => { + return ( +
+ + + Card with Image + This card uses an edge-to-edge image instead of an icon. + +
+ ) +} + +export const WithMetadata = () => { + return ( +
+ + + primer/react + + {"GitHub's design system implemented as React components for building consistent user interfaces."} + + + + 1.2k stars + + +
+ ) +} + +export const Playground = { + render: () => ( +
+ + + Playground Card + Experiment with the Card component and its subcomponents. + Just now + +
+ ), +} diff --git a/packages/react/src/Card/Card.test.tsx b/packages/react/src/Card/Card.test.tsx new file mode 100644 index 00000000000..4fd9cb5158b --- /dev/null +++ b/packages/react/src/Card/Card.test.tsx @@ -0,0 +1,117 @@ +import {describe, expect, it} from 'vitest' +import {render, screen} from '@testing-library/react' +import {Card} from '../Card' +import {implementsClassName} from '../utils/testing' +import classes from './Card.module.css' + +const TestIcon = () => + +describe('Card', () => { + implementsClassName(props => , classes.Card) + + it('should render a Card with heading and description', () => { + render( + + Test Heading + Test Description + , + ) + expect(screen.getByText('Test Heading')).toBeInTheDocument() + expect(screen.getByText('Test Description')).toBeInTheDocument() + }) + + it('should render a heading as an h3 element', () => { + render( + + Heading + , + ) + expect(screen.getByRole('heading', {level: 3, name: 'Heading'})).toBeInTheDocument() + }) + + it('should render an icon', () => { + render( + + + With Icon + , + ) + expect(screen.getByTestId('test-icon')).toBeInTheDocument() + }) + + it('should render an image', () => { + render( + + + With Image + , + ) + const img = screen.getByRole('img', {name: 'Example'}) + expect(img).toBeInTheDocument() + expect(img).toHaveAttribute('src', 'https://example.com/image.png') + }) + + it('should render metadata', () => { + render( + + Metadata Card + Updated 2 hours ago + , + ) + expect(screen.getByText('Updated 2 hours ago')).toBeInTheDocument() + }) + + it('should render a menu', () => { + render( + + Menu Card + + + + , + ) + expect(screen.getByRole('button', {name: 'Options'})).toBeInTheDocument() + }) + + it('should apply edge-to-edge styling when image is provided', () => { + const {container} = render( + + + Edge to Edge + , + ) + const header = container.querySelector(`.${classes.CardHeader}`) + expect(header).toHaveClass(classes.CardHeaderEdgeToEdge) + }) + + it('should not apply edge-to-edge styling when only icon is provided', () => { + const {container} = render( + + + With Icon + , + ) + const header = container.querySelector(`.${classes.CardHeader}`) + expect(header).not.toHaveClass(classes.CardHeaderEdgeToEdge) + }) + + it('should support a custom className on the root element', () => { + const {container} = render( + + Custom + , + ) + expect(container.firstChild).toHaveClass('custom-class') + expect(container.firstChild).toHaveClass(classes.Card) + }) + + it('should forward a ref to the root element', () => { + const ref = {current: null as HTMLDivElement | null} + render( + + Ref Card + , + ) + expect(ref.current).toBeInstanceOf(HTMLDivElement) + }) +}) diff --git a/packages/react/src/Card/Card.tsx b/packages/react/src/Card/Card.tsx new file mode 100644 index 00000000000..b06e3cf67f6 --- /dev/null +++ b/packages/react/src/Card/Card.tsx @@ -0,0 +1,160 @@ +import {clsx} from 'clsx' +import React, {forwardRef} from 'react' +import classes from './Card.module.css' + +export type CardProps = React.ComponentPropsWithoutRef<'div'> & { + /** + * Provide an optional className to add to the outermost element rendered by + * the Card + */ + className?: string +} + +type HeadingLevel = 'h2' | 'h3' | 'h4' | 'h5' | 'h6' + +type HeadingProps = React.ComponentPropsWithoutRef<'h3'> & { + /** + * The heading level to render. Defaults to 'h3'. + */ + as?: HeadingLevel + children: React.ReactNode +} + +type DescriptionProps = React.ComponentPropsWithoutRef<'p'> & { + children: React.ReactNode +} + +type IconProps = { + /** + * An Octicon or custom SVG icon to render + */ + icon: React.ElementType + className?: string +} + +type ImageProps = React.ComponentPropsWithoutRef<'img'> & { + /** + * The image source URL + */ + src: string + /** + * Alt text for accessibility + */ + alt?: string +} + +type MenuProps = { + children: React.ReactNode +} + +type MetadataProps = React.ComponentPropsWithoutRef<'div'> & { + children: React.ReactNode +} + +const CardImpl = forwardRef(function Card({children, className, ...rest}, ref) { + let icon: React.ReactNode = null + let image: React.ReactNode = null + let heading: React.ReactNode = null + let description: React.ReactNode = null + let metadata: React.ReactNode = null + let menu: React.ReactNode = null + + const childArray = React.Children.toArray(children) + + for (const child of childArray) { + if (!React.isValidElement(child)) continue + + if (child.type === CardIcon) { + icon = child + } else if (child.type === CardImage) { + image = child + } else if (child.type === CardHeading) { + heading = child + } else if (child.type === CardDescription) { + description = child + } else if (child.type === CardMetadata) { + metadata = child + } else if (child.type === CardMenu) { + menu = child + } + } + + return ( +
+ {(image || icon) && ( +
{image || icon}
+ )} +
+
+ {heading} + {description} +
+ {metadata ?
{metadata}
: null} +
+ {menu ?
{menu}
: null} +
+ ) +}) + +const CardIcon = ({icon: IconComponent, className}: IconProps) => { + return ( + + + + ) +} + +CardIcon.displayName = 'Card.Icon' + +const CardImage = ({src, alt = '', className, ...rest}: ImageProps) => { + return {alt} +} + +CardImage.displayName = 'Card.Image' + +const CardHeading = forwardRef(function CardHeading( + {as: Component = 'h3', children, className, ...rest}, + ref, +) { + return ( + + {children} + + ) +}) + +const CardDescription = forwardRef(function CardDescription( + {children, className, ...rest}, + ref, +) { + return ( +

+ {children} +

+ ) +}) + +const CardMenu = ({children}: MenuProps) => { + return <>{children} +} + +CardMenu.displayName = 'Card.Menu' + +const CardMetadata = forwardRef(function CardMetadata( + {children, className, ...rest}, + ref, +) { + return ( +
+ {children} +
+ ) +}) + +export {CardImpl, CardIcon, CardImage, CardHeading, CardDescription, CardMenu, CardMetadata} +export type {HeadingProps as CardHeadingProps} +export type {DescriptionProps as CardDescriptionProps} +export type {IconProps as CardIconProps} +export type {ImageProps as CardImageProps} +export type {MenuProps as CardMenuProps} +export type {MetadataProps as CardMetadataProps} diff --git a/packages/react/src/Card/index.ts b/packages/react/src/Card/index.ts new file mode 100644 index 00000000000..a00b1d69385 --- /dev/null +++ b/packages/react/src/Card/index.ts @@ -0,0 +1,30 @@ +import {CardImpl, CardIcon, CardImage, CardHeading, CardDescription, CardMenu, CardMetadata} from './Card' +import type { + CardProps, + CardIconProps, + CardImageProps, + CardHeadingProps, + CardDescriptionProps, + CardMenuProps, + CardMetadataProps, +} from './Card' + +const Card = Object.assign(CardImpl, { + Icon: CardIcon, + Image: CardImage, + Heading: CardHeading, + Description: CardDescription, + Menu: CardMenu, + Metadata: CardMetadata, +}) + +export {Card} +export type { + CardProps, + CardIconProps, + CardImageProps, + CardHeadingProps, + CardDescriptionProps, + CardMenuProps, + CardMetadataProps, +} diff --git a/packages/react/src/__tests__/__snapshots__/exports.test.ts.snap b/packages/react/src/__tests__/__snapshots__/exports.test.ts.snap index cec11bdd137..8f7af11b577 100644 --- a/packages/react/src/__tests__/__snapshots__/exports.test.ts.snap +++ b/packages/react/src/__tests__/__snapshots__/exports.test.ts.snap @@ -46,6 +46,14 @@ exports[`@primer/react > should not update exports without a semver change 1`] = "ButtonGroup", "type ButtonGroupProps", "type ButtonProps", + "Card", + "type CardDescriptionProps", + "type CardHeadingProps", + "type CardIconProps", + "type CardImageProps", + "type CardMenuProps", + "type CardMetadataProps", + "type CardProps", "Checkbox", "CheckboxGroup", "type CheckboxGroupProps", diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 81c0fae44ad..cfe7fe16a3e 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -78,6 +78,16 @@ export {default as AvatarStack} from './AvatarStack' export type {AvatarStackProps} from './AvatarStack' export {Banner} from './Banner' export type {BannerProps} from './Banner' +export {Card} from './Card' +export type { + CardProps, + CardIconProps, + CardImageProps, + CardHeadingProps, + CardDescriptionProps, + CardMenuProps, + CardMetadataProps, +} from './Card' export {default as BranchName} from './BranchName' export type {BranchNameProps} from './BranchName' diff --git a/script/generate-e2e-tests.js b/script/generate-e2e-tests.js index fc80d76ddce..975b3f0709c 100755 --- a/script/generate-e2e-tests.js +++ b/script/generate-e2e-tests.js @@ -289,6 +289,25 @@ const components = new Map([ ], }, ], + [ + 'Card', + { + stories: [ + { + id: 'components-card--default', + name: 'Default', + }, + { + id: 'components-card--with-image', + name: 'With Image', + }, + { + id: 'components-card--with-metadata', + name: 'With Metadata', + }, + ], + }, + ], [ 'Checkbox', {