From 041becfb31783afc87dbe21bf656d0d2bc1b7c78 Mon Sep 17 00:00:00 2001 From: Johnny Bouder Date: Tue, 27 Aug 2024 16:11:57 -0400 Subject: [PATCH 1/4] Update card to support media left and right. Update card to support inset and exdent media. --- .../src/components/card/card.stories.tsx | 51 ++++++++++++--- .../src/components/card/card.test.tsx | 38 +++++++++++- .../comet-uswds/src/components/card/card.tsx | 62 +++++++++++++++++-- .../comet-uswds/src/components/card/index.ts | 2 +- packages/comet-uswds/src/components/index.ts | 2 +- 5 files changed, 139 insertions(+), 16 deletions(-) diff --git a/packages/comet-uswds/src/components/card/card.stories.tsx b/packages/comet-uswds/src/components/card/card.stories.tsx index 978bc776..2693eb7a 100644 --- a/packages/comet-uswds/src/components/card/card.stories.tsx +++ b/packages/comet-uswds/src/components/card/card.stories.tsx @@ -1,25 +1,27 @@ 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 = { title: 'USWDS/Card', component: Card, argTypes: { id: { required: true }, + layout: { control: { type: 'select', options: ['default', 'flag'] } }, }, }; export default meta; const Template: StoryFn = (args: CardProps) => ( - Card Header - The meat of the card... + Card + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis earum tenetur quo cupiditate, + eaque qui officia recusandae. + - + ); @@ -27,5 +29,40 @@ const Template: StoryFn = (args: CardProps) => ( export const Default = Template.bind({}); Default.args = { id: 'card-1', - className: '', + layout: 'default', + className: 'maxw-mobile-lg', +}; + +const MediaTemplate: StoryFn = (args: CardProps) => ( + + + a placeholder image + + Card with Media + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis earum tenetur quo cupiditate, + eaque qui officia recusandae. + + + + + +); + +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', }; diff --git a/packages/comet-uswds/src/components/card/card.test.tsx b/packages/comet-uswds/src/components/card/card.test.tsx index 4a6150cb..9e7451ad 100644 --- a/packages/comet-uswds/src/components/card/card.test.tsx +++ b/packages/comet-uswds/src/components/card/card.test.tsx @@ -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 () => { @@ -21,6 +21,40 @@ describe('Card', () => { expect(screen.getByText('Test')).toBeVisible(); }); + test('should render a card with media', () => { + render( + + + a placeholder image + + Foo + Bar + Test + , + ); + 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( + + + a placeholder image + + Foo + Bar + Test + , + ); + 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( @@ -28,6 +62,6 @@ describe('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'); }); }); diff --git a/packages/comet-uswds/src/components/card/card.tsx b/packages/comet-uswds/src/components/card/card.tsx index 915d22f7..e4476e8f 100644 --- a/packages/comet-uswds/src/components/card/card.tsx +++ b/packages/comet-uswds/src/components/card/card.tsx @@ -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 */ @@ -16,15 +24,41 @@ 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 ( -
-
{children}
+
+
{children}
); }; @@ -36,7 +70,25 @@ export const CardBody: React.FC = ({ children }: PropsWithChi export const CardHeader: React.FC = ({ children }: PropsWithChildren) => { return (
-

{children}

+

{children}

+
+ ); +}; + +export const CardMedia: React.FC = ({ + inset = false, + exdent = false, + children, +}: CardMediaProps) => { + const classes = classnames( + 'usa-card__media', + { 'usa-card__media--inset': inset }, + { 'usa-card__media--exdent': exdent }, + ); + + return ( +
+
{children}
); }; diff --git a/packages/comet-uswds/src/components/card/index.ts b/packages/comet-uswds/src/components/card/index.ts index 2a0cd701..db19a2f1 100644 --- a/packages/comet-uswds/src/components/card/index.ts +++ b/packages/comet-uswds/src/components/card/index.ts @@ -1 +1 @@ -export { default, CardHeader, CardBody, CardFooter } from './card'; +export { default, CardHeader, CardMedia, CardBody, CardFooter } from './card'; diff --git a/packages/comet-uswds/src/components/index.ts b/packages/comet-uswds/src/components/index.ts index f5a5db09..eb624bde 100644 --- a/packages/comet-uswds/src/components/index.ts +++ b/packages/comet-uswds/src/components/index.ts @@ -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'; From d3160856d06fdfdda56e90c7946dcc5d0f75e11e Mon Sep 17 00:00:00 2001 From: Johnny Bouder Date: Tue, 27 Aug 2024 16:34:34 -0400 Subject: [PATCH 2/4] Update card code connect file for card updates. --- .../src/components/card/card.figma.tsx | 110 ++++++++++++++++-- 1 file changed, 103 insertions(+), 7 deletions(-) diff --git a/packages/comet-uswds/src/components/card/card.figma.tsx b/packages/comet-uswds/src/components/card/card.figma.tsx index c32c28bb..1d19d271 100644 --- a/packages/comet-uswds/src/components/card/card.figma.tsx +++ b/packages/comet-uswds/src/components/card/card.figma.tsx @@ -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 }) => ( + + + a placeholder image + + + ), + }, +); + figma.connect( Card, 'https://www.figma.com/design/U58Pbb84dLaZfvFvdtGVdT/Comet-UI-Kit?node-id=43-2604', { props: {}, + variant: { + Variant: 'Default', + }, example: () => ( - - Card Header - Card Body + + + a placeholder image + + Card title + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis earum tenetur quo + cupiditate, eaque qui officia recusandae. + + + + + + ), + }, +); + +figma.connect( + Card, + 'https://www.figma.com/design/U58Pbb84dLaZfvFvdtGVdT/Comet-UI-Kit?node-id=43-2604', + { + props: {}, + variant: { + Variant: 'Header first', + }, + example: () => ( + + Card title + + a placeholder image + + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis earum tenetur quo + cupiditate, eaque qui officia recusandae. + + + + + + ), + }, +); + +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 title + + a placeholder image + + Lorem ipsum dolor sit amet consectetur adipisicing elit. - + ), From 53810680a014401084d422dcebfa52c753e77744 Mon Sep 17 00:00:00 2001 From: Johnny Bouder Date: Tue, 27 Aug 2024 16:37:52 -0400 Subject: [PATCH 3/4] Update comet-uswds to next minor version. --- package-lock.json | 2 +- packages/comet-uswds/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4a4ae6b2..a14fb591 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14952,7 +14952,7 @@ }, "packages/comet-uswds": { "name": "@metrostar/comet-uswds", - "version": "3.1.0", + "version": "3.2.0", "license": "Apache-2.0", "dependencies": { "@uswds/uswds": "3.8.2", diff --git a/packages/comet-uswds/package.json b/packages/comet-uswds/package.json index 0daf4f83..ae5758b0 100644 --- a/packages/comet-uswds/package.json +++ b/packages/comet-uswds/package.json @@ -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", From 02ce7789bfec6f848a882a32834d24b7a3223aae Mon Sep 17 00:00:00 2001 From: Johnny Bouder Date: Wed, 28 Aug 2024 07:05:10 -0400 Subject: [PATCH 4/4] Remove redundant typing. Update all card components with standard declaration. --- packages/comet-uswds/src/components/card/card.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/comet-uswds/src/components/card/card.tsx b/packages/comet-uswds/src/components/card/card.tsx index e4476e8f..2b9de60a 100644 --- a/packages/comet-uswds/src/components/card/card.tsx +++ b/packages/comet-uswds/src/components/card/card.tsx @@ -63,11 +63,11 @@ export const Card = ({ ); }; -export const CardBody: React.FC = ({ children }: PropsWithChildren) => { +export const CardBody = ({ children }: PropsWithChildren): React.ReactElement => { return
{children}
; }; -export const CardHeader: React.FC = ({ children }: PropsWithChildren) => { +export const CardHeader = ({ children }: PropsWithChildren): React.ReactElement => { return (

{children}

@@ -75,11 +75,11 @@ export const CardHeader: React.FC = ({ children }: PropsWithC ); }; -export const CardMedia: React.FC = ({ +export const CardMedia = ({ inset = false, exdent = false, children, -}: CardMediaProps) => { +}: CardMediaProps): React.ReactElement => { const classes = classnames( 'usa-card__media', { 'usa-card__media--inset': inset }, @@ -93,7 +93,7 @@ export const CardMedia: React.FC = ({ ); }; -export const CardFooter: React.FC = ({ children }: PropsWithChildren) => { +export const CardFooter = ({ children }: PropsWithChildren): React.ReactElement => { return
{children}
; };