aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-11-22 18:12:32 +0100
committerArmand Philippot <git@armandphilippot.com>2023-11-22 19:01:04 +0100
commit329e7c89bac50be9db2c6d2ec6751ab0ffad42ac (patch)
treee389de0a3ccda15fa3fb0dbaace185c905449f7b /src/components
parent0ac690339083f01a0b12a74ec117eeccd055e932 (diff)
refactor(components): replace items prop in Grid with children prop
It is easier to read and to maintain this way. The `items` prop was not useful since we are not manipulating the items. Changes: * extract GridItem component from Grid component * replace `items` prop of type Array<ReactNode> with `children` prop of type ReactNode * remove GridItem styles
Diffstat (limited to 'src/components')
-rw-r--r--src/components/mdx.tsx13
-rw-r--r--src/components/molecules/grid/grid-item.tsx15
-rw-r--r--src/components/molecules/grid/grid.module.scss9
-rw-r--r--src/components/molecules/grid/grid.stories.tsx224
-rw-r--r--src/components/molecules/grid/grid.test.tsx73
-rw-r--r--src/components/molecules/grid/grid.tsx23
-rw-r--r--src/components/molecules/grid/index.ts1
7 files changed, 245 insertions, 113 deletions
diff --git a/src/components/mdx.tsx b/src/components/mdx.tsx
index f11dda5..9f0a4a5 100644
--- a/src/components/mdx.tsx
+++ b/src/components/mdx.tsx
@@ -2,7 +2,7 @@ import type { MDXComponents } from 'mdx/types';
import NextImage from 'next/image';
import type { AnchorHTMLAttributes, ImgHTMLAttributes, ReactNode } from 'react';
import { Figure, Heading, Link, List, ListItem } from './atoms';
-import { Code, Grid } from './molecules';
+import { Code, Grid, GridItem } from './molecules';
const Anchor = ({
children = '',
@@ -45,16 +45,15 @@ const Img = ({
return <img {...props} alt={alt} height={height} src={src} width={width} />;
};
-const Gallery = ({ children }: { children: ReactNode[] }) => (
+const Gallery = ({ children }: { children: ReactNode }) => (
<Grid
// eslint-disable-next-line react/jsx-no-literals
gap="sm"
- items={children.map((child, index) => {
- return { id: `${index}`, item: child };
- })}
// eslint-disable-next-line react/jsx-no-literals
sizeMin="250px"
- />
+ >
+ {children}
+ </Grid>
);
export const mdxComponents: MDXComponents = {
@@ -63,6 +62,8 @@ export const mdxComponents: MDXComponents = {
figure: ({ ref, ...props }) => <Figure {...props} />,
Figure,
Gallery,
+ Grid,
+ GridItem,
h1: ({ ref, ...props }) => <Heading {...props} level={1} />,
h2: ({ ref, ...props }) => <Heading {...props} level={2} />,
h3: ({ ref, ...props }) => <Heading {...props} level={3} />,
diff --git a/src/components/molecules/grid/grid-item.tsx b/src/components/molecules/grid/grid-item.tsx
new file mode 100644
index 0000000..0592cec
--- /dev/null
+++ b/src/components/molecules/grid/grid-item.tsx
@@ -0,0 +1,15 @@
+import { type ForwardRefRenderFunction, forwardRef } from 'react';
+import { ListItem, type ListItemProps } from '../../atoms';
+
+export type GridItemProps = ListItemProps;
+
+const GridItemWithRef: ForwardRefRenderFunction<
+ HTMLLIElement,
+ GridItemProps
+> = ({ children, ...props }, ref) => (
+ <ListItem {...props} ref={ref}>
+ {children}
+ </ListItem>
+);
+
+export const GridItem = forwardRef(GridItemWithRef);
diff --git a/src/components/molecules/grid/grid.module.scss b/src/components/molecules/grid/grid.module.scss
index e253a89..f13af30 100644
--- a/src/components/molecules/grid/grid.module.scss
+++ b/src/components/molecules/grid/grid.module.scss
@@ -30,12 +30,3 @@
);
}
}
-
-.item {
- display: flex;
- flex-flow: row wrap;
-
- > * {
- flex: 1;
- }
-}
diff --git a/src/components/molecules/grid/grid.stories.tsx b/src/components/molecules/grid/grid.stories.tsx
index ce3ee2b..4e12af4 100644
--- a/src/components/molecules/grid/grid.stories.tsx
+++ b/src/components/molecules/grid/grid.stories.tsx
@@ -1,6 +1,6 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';
-import type { FC, ReactNode } from 'react';
import { Grid } from './grid';
+import { GridItem } from './grid-item';
export default {
title: 'Molecules/Grid',
@@ -19,107 +19,185 @@ export default {
const Template: ComponentStory<typeof Grid> = (args) => <Grid {...args} />;
-type ItemProps = {
- children: ReactNode;
-};
-
-const Item: FC<ItemProps> = ({ children }) => (
- <div style={{ border: '1px solid #000', padding: '1rem' }}>{children}</div>
-);
-
export const Default = Template.bind({});
Default.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- { id: 'item-4', item: <Item>Item 4</Item> },
- { id: 'item-5', item: <Item>Item 5</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 4
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 5
+ </GridItem>
+ </>
+ ),
};
export const OneColumn = Template.bind({});
OneColumn.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ </>
+ ),
col: 1,
gap: 'sm',
};
export const TwoColumns = Template.bind({});
TwoColumns.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ </>
+ ),
col: 2,
gap: 'sm',
};
export const ThreeColumns = Template.bind({});
ThreeColumns.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- { id: 'item-4', item: <Item>Item 4</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 4
+ </GridItem>
+ </>
+ ),
col: 3,
gap: 'sm',
};
export const FixedSize = Template.bind({});
FixedSize.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- { id: 'item-4', item: <Item>Item 4</Item> },
- { id: 'item-5', item: <Item>Item 5</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 4
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 5
+ </GridItem>
+ </>
+ ),
size: '300px',
gap: 'sm',
};
export const MaxSize = Template.bind({});
MaxSize.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- { id: 'item-4', item: <Item>Item 4</Item> },
- { id: 'item-5', item: <Item>Item 5</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 4
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 5
+ </GridItem>
+ </>
+ ),
sizeMax: '300px',
gap: 'sm',
};
export const MinSize = Template.bind({});
MinSize.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- { id: 'item-4', item: <Item>Item 4</Item> },
- { id: 'item-5', item: <Item>Item 5</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 4
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 5
+ </GridItem>
+ </>
+ ),
sizeMin: '100px',
gap: 'sm',
};
export const MinAndMaxSize = Template.bind({});
MinAndMaxSize.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- { id: 'item-4', item: <Item>Item 4</Item> },
- { id: 'item-5', item: <Item>Item 5</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 4
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 5
+ </GridItem>
+ </>
+ ),
sizeMax: '300px',
sizeMin: '100px',
gap: 'sm',
@@ -127,13 +205,25 @@ MinAndMaxSize.args = {
export const Fill = Template.bind({});
Fill.args = {
- items: [
- { id: 'item-1', item: <Item>Item 1</Item> },
- { id: 'item-2', item: <Item>Item 2</Item> },
- { id: 'item-3', item: <Item>Item 3</Item> },
- { id: 'item-4', item: <Item>Item 4</Item> },
- { id: 'item-5', item: <Item>Item 5</Item> },
- ],
+ children: (
+ <>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 1
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 2
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 3
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 4
+ </GridItem>
+ <GridItem style={{ border: '1px solid #000', padding: '1rem' }}>
+ Item 5
+ </GridItem>
+ </>
+ ),
col: 'auto-fill',
sizeMin: '100px',
gap: 'sm',
diff --git a/src/components/molecules/grid/grid.test.tsx b/src/components/molecules/grid/grid.test.tsx
index 212bdc4..e69610d 100644
--- a/src/components/molecules/grid/grid.test.tsx
+++ b/src/components/molecules/grid/grid.test.tsx
@@ -1,18 +1,25 @@
import { describe, expect, it } from '@jest/globals';
import { render, screen as rtlScreen } from '@testing-library/react';
-import { Grid, type GridItem } from './grid';
-
-const items: GridItem[] = [
- { id: 'item-1', item: 'Item 1' },
- { id: 'item-2', item: 'Item 2' },
- { id: 'item-3', item: 'Item 3' },
- { id: 'item-4', item: 'Item 4' },
- { id: 'item-5', item: 'Item 5' },
+import { Grid } from './grid';
+import { GridItem } from './grid-item';
+
+const items = [
+ { id: 'item-1', contents: 'Item 1' },
+ { id: 'item-2', contents: 'Item 2' },
+ { id: 'item-3', contents: 'Item 3' },
+ { id: 'item-4', contents: 'Item 4' },
+ { id: 'item-5', contents: 'Item 5' },
];
describe('Grid', () => {
it('render a list of items as grid', () => {
- render(<Grid items={items} />);
+ render(
+ <Grid>
+ {items.map((item) => (
+ <GridItem key={item.id}>{item.contents}</GridItem>
+ ))}
+ </Grid>
+ );
expect(rtlScreen.getAllByRole('listitem')).toHaveLength(items.length);
});
@@ -20,7 +27,13 @@ describe('Grid', () => {
it('can render a list of items with fixed size', () => {
const size = '200px';
- render(<Grid items={items} size={size} />);
+ render(
+ <Grid size={size}>
+ {items.map((item) => (
+ <GridItem key={item.id}>{item.contents}</GridItem>
+ ))}
+ </Grid>
+ );
expect(rtlScreen.getByRole('list')).toHaveClass('wrapper--has-fixed-size');
expect(rtlScreen.getByRole('list')).toHaveStyle({ '--size': size });
@@ -29,7 +42,13 @@ describe('Grid', () => {
it('can render a list of items with min size', () => {
const size = '200px';
- render(<Grid items={items} sizeMin={size} />);
+ render(
+ <Grid sizeMin={size}>
+ {items.map((item) => (
+ <GridItem key={item.id}>{item.contents}</GridItem>
+ ))}
+ </Grid>
+ );
expect(rtlScreen.getByRole('list')).toHaveClass('wrapper--has-min-size');
expect(rtlScreen.getByRole('list')).toHaveStyle({ '--size-min': size });
@@ -38,7 +57,13 @@ describe('Grid', () => {
it('can render a list of items with max size', () => {
const size = '200px';
- render(<Grid items={items} sizeMax={size} />);
+ render(
+ <Grid sizeMax={size}>
+ {items.map((item) => (
+ <GridItem key={item.id}>{item.contents}</GridItem>
+ ))}
+ </Grid>
+ );
expect(rtlScreen.getByRole('list')).toHaveStyle({ '--size-max': size });
});
@@ -46,7 +71,13 @@ describe('Grid', () => {
it('can render a list of items with a custom gap', () => {
const gap = 'md';
- render(<Grid items={items} gap={gap} />);
+ render(
+ <Grid gap={gap}>
+ {items.map((item) => (
+ <GridItem key={item.id}>{item.contents}</GridItem>
+ ))}
+ </Grid>
+ );
expect(rtlScreen.getByRole('list')).toHaveStyle({
'--gap': `var(--spacing-${gap})`,
@@ -56,13 +87,25 @@ describe('Grid', () => {
it('can render a list of items with an explicit number of columns', () => {
const col = 4;
- render(<Grid col={col} items={items} />);
+ render(
+ <Grid col={col}>
+ {items.map((item) => (
+ <GridItem key={item.id}>{item.contents}</GridItem>
+ ))}
+ </Grid>
+ );
expect(rtlScreen.getByRole('list')).toHaveStyle(`--col: ${col}`);
});
it('can render a centered list of items', () => {
- render(<Grid isCentered items={items} />);
+ render(
+ <Grid isCentered>
+ {items.map((item) => (
+ <GridItem key={item.id}>{item.contents}</GridItem>
+ ))}
+ </Grid>
+ );
expect(rtlScreen.getByRole('list')).toHaveClass('wrapper--is-centered');
});
diff --git a/src/components/molecules/grid/grid.tsx b/src/components/molecules/grid/grid.tsx
index ca920f8..3d0ecf1 100644
--- a/src/components/molecules/grid/grid.tsx
+++ b/src/components/molecules/grid/grid.tsx
@@ -5,19 +5,18 @@ import {
type CSSProperties,
} from 'react';
import type { Spacing } from '../../../types';
-import { List, ListItem, type ListProps } from '../../atoms';
+import { List, type ListProps } from '../../atoms';
import styles from './grid.module.scss';
-export type GridItem = {
- id: string;
- item: ReactNode;
-};
-
export type GridProps<T extends boolean> = Omit<
ListProps<T, false>,
'children' | 'hideMarker' | 'isHierarchical' | 'isInline' | 'spacing'
> & {
/**
+ * The grid items.
+ */
+ children: ReactNode;
+ /**
* Control the number of column.
*
* @default 'auto-fit'
@@ -36,10 +35,6 @@ export type GridProps<T extends boolean> = Omit<
*/
isCentered?: boolean;
/**
- * The grid items.
- */
- items: GridItem[];
- /**
* Define a fixed size for each item.
*
* You should either use `size` or `sizeMax`/`sizeMin` not both.
@@ -67,11 +62,11 @@ export type GridProps<T extends boolean> = Omit<
const GridWithRef = <T extends boolean>(
{
+ children,
className = '',
col = 'auto-fit',
gap,
isCentered = false,
- items,
size,
sizeMax,
sizeMin,
@@ -104,11 +99,7 @@ const GridWithRef = <T extends boolean>(
ref={ref}
style={gridStyles}
>
- {items.map(({ id, item }) => (
- <ListItem className={styles.item} key={id}>
- {item}
- </ListItem>
- ))}
+ {children}
</List>
);
};
diff --git a/src/components/molecules/grid/index.ts b/src/components/molecules/grid/index.ts
index d24d1bd..d657dcb 100644
--- a/src/components/molecules/grid/index.ts
+++ b/src/components/molecules/grid/index.ts
@@ -1 +1,2 @@
export * from './grid';
+export * from './grid-item';