Skip to content

Commit

Permalink
fixup! fixup! fixup! fixup! fixup! Feat(web-react): Introduce Card co…
Browse files Browse the repository at this point in the history
…mponent #1535
  • Loading branch information
pavelklibani committed Nov 27, 2024
1 parent 2d82baf commit 7b1a41c
Show file tree
Hide file tree
Showing 37 changed files with 592 additions and 273 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ElementType } from 'react';
import {
Button,
ButtonLink,
Card,
CardArtwork,
CardBody,
Expand All @@ -17,8 +17,8 @@ import {
UseCardStyleProps,
} from '../../../src/components';
import { LOGO, MEDIA_IMAGE } from '../../../src/components/Card/demo/constants';
import { AlignmentX, Direction, Sizes } from '../../../src/constants';
import { GridColumns, SizesDictionaryType } from '../../../src/types';
import { AlignmentX, Sizes } from '../../../src/constants';
import { CardDirection, CardSizes, GridColumns, SizesDictionaryType } from '../../../src/types';

type CardCompositionType = {
cardElementType: ElementType;
Expand All @@ -45,7 +45,7 @@ type CardCompositionType = {
export default {
title: 'Examples/Compositions',
argTypes: {
alignmentX: {
footerAlignmentX: {
control: 'select',
description: 'Alignment inside CardFooter component.',
options: [...Object.values(AlignmentX)],
Expand Down Expand Up @@ -96,10 +96,10 @@ export default {
direction: {
control: 'select',
description: 'Direction of the card.',
options: [...Object.values(Direction), 'horizontal-reversed'],
options: [...Object.values(CardDirection)],
table: {
category: 'Card',
defaultValue: { summary: Direction.VERTICAL },
defaultValue: { summary: CardDirection.VERTICAL },
},
},
eyebrowText: {
Expand Down Expand Up @@ -230,10 +230,10 @@ export default {
size: {
control: 'select',
description: 'Size of the media.',
options: [...Object.values(Sizes), 'auto'],
options: [...Object.values(CardSizes)],
table: {
category: 'CardMedia',
defaultValue: { summary: Sizes.MEDIUM },
defaultValue: { summary: CardSizes.MEDIUM },
},
},
titleElementType: {
Expand Down Expand Up @@ -276,7 +276,7 @@ export default {
cardLogoSize: Sizes.MEDIUM,
contentText:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus ultrices eleifend gravida, nulla nunc varius lectus, nec rutrum justo nibh eu lectus. Ut vulputate semper dui. Fusce erat. Morbi fringilla convallis sapien. Sed ac felis. Aliquam erat volutpat. Aliquam euismod. Aenean vel lectus. Nunc imperdiet justo nec dolor.',
direction: Direction.VERTICAL,
direction: CardDirection.VERTICAL,
eyebrowText: 'Eyebrow title',
gridCols: 3,
hasFilledHeight: false,
Expand All @@ -292,7 +292,7 @@ export default {
showEyebrow: true,
showMedia: true,
showTitle: true,
size: Sizes.MEDIUM,
size: CardSizes.MEDIUM,
titleElementType: 'h4',
titleText: 'Card Title',
titleWithLink: false,
Expand All @@ -302,13 +302,13 @@ export default {

export const CardComposition = (args: CardCompositionType) => {
const {
alignmentX,
cardElementType,
cardLogoHasSafeArea,
cardLogoSize,
contentText,
direction,
eyebrowText,
footerAlignmentX,
gridCols,
hasFilledHeight,
image,
Expand Down Expand Up @@ -366,9 +366,9 @@ export const CardComposition = (args: CardCompositionType) => {
</CardBody>
)}
{showFooter && (
<CardFooter alignmentX={alignmentX}>
<Button color="primary">Primary</Button>
<Button color="secondary">Secondary</Button>
<CardFooter alignmentX={footerAlignmentX}>
<ButtonLink color="primary">Primary</ButtonLink>
<ButtonLink color="secondary">Secondary</ButtonLink>
</CardFooter>
)}
</Card>
Expand Down
2 changes: 1 addition & 1 deletion packages/web-react/src/components/Card/CardArtwork.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const defaultProps: Partial<SpiritCardArtworkProps> = {
const CardArtwork = (props: SpiritCardArtworkProps) => {
const propsWithDefaults = { ...defaultProps, ...props };
const { children, alignmentX, ...restProps } = propsWithDefaults;
const { classProps } = useCardStyleProps({ artworkAlignment: alignmentX });
const { classProps } = useCardStyleProps({ artworkAlignmentX: alignmentX });
const { styleProps, props: otherProps } = useStyleProps(restProps);

return (
Expand Down
7 changes: 4 additions & 3 deletions packages/web-react/src/components/Card/CardLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import classNames from 'classnames';
import React from 'react';
import { useStyleProps, useClassNamePrefix } from '../../hooks';
import { useStyleProps } from '../../hooks';
import { SpiritCardLogoProps } from '../../types';
import { useCardStyleProps } from './useCardStyleProps';

const CardLogo = (props: SpiritCardLogoProps) => {
const { children, ...restProps } = props;
const { classProps } = useCardStyleProps();
const { styleProps, props: otherProps } = useStyleProps(restProps);
const cardLogoClass = useClassNamePrefix('CardLogo');

return (
<div {...otherProps} className={classNames(cardLogoClass, styleProps.className)} style={{ ...styleProps.style }}>
<div {...otherProps} className={classNames(classProps.logo, styleProps.className)} style={{ ...styleProps.style }}>
{children}
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions packages/web-react/src/components/Card/CardMedia.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import classNames from 'classnames';
import React from 'react';
import { useStyleProps } from '../../hooks';
import { SpiritCardMediaProps } from '../../types';
import { CardSizes, SpiritCardMediaProps } from '../../types';
import { useCardStyleProps } from './useCardStyleProps';

const defaultProps: Partial<SpiritCardMediaProps> = {
size: 'auto',
isExpanded: false,
hasFilledHeight: false,
isExpanded: false,
size: CardSizes.AUTO,
};

const CardMedia = (props: SpiritCardMediaProps) => {
Expand Down
90 changes: 46 additions & 44 deletions packages/web-react/src/components/Card/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Card can be displayed in a vertical, horizontal, or reversed horizontal layout.
```

👉 Keep in mind that, no matter the layout, the Card subcomponents must be arranged in the order
[specified above](#card).
[specified above](#card-1).

### Boxed Cards

Expand Down Expand Up @@ -197,7 +197,7 @@ Additionally, there is a `filledHeight` prop that expands the media to match the
content. This option works with both boxed and non-boxed Card, but is only available in the horizontal Card layout.

```jsx
<CArd direction="horizontal">
<Card direction="horizontal">
<CardMedia hasFilledHeight>
{/**/}
</CardMedia>
Expand Down Expand Up @@ -231,7 +231,7 @@ subcomponent.

```jsx
<CardLogo>
<PartnerLogo class="PartnerLogo">
<PartnerLogo>
<img src="" alt="Product Name" />
</PartnerLogo>
</CardLogo>
Expand Down Expand Up @@ -314,34 +314,6 @@ On top of the API options, the components accept [additional attributes][readme-
If you need more control over the styling of a component, you can use [style props][readme-style-props]
and [escape hatches][readme-escape-hatches].

## Full Example

When you put it all together:

```jsx
<Card isBoxed>
<CardMedia>
<img src="" alt="" />
</CardMedia>
<CardLogo>
<PartnerLogo>
<img src="" alt="Logo" />
</PartnerLogo>
</CardLogo>
<CardBody>
<CardEyebrow>Content options</CardEyebrow>
<CardTitle>
<CardLink href="#">Card Title</CardLink>
</CardTitle>
<p>Card content</p>
</CardBody>
<CardFooter>
<ButtonLink>Primary</ButtonLink>
<ButtonLink>Secondary</ButtonLink>
</CardFooter>
</Card>
```

## Card Grid

In a typical use case, you will display multiple Cards in a [Grid][grid].
Expand All @@ -357,7 +329,7 @@ In a typical use case, you will display multiple Cards in a [Grid][grid].
Depending on your situation, you may want to use the list semantics. And it will work!

```jsx
<Grid cols={{ mobile: 1, tablet: 2, desktop: 3 }}>
<Grid cols={{ mobile: 1, tablet: 2, desktop: 3 }} elementType="ul">
<Card elementType="li">{/**/}</Card>
<Card elementType="li">{/**/}</Card>
<Card elementType="li">{/**/}</Card>
Expand Down Expand Up @@ -404,9 +376,9 @@ CardMedia image in a link:

```jsx
<CardMedia>
<a href="#" aria-hidden="true">
<Link href="#" aria-hidden="true">
<img src="https://via.placeholder.com/300x200" alt="" />
</a>
</Link>
</CardMedia>
```

Expand All @@ -416,24 +388,54 @@ confused by too many links in the Card.
### The “Read More” Use Case

For article previews or similar use cases, you may want to display a limited amount of text content with a “Read More”
link. For optimum accessibility, you should only provide this in form of a text node, not a button or a link:
link. For optimum accessibility, you should only provide this in the form of a text node, not a button or a link:

```jsx
<CardTitle>
<CardLink href="#">Card title</a>
</CardTitle>
<p>{/**/}</p>
<!-- DON'T DO THIS -->
<a href="#" class="link-primary link-underlined">Read more</a>
<!-- This is correct -->
<div class="link-primary link-underlined">Read more</div>
<CardBody>
<CardTitle>
<CardLink href="#">Card title</a>
</CardTitle>
<p>{/**/}</p>
{/* DON'T DO THIS */}
<Link href="#" underlined="always">Read more</Link>
{/* This is correct */}
<div class="link-primary link-underlined">Read more</div>
</CardBody>
```

This way, the Card will only have a single accessible link which will be announced by screen readers.

## Full Example

When you put it all together:

```jsx
<Card isBoxed>
<CardMedia>
<img src="" alt="" />
</CardMedia>
<CardLogo>
<PartnerLogo>
<img src="" alt="Logo" />
</PartnerLogo>
</CardLogo>
<CardBody>
<CardEyebrow>Content options</CardEyebrow>
<CardTitle>
<CardLink href="#">Card Title</CardLink>
</CardTitle>
<p>Card content</p>
</CardBody>
<CardFooter>
<ButtonLink>Primary</ButtonLink>
<ButtonLink>Secondary</ButtonLink>
</CardFooter>
</Card>
```

ℹ️ A big shout-out to [Ondřej Pohl][ondrej-pohl] for sharing many of these best practices!

[grid]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web/src/scss/components/Grid/README.md
[dictionary-alignment]: https://github.com/lmc-eu/spirit-design-system/blob/main/docs/DICTIONARIES.md#alignment
[dictionary-size]: https://github.com/lmc-eu/spirit-design-system/blob/main/docs/DICTIONARIES.md#size
[grid]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/src/components/Grid/README.md
[ondrej-pohl]: https://linkedin.com/in/ondrejpohl
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ describe('Card', () => {

restPropsTest(Card, 'article');

it('should render card component', () => {
it('should render card component and have default class names', () => {
render(<Card />);

expect(screen.getByRole('article')).toBeInTheDocument();
expect(screen.getByRole('article')).toHaveClass('Card Card--vertical');
});

it('should render custom element', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ describe('CardArtwork', () => {

alignmentXPropsTest(CardArtwork, 'CardArtwork');

it('should render artwork card component', () => {
it('should render artwork card component and have default class name', () => {
render(<CardArtwork data-testId="test" />);

expect(screen.getByTestId('test')).toBeInTheDocument();
expect(screen.getByTestId('test')).toHaveClass('CardArtwork');
});

it('should render text children', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ describe('CardBody', () => {

restPropsTest(CardBody, '.CardBody');

it('should render body card component', () => {
it('should render body card component and have default class name', () => {
render(<CardBody data-testId="test" />);

expect(screen.getByTestId('test')).toBeInTheDocument();
expect(screen.getByTestId('test')).toHaveClass('CardBody');
});

it('should render text children', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ describe('CardEyebrow', () => {

restPropsTest(CardEyebrow, '.CardEyebrow');

it('should render eyebrow card component', () => {
it('should render eyebrow card component and have default class name', () => {
render(<CardEyebrow data-testId="test" />);

expect(screen.getByTestId('test')).toBeInTheDocument();
expect(screen.getByTestId('test')).toHaveClass('CardEyebrow');
});

it('should render text children', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ describe('CardFooter', () => {

alignmentXPropsTest(CardFooter, 'CardFooter');

it('should render footer card component', () => {
it('should render footer card component and have default class names', () => {
render(<CardFooter />);

expect(screen.getByRole('contentinfo')).toBeInTheDocument();
expect(screen.getByRole('contentinfo')).toHaveClass('CardFooter CardFooter--alignmentXLeft');
});

it('should render text children', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ describe('CardLink', () => {

restPropsTest(CardLink, '.CardLink');

it('should render link card component', () => {
it('should render link card component and have default class name', () => {
render(<CardLink href="#" />);

expect(screen.getByRole('link')).toBeInTheDocument();
expect(screen.getByRole('link')).toHaveClass('CardLink');
});

it('should render text children', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ describe('CardLogo', () => {

restPropsTest(CardLogo, '.CardLogo');

it('should render logo card component', () => {
it('should render logo card component and have default class name', () => {
render(<CardLogo data-testId="test" />);

expect(screen.getByTestId('test')).toBeInTheDocument();
expect(screen.getByTestId('test')).toHaveClass('CardLogo');
});

it('should render text children', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ describe('CardMedia', () => {

sizePropsTest(CardMedia);

it('should render media card media component', () => {
it('should render media card media component and have default class names', () => {
render(<CardMedia data-testId="test" />);

expect(screen.getByTestId('test')).toBeInTheDocument();
expect(screen.getByTestId('test')).toHaveClass('CardMedia CardMedia--auto');
});

it('should render auto size', () => {
Expand Down
Loading

0 comments on commit 7b1a41c

Please sign in to comment.