From 06396f8e942c58254ee4e87f610d3e33197e0d73 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 7 Apr 2022 19:00:13 +0200 Subject: chore: add a DescriptionList component --- .../atoms/lists/description-list.module.scss | 42 +++++++++++++++ .../atoms/lists/description-list.stories.tsx | 55 ++++++++++++++++++++ .../atoms/lists/description-list.test.tsx | 20 ++++++++ src/components/atoms/lists/description-list.tsx | 60 ++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 src/components/atoms/lists/description-list.module.scss create mode 100644 src/components/atoms/lists/description-list.stories.tsx create mode 100644 src/components/atoms/lists/description-list.test.tsx create mode 100644 src/components/atoms/lists/description-list.tsx (limited to 'src/components/atoms/lists') diff --git a/src/components/atoms/lists/description-list.module.scss b/src/components/atoms/lists/description-list.module.scss new file mode 100644 index 0000000..4758816 --- /dev/null +++ b/src/components/atoms/lists/description-list.module.scss @@ -0,0 +1,42 @@ +@use "@styles/abstracts/mixins" as mix; + +.list { + display: flex; + flex-flow: column wrap; + gap: var(--spacing-2xs); + margin: 0; + + &__item { + display: flex; + flex-flow: column wrap; + gap: var(--spacing-2xs); + + @include mix.media("screen") { + @include mix.dimensions("sm") { + flex-flow: row wrap; + } + } + } + + &__term { + flex: 0 0 max-content; + color: var(--color-fg-light); + font-weight: 600; + } + + &__description { + flex: 0 0 auto; + margin: 0; + + @include mix.media("screen") { + @include mix.dimensions("sm") { + &:not(:first-of-type) { + &::before { + content: "/"; + margin: 0 var(--spacing-2xs); + } + } + } + } + } +} diff --git a/src/components/atoms/lists/description-list.stories.tsx b/src/components/atoms/lists/description-list.stories.tsx new file mode 100644 index 0000000..e9a60cf --- /dev/null +++ b/src/components/atoms/lists/description-list.stories.tsx @@ -0,0 +1,55 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import DescriptionListComponent, { + DescriptionListItem, +} from './description-list'; + +export default { + title: 'Atoms/Lists', + component: DescriptionListComponent, + argTypes: { + classes: { + control: { + type: 'text', + }, + description: 'Set additional classes to the list wrapper.', + table: { + category: 'Options', + }, + type: { + name: 'string', + required: false, + }, + }, + items: { + control: { + type: null, + }, + description: 'The list items.', + type: { + name: 'object', + required: true, + value: {}, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +const items: DescriptionListItem[] = [ + { id: 'term-1', term: 'Term 1:', value: ['Value for term 1'] }, + { id: 'term-2', term: 'Term 2:', value: ['Value for term 2'] }, + { + id: 'term-3', + term: 'Term 3:', + value: ['Value 1 for term 3', 'Value 2 for term 3', 'Value 3 for term 3'], + }, + { id: 'term-4', term: 'Term 4:', value: ['Value for term 4'] }, +]; + +export const DescriptionList = Template.bind({}); +DescriptionList.args = { + items, +}; diff --git a/src/components/atoms/lists/description-list.test.tsx b/src/components/atoms/lists/description-list.test.tsx new file mode 100644 index 0000000..d3f7045 --- /dev/null +++ b/src/components/atoms/lists/description-list.test.tsx @@ -0,0 +1,20 @@ +import { render } from '@test-utils'; +import DescriptionList, { DescriptionListItem } from './description-list'; + +const items: DescriptionListItem[] = [ + { id: 'term-1', term: 'Term 1:', value: ['Value for term 1'] }, + { id: 'term-2', term: 'Term 2:', value: ['Value for term 2'] }, + { + id: 'term-3', + term: 'Term 3:', + value: ['Value 1 for term 3', 'Value 2 for term 3', 'Value 3 for term 3'], + }, + { id: 'term-4', term: 'Term 4:', value: ['Value for term 4'] }, +]; + +describe('DescriptionList', () => { + it('renders a list of terms and description', () => { + const { container } = render(); + expect(container).toBeDefined(); + }); +}); diff --git a/src/components/atoms/lists/description-list.tsx b/src/components/atoms/lists/description-list.tsx new file mode 100644 index 0000000..df2880f --- /dev/null +++ b/src/components/atoms/lists/description-list.tsx @@ -0,0 +1,60 @@ +import { FC } from 'react'; +import styles from './description-list.module.scss'; + +export type DescriptionListItem = { + /** + * The item id. + */ + id: string; + /** + * A list term. + */ + term: string; + /** + * An array of values for the list term. + */ + value: any[]; +}; + +export type DescriptionListProps = { + /** + * Set additional classes to the list wrapper. + */ + classes?: string; + /** + * The list items. + */ + items: DescriptionListItem[]; +}; + +/** + * DescriptionList component + * + * Render a description list. + */ +const DescriptionList: FC = ({ classes = '', items }) => { + /** + * Retrieve the description list items wrapped in a div element. + * + * @param {DescriptionListItem[]} listItems - An array of term and description couples. + * @returns {JSX.Element[]} The description list items. + */ + const getItems = (listItems: DescriptionListItem[]): JSX.Element[] => { + return listItems.map(({ id, term, value }) => { + return ( +
+
{term}
+ {value.map((currentValue, index) => ( +
+ {currentValue} +
+ ))} +
+ ); + }); + }; + + return
{getItems(items)}
; +}; + +export default DescriptionList; -- cgit v1.2.3