Skip to content

Commit

Permalink
feat(Card)!: remove top-level sub-component(s) (#1692)
Browse files Browse the repository at this point in the history
- Combine card sub components into one file
- update docs to reflect this new paradigm
- rename directory and adjust copy
  • Loading branch information
booc0mtaco authored Jul 17, 2023
1 parent e8b03c0 commit 3ee6120
Show file tree
Hide file tree
Showing 18 changed files with 77 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -528,10 +528,6 @@ return <div className={componentClassName} {...other} />;

## Component Rules and Considerations <a name="component-rules"></a>

### Exactly one component per directory and per folder

Components in this library exist in a flat structure so each component directory needs to contain exactly one component file. Certain components may require several components to properly function (for instance, a `Table` may consist of `TableRow` and `TableCell` subcomponents), and these components should live as siblings in the `components` directory.

### Compound Components

Certain components (such as `<Tabs />` and `<Table />`) require splitting up into smaller subcomponents.
Expand All @@ -540,11 +536,11 @@ By default, we err towards more centralized control over the component architect

#### Conventions for compound components

- Compound components are composed of a parent component (e.g. `<Card>`) and children component (e.g. `<CardHeader>` and `<CardFooter>`).
- Compound component children names must always begin with the parent name. A parent component `Table` means that all child components related to it must begin with `Table` (such as `TableBody`, `TableRow` and `TableCell`).
- Compound component children have an associated `.module.css` file, and child component styles will contain styles relevant to the subcomponent element (e.g. `AccordionPanel.module.css` would begin with `.accordion__panel { ... }`).
- Compound components are composed of a parent component (e.g. `<Card>`) and children component (e.g. `<Card.Header>` and `<Card.Footer>`).
- Compound component children must be declared within the parent component file.
- Compound component children names must always begin with the parent name. A parent component `Table` means that all child components related to it must begin with `Table` (such as `Table.Body`, `Table.Row` and `Table.Cell`).
- Compound components never have an associated `.stories.tsx` file as they rely on the parent component's stories to render properly.
- Compound components should be re-exported from their parent component file for easier usage. For example, at the bottom of `Card.tsx`, add the lines:
- Compound components should be exported as subcomponents from their parent component file for easier usage. For example, at the bottom of `Card.tsx`, add the lines:

```tsx
// This demonstrates how bound subcomponents are attached
Expand Down
10 changes: 4 additions & 6 deletions .storybook/pages/CoursePlannerEdit/CoursePlannerEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import {
Button,
ButtonGroup,
Card,
CardBody,
CardFooter,
DataBar,
DragDrop,
DragDropContainerHeader,
Expand Down Expand Up @@ -310,7 +308,7 @@ export const TableCard = ({

return (
<Card className={componentClassName} {...other}>
<CardBody>
<Card.Body>
<Heading
as="h2"
className="mb-4"
Expand Down Expand Up @@ -362,10 +360,10 @@ export const TableCard = ({
})}
</Table.Body>
</Table>
</CardBody>
<CardFooter>
</Card.Body>
<Card.Footer>
<Button status="neutral">{buttonContent}</Button>
</CardFooter>
</Card.Footer>
</Card>
);
};
Expand Down
13 changes: 3 additions & 10 deletions .storybook/pages/CoursePlannerEdit/ProjectCard/ProjectCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@ import clsx from 'clsx';
import type { ReactNode } from 'react';
import React from 'react';

import {
Card,
CardHeader,
Heading,
Icon,
Menu,
NumberIcon,
} from '../../../../src';
import { Card, Heading, Icon, Menu, NumberIcon } from '../../../../src';
import type { HeadingElement } from '../../../../src/components/Heading';

import type { IconName } from '../../../../src/components/Icon';
Expand Down Expand Up @@ -96,7 +89,7 @@ export const ProjectCard = ({
orientation="horizontal"
{...other}
>
<CardHeader className={styles['project-card__header']}>
<Card.Header className={styles['project-card__header']}>
{number && numberAriaLabel && (
<NumberIcon
aria-label={numberAriaLabel}
Expand All @@ -105,7 +98,7 @@ export const ProjectCard = ({
size="sm"
/>
)}
</CardHeader>
</Card.Header>
<Card.Body className={styles['project-card__body']}>
<Heading
as={headingAs}
Expand Down
9 changes: 5 additions & 4 deletions src/components/Card/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type { StoryObj, Meta } from '@storybook/react';
import React from 'react';
import { Card } from './Card';
import CardBody from '../CardBody';
import CardFooter from '../CardFooter';
import CardHeader from '../CardHeader';

export default {
title: 'Components/Card',
component: Card,
subcomponents: { CardHeader, CardBody, CardFooter },
subcomponents: {
CardHeader: Card.Header,
CardBody: Card.Body,
CardFooter: Card.Footer,
},
parameters: {
badges: ['1.0'],
},
Expand Down
64 changes: 61 additions & 3 deletions src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import clsx from 'clsx';
import type { HTMLAttributes, ReactNode } from 'react';
import React from 'react';
import CardBody from '../CardBody';
import CardFooter from '../CardFooter';
import CardHeader from '../CardHeader';
import styles from './Card.module.css';

export interface Props extends HTMLAttributes<HTMLElement> {
Expand Down Expand Up @@ -35,6 +32,17 @@ export interface Props extends HTMLAttributes<HTMLElement> {
orientation?: 'vertical' | 'horizontal';
}

export interface CardSubComponentProps {
/**
* Child node(s) that can be nested inside component
*/
children: ReactNode;
/**
* CSS class names that can be appended to the component.
*/
className?: string;
}

/**
* `import {Card} from "@chanzuckerberg/eds";`
*
Expand Down Expand Up @@ -66,6 +74,56 @@ export const Card = ({

Card.displayName = 'Card';

/**
* Body of the Card component.
*/
const CardBody = ({ children, className, ...other }: CardSubComponentProps) => {
const componentClassName = clsx(styles['card__body'], className);
return (
<div className={componentClassName} {...other}>
{children}
</div>
);
};

CardBody.displayName = 'CardBody';

/**
* Footer of the Card component.
*/
const CardFooter = ({
children,
className,
...other
}: CardSubComponentProps) => {
const componentClassName = clsx(styles['card__footer'], className);
return (
<footer className={componentClassName} {...other}>
{children}
</footer>
);
};

CardFooter.displayName = 'CardFooter';

/**
* Header of the Card component.
*/
const CardHeader = ({
children,
className,
...other
}: CardSubComponentProps) => {
const componentClassName = clsx(styles['card__header'], className);
return (
<header className={componentClassName} {...other}>
{children}
</header>
);
};

CardHeader.displayName = 'CardHeader';

Card.Body = CardBody;
Card.Footer = CardFooter;
Card.Header = CardHeader;
31 changes: 0 additions & 31 deletions src/components/CardBody/CardBody.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/components/CardBody/index.ts

This file was deleted.

31 changes: 0 additions & 31 deletions src/components/CardFooter/CardFooter.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/components/CardFooter/index.ts

This file was deleted.

31 changes: 0 additions & 31 deletions src/components/CardHeader/CardHeader.tsx

This file was deleted.

1 change: 0 additions & 1 deletion src/components/CardHeader/index.ts

This file was deleted.

3 changes: 0 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ export { default as Button } from './components/Button';
export { default as ButtonDropdown } from './components/ButtonDropdown';
export { default as ButtonGroup } from './components/ButtonGroup';
export { default as Card } from './components/Card';
export { default as CardBody } from './components/CardBody';
export { default as CardFooter } from './components/CardFooter';
export { default as CardHeader } from './components/CardHeader';
export { default as Checkbox } from './components/Checkbox';
export { default as ClickableStyle } from './components/ClickableStyle';
export { default as DataBar } from './components/DataBar';
Expand Down

0 comments on commit 3ee6120

Please sign in to comment.