diff options
Diffstat (limited to 'src/components')
4 files changed, 177 insertions, 0 deletions
| 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<typeof DescriptionListComponent>; + +const Template: ComponentStory<typeof DescriptionListComponent> = (args) => ( +  <DescriptionListComponent {...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(<DescriptionList items={items} />); +    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<DescriptionListProps> = ({ 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 ( +        <div key={id} className={styles.list__item}> +          <dt className={styles.list__term}>{term}</dt> +          {value.map((currentValue, index) => ( +            <dd key={`${id}-${index}`} className={styles.list__description}> +              {currentValue} +            </dd> +          ))} +        </div> +      ); +    }); +  }; + +  return <dl className={`${styles.list} ${classes}`}>{getItems(items)}</dl>; +}; + +export default DescriptionList; | 
