From a208a8f314f697dbd6f85f8be8332bcea0204178 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 29 Apr 2022 18:49:38 +0200 Subject: chore: add a Columns component --- .../molecules/layout/columns.module.scss | 30 ++++++ .../molecules/layout/columns.stories.tsx | 108 +++++++++++++++++++++ src/components/molecules/layout/columns.test.tsx | 48 +++++++++ src/components/molecules/layout/columns.tsx | 49 ++++++++++ 4 files changed, 235 insertions(+) create mode 100644 src/components/molecules/layout/columns.module.scss create mode 100644 src/components/molecules/layout/columns.stories.tsx create mode 100644 src/components/molecules/layout/columns.test.tsx create mode 100644 src/components/molecules/layout/columns.tsx (limited to 'src') diff --git a/src/components/molecules/layout/columns.module.scss b/src/components/molecules/layout/columns.module.scss new file mode 100644 index 0000000..b449c45 --- /dev/null +++ b/src/components/molecules/layout/columns.module.scss @@ -0,0 +1,30 @@ +@use "@styles/abstracts/mixins" as mix; + +.wrapper { + display: grid; + gap: var(--spacing-md); + + &--responsive#{&} { + @for $i from 2 through 4 { + &--#{$i}-columns { + @include mix.media("screen") { + @include mix.dimensions("sm") { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + @include mix.dimensions("md") { + grid-template-columns: repeat($i, minmax(0, 1fr)); + } + } + } + } + } + + &--no-responsive#{&} { + @for $i from 2 through 4 { + &--#{$i}-columns { + grid-template-columns: repeat($i, minmax(0, 1fr)); + } + } + } +} diff --git a/src/components/molecules/layout/columns.stories.tsx b/src/components/molecules/layout/columns.stories.tsx new file mode 100644 index 0000000..2022fa4 --- /dev/null +++ b/src/components/molecules/layout/columns.stories.tsx @@ -0,0 +1,108 @@ +import Column from '@components/atoms/layout/column'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import Columns from './columns'; + +export default { + title: 'Molecules/Layout/Columns', + args: { + responsive: true, + }, + component: Columns, + argTypes: { + children: { + description: 'The columns.', + type: { + name: 'function', + required: true, + }, + }, + className: { + control: { + type: 'text', + }, + description: 'Set additional classnames to the columns wrapper.', + table: { + category: 'Styles', + }, + type: { + name: 'string', + required: false, + }, + }, + count: { + control: { + type: 'number', + min: 2, + max: 4, + }, + description: 'The number of columns.', + type: { + name: 'number', + required: true, + }, + }, + responsive: { + control: { + type: 'boolean', + }, + description: 'Should the columns be stacked on small devices?', + table: { + category: 'Options', + defaultValue: { summary: true }, + }, + type: { + name: 'boolean', + required: false, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +const column1 = + 'Non praesentium voluptas quisquam ex est. Distinctio accusamus facilis libero in aut. Et veritatis quo impedit fugit amet sit accusantium. Ut est rerum asperiores sint libero eveniet. Molestias placeat recusandae suscipit eligendi sunt hic.'; + +const column2 = + 'Occaecati consectetur ad similique itaque rem doloremque commodi voluptate porro. Nam quo voluptas commodi qui rerum qui. Explicabo quis adipisci rerum. Culpa alias laboriosam temporibus iusto harum at placeat.'; + +const column3 = + 'Libero aut ab neque voluptatem commodi. Quam quia voluptatem iusto dolorum. Enim ipsa totam corrupti qui cum quidem ea. Eos sed aliquam porro consequatur officia sed.'; + +const column4 = + 'Ratione placeat ea ea. Explicabo rem eaque voluptatibus. Nihil nulla culpa et dolor numquam omnis est. Quis quas excepturi est dignissimos ducimus et ad quis quis. Eos enim et nam delectus.'; + +export const TwoColumns = Template.bind({}); +TwoColumns.args = { + children: [ + {column1}, + {column2}, + {column3}, + {column4}, + ], + count: 2, +}; + +export const ThreeColumns = Template.bind({}); +ThreeColumns.args = { + children: [ + {column1}, + {column2}, + {column3}, + {column4}, + ], + count: 3, +}; + +export const FourColumns = Template.bind({}); +FourColumns.args = { + children: [ + {column1}, + {column2}, + {column3}, + {column4}, + ], + count: 4, +}; diff --git a/src/components/molecules/layout/columns.test.tsx b/src/components/molecules/layout/columns.test.tsx new file mode 100644 index 0000000..4b55bbb --- /dev/null +++ b/src/components/molecules/layout/columns.test.tsx @@ -0,0 +1,48 @@ +import Column from '@components/atoms/layout/column'; +import { render, screen } from '@test-utils'; +import Columns from './columns'; + +const column1 = + 'Non praesentium voluptas quisquam ex est. Distinctio accusamus facilis libero in aut. Et veritatis quo impedit fugit amet sit accusantium. Ut est rerum asperiores sint libero eveniet. Molestias placeat recusandae suscipit eligendi sunt hic.'; + +const column2 = + 'Occaecati consectetur ad similique itaque rem doloremque commodi voluptate porro. Nam quo voluptas commodi qui rerum qui. Explicabo quis adipisci rerum. Culpa alias laboriosam temporibus iusto harum at placeat.'; + +const column3 = + 'Libero aut ab neque voluptatem commodi. Quam quia voluptatem iusto dolorum. Enim ipsa totam corrupti qui cum quidem ea. Eos sed aliquam porro consequatur officia sed.'; + +const column4 = + 'Ratione placeat ea ea. Explicabo rem eaque voluptatibus. Nihil nulla culpa et dolor numquam omnis est. Quis quas excepturi est dignissimos ducimus et ad quis quis. Eos enim et nam delectus.'; + +describe('Columns', () => { + it('renders all the children', () => { + render( + + {column1} + {column2} + {column3} + {column4} + + ); + + expect(screen.getByText(column1)).toBeInTheDocument(); + expect(screen.getByText(column2)).toBeInTheDocument(); + expect(screen.getByText(column3)).toBeInTheDocument(); + expect(screen.getByText(column4)).toBeInTheDocument(); + }); + + it('renders the right number of columns', () => { + render( + + {column1} + {column2} + {column3} + {column4} + + ); + + const container = screen.getByText(column1).parentElement; + + expect(container).toHaveClass('wrapper--3-columns'); + }); +}); diff --git a/src/components/molecules/layout/columns.tsx b/src/components/molecules/layout/columns.tsx new file mode 100644 index 0000000..c196457 --- /dev/null +++ b/src/components/molecules/layout/columns.tsx @@ -0,0 +1,49 @@ +import Column from '@components/atoms/layout/column'; +import { FC, ReactComponentElement } from 'react'; +import styles from './columns.module.scss'; + +export type ColumnsProps = { + /** + * The columns. + */ + children: ReactComponentElement[]; + /** + * Set additional classnames to the columns wrapper. + */ + className?: string; + /** + * The number of columns. + */ + count: 2 | 3 | 4; + /** + * Should the columns be stacked on small devices? Default: true. + */ + responsive?: boolean; +}; + +/** + * Columns component. + * + * Render some Column components as columns. + */ +const Columns: FC = ({ + children, + className = '', + count, + responsive = true, +}) => { + const countClass = `wrapper--${count}-columns`; + const responsiveClass = responsive + ? `wrapper--responsive` + : 'wrapper--no-responsive'; + + return ( +
+ {children} +
+ ); +}; + +export default Columns; -- cgit v1.2.3