Skip to content

Commit

Permalink
Merge pull request #252 from MetroStar/card-updates
Browse files Browse the repository at this point in the history
Card Updates
  • Loading branch information
jbouder authored Aug 28, 2024
2 parents 5f3208b + 02ce778 commit 6802cf6
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 28 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/comet-uswds/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@metrostar/comet-uswds",
"version": "3.1.0",
"version": "3.2.0",
"description": "React with TypeScript Component Library based on USWDS 3.0.",
"license": "Apache-2.0",
"main": "./dist/cjs/index.js",
Expand Down
110 changes: 103 additions & 7 deletions packages/comet-uswds/src/components/card/card.figma.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,116 @@
import { Card, CardBody, CardFooter, CardHeader } from './card';
import { Card, CardBody, CardFooter, CardHeader, CardMedia } from './card';
import figma from '@figma/code-connect';
import Button from '../button';

figma.connect(
Card,
'https://www.figma.com/design/U58Pbb84dLaZfvFvdtGVdT/Comet-UI-Kit?node-id=43-2601',
{
props: {
layout: figma.enum('Type', {
Default: 'default',
Flag: 'flag',
}),
inset: figma.enum('Variant', {
Inset: true,
}),
exdent: figma.enum('Variant', {
Exdent: true,
}),
},
example: ({ layout, inset, exdent }) => (
<Card id="card-default" layout={layout}>
<CardMedia inset={inset} exdent={exdent}>
<img
src="https://designsystem.digital.gov/img/introducing-uswds-2-0/built-to-grow--alt.jpg"
alt="a placeholder image"
/>
</CardMedia>
</Card>
),
},
);

figma.connect(
Card,
'https://www.figma.com/design/U58Pbb84dLaZfvFvdtGVdT/Comet-UI-Kit?node-id=43-2604',
{
props: {},
variant: {
Variant: 'Default',
},
example: () => (
<Card id="card-1">
<CardHeader>Card Header</CardHeader>
<CardBody>Card Body</CardBody>
<Card id="card-default">
<CardMedia>
<img
src="https://designsystem.digital.gov/img/introducing-uswds-2-0/built-to-grow--alt.jpg"
alt="a placeholder image"
/>
</CardMedia>
<CardHeader>Card title</CardHeader>
<CardBody>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis earum tenetur quo
cupiditate, eaque qui officia recusandae.
</CardBody>
<CardFooter>
<Button id="button">Button</Button>
</CardFooter>
</Card>
),
},
);

figma.connect(
Card,
'https://www.figma.com/design/U58Pbb84dLaZfvFvdtGVdT/Comet-UI-Kit?node-id=43-2604',
{
props: {},
variant: {
Variant: 'Header first',
},
example: () => (
<Card id="card-default">
<CardHeader>Card title</CardHeader>
<CardMedia>
<img
src="https://designsystem.digital.gov/img/introducing-uswds-2-0/built-to-grow--alt.jpg"
alt="a placeholder image"
/>
</CardMedia>
<CardBody>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis earum tenetur quo
cupiditate, eaque qui officia recusandae.
</CardBody>
<CardFooter>
<Button id="button">Button</Button>
</CardFooter>
</Card>
),
},
);

figma.connect(
Card,
'https://www.figma.com/design/U58Pbb84dLaZfvFvdtGVdT/Comet-UI-Kit?node-id=46-7016',
{
props: {
mediaRight: figma.enum('Variant', {
'Media left': false,
'Media right': true,
}),
},
example: ({ mediaRight }) => (
<Card id="card-default" layout="flag" mediaRight={mediaRight}>
<CardHeader>Card title</CardHeader>
<CardMedia>
<img
src="https://designsystem.digital.gov/img/introducing-uswds-2-0/built-to-grow--alt.jpg"
alt="a placeholder image"
/>
</CardMedia>
<CardBody>Lorem ipsum dolor sit amet consectetur adipisicing elit.</CardBody>
<CardFooter>
<Button id="card-button" variant="outline">
Click me...
</Button>
<Button id="button">Button</Button>
</CardFooter>
</Card>
),
Expand Down
51 changes: 44 additions & 7 deletions packages/comet-uswds/src/components/card/card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,68 @@
import React from 'react';
import { StoryFn, Meta } from '@storybook/react';
import { Card, CardHeader, CardFooter, CardBody, Button } from '../../index';
import { CardProps } from './card';
import { CardMedia, CardProps } from './card';

const meta: Meta<typeof Card> = {
title: 'USWDS/Card',
component: Card,
argTypes: {
id: { required: true },
layout: { control: { type: 'select', options: ['default', 'flag'] } },
},
};
export default meta;

const Template: StoryFn<typeof Card> = (args: CardProps) => (
<Card {...args}>
<CardHeader>Card Header</CardHeader>
<CardBody>The meat of the card...</CardBody>
<CardHeader>Card</CardHeader>
<CardBody>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis earum tenetur quo cupiditate,
eaque qui officia recusandae.
</CardBody>
<CardFooter>
<Button id="card-button" variant="outline">
Click me...
</Button>
<Button id="card-button">Button</Button>
</CardFooter>
</Card>
);

export const Default = Template.bind({});
Default.args = {
id: 'card-1',
className: '',
layout: 'default',
className: 'maxw-mobile-lg',
};

const MediaTemplate: StoryFn<typeof Card> = (args: CardProps) => (
<Card {...args}>
<CardMedia>
<img
src="https://designsystem.digital.gov/img/introducing-uswds-2-0/built-to-grow--alt.jpg"
alt="a placeholder image"
/>
</CardMedia>
<CardHeader>Card with Media</CardHeader>
<CardBody>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis earum tenetur quo cupiditate,
eaque qui officia recusandae.
</CardBody>
<CardFooter>
<Button id="card-button">Button</Button>
</CardFooter>
</Card>
);

export const WithMedia = MediaTemplate.bind({});
WithMedia.args = {
id: 'card-standard-media',
layout: 'default',
className: 'maxw-mobile',
};

export const FlagLayout = MediaTemplate.bind({});
FlagLayout.args = {
id: 'card-flag-media',
layout: 'flag',
mediaRight: false,
className: 'maxw-tablet',
};
38 changes: 36 additions & 2 deletions packages/comet-uswds/src/components/card/card.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import { axe } from 'jest-axe';
import Card, { CardBody, CardHeader, CardFooter } from './card';
import Card, { CardBody, CardHeader, CardFooter, CardMedia } from './card';

describe('Card', () => {
test('should render with no accessibility violations', async () => {
Expand All @@ -21,13 +21,47 @@ describe('Card', () => {
expect(screen.getByText('Test')).toBeVisible();
});

test('should render a card with media', () => {
render(
<Card id="card-1">
<CardMedia>
<img src="someimage.jpg" alt="a placeholder image" />
</CardMedia>
<CardHeader>Foo</CardHeader>
<CardBody>Bar</CardBody>
<CardFooter>Test</CardFooter>
</Card>,
);
expect(screen.getByText('Foo')).toBeVisible();
expect(screen.getByText('Bar')).toBeVisible();
expect(screen.getByText('Test')).toBeVisible();
expect(screen.getByAltText('a placeholder image')).toBeVisible();
});

test('should render a card with media on right', () => {
render(
<Card id="card-1" mediaRight>
<CardMedia>
<img src="someimage.jpg" alt="a placeholder image" />
</CardMedia>
<CardHeader>Foo</CardHeader>
<CardBody>Bar</CardBody>
<CardFooter>Test</CardFooter>
</Card>,
);
expect(screen.getByText('Foo')).toBeVisible();
expect(screen.getByText('Bar')).toBeVisible();
expect(screen.getByText('Test')).toBeVisible();
expect(screen.getByAltText('a placeholder image')).toBeVisible();
});

test('should render with custom class', () => {
const { container } = render(
<Card id="card-2" className="some-class">
Body
</Card>,
);
expect(container.querySelector('#card-2')).toHaveClass('usa-card');
expect(container.querySelector('#card-2 > div')).toHaveClass('some-class');
expect(container.querySelector('#card-2')).toHaveClass('some-class');
});
});
68 changes: 60 additions & 8 deletions packages/comet-uswds/src/components/card/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ export interface CardProps {
* The unique identifier for this component
*/
id: string;
/**
* The layout of the card
*/
layout?: 'default' | 'flag';
/**
* Whether the media is on the right
*/
mediaRight?: boolean;
/**
* A custom class to apply to the component
*/
Expand All @@ -16,32 +24,76 @@ export interface CardProps {
children: ReactNode;
}

export interface CardMediaProps {
/**
* Whether the card media is inset
*/
inset?: boolean;
/**
* Whether the card media is exdent
*/
exdent?: boolean;
/**
* The body of the card media
*/
children: ReactNode;
}

/**
* Cards contain content and actions about a single subject.
*/
export const Card = ({ id, className, children }: CardProps): React.ReactElement => {
const classes = classnames('usa-card__container', className);
export const Card = ({
id,
layout = 'default',
mediaRight = false,
className,
children,
}: CardProps): React.ReactElement => {
const classes = classnames(
'usa-card',
{ 'usa-card--flag flex-1': layout === 'flag' },
{ 'usa-card--media-right': mediaRight },
className,
);

return (
<div className="usa-card" id={id}>
<div className={classes}>{children}</div>
<div className={classes} id={id}>
<div className="usa-card__container">{children}</div>
</div>
);
};

export const CardBody: React.FC<PropsWithChildren> = ({ children }: PropsWithChildren) => {
export const CardBody = ({ children }: PropsWithChildren): React.ReactElement => {
return <div className="usa-card__body">{children}</div>;
};

export const CardHeader: React.FC<PropsWithChildren> = ({ children }: PropsWithChildren) => {
export const CardHeader = ({ children }: PropsWithChildren): React.ReactElement => {
return (
<div className="usa-card__header">
<h2 className="usa-card__heading text-primary-dark">{children}</h2>
<h2 className="usa-card__heading">{children}</h2>
</div>
);
};

export const CardMedia = ({
inset = false,
exdent = false,
children,
}: CardMediaProps): React.ReactElement => {
const classes = classnames(
'usa-card__media',
{ 'usa-card__media--inset': inset },
{ 'usa-card__media--exdent': exdent },
);

return (
<div className={classes}>
<div className="usa-card__img">{children}</div>
</div>
);
};

export const CardFooter: React.FC<PropsWithChildren> = ({ children }: PropsWithChildren) => {
export const CardFooter = ({ children }: PropsWithChildren): React.ReactElement => {
return <div className="usa-card__footer">{children}</div>;
};

Expand Down
2 changes: 1 addition & 1 deletion packages/comet-uswds/src/components/card/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { default, CardHeader, CardBody, CardFooter } from './card';
export { default, CardHeader, CardMedia, CardBody, CardFooter } from './card';
2 changes: 1 addition & 1 deletion packages/comet-uswds/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export { default as Breadcrumb, BreadcrumbItem } from './breadcrumb';
export type { BreadcrumbItemProps } from './breadcrumb';
export { default as Button } from './button';
export { default as ButtonGroup } from './button-group';
export { default as Card, CardFooter, CardBody, CardHeader } from './card';
export { default as Card, CardFooter, CardBody, CardHeader, CardMedia } from './card';
export { default as CharacterCount, CharacterCountContainer } from './character-count';
export { default as Checkbox, CheckboxGroup } from './checkbox';
export type { CheckboxData } from './checkbox';
Expand Down

0 comments on commit 6802cf6

Please sign in to comment.