Skip to content

Commit

Permalink
feat(DefinitionList): add mobile view (#205)
Browse files Browse the repository at this point in the history
  • Loading branch information
Raubzeug authored Jul 10, 2024
1 parent 913c38e commit b94ee82
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 31 deletions.
19 changes: 19 additions & 0 deletions src/components/DefinitionList/DefinitionList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,22 @@ $block: '.#{variables.$ns}definition-list';
}
}
}

#{$block}_vertical {
#{$block}__term-container {
flex: 1 0 auto;
}
#{$block}__item {
flex-direction: column;
gap: var(--g-spacing-half);
}
#{$block}__item + #{$block}__item {
margin-block-start: var(--g-spacing-3);
}
#{$block}__title:not(:first-of-type) {
margin-block-start: var(--g-spacing-8);
}
#{$block}__item:is(#{$block}__item_grouped) + #{$block}__item:not(#{$block}__item_grouped) {
margin-block-start: var(--g-spacing-8);
}
}
28 changes: 14 additions & 14 deletions src/components/DefinitionList/DefinitionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,39 @@ import {Definition} from './components/Definition';
import {GroupLabel} from './components/GroupLabel';
import {Term} from './components/Term';
import {DefinitionListProps} from './types';
import {b, getFlattenItems, getTitle, isGroup, isUnbreakableOver} from './utils';
import {
b,
getFlattenItems,
getKeyStyles,
getTitle,
getValueStyles,
isGroup,
isUnbreakableOver,
} from './utils';

import './DefinitionList.scss';

export function DefinitionList({
items,
responsive,
direction = 'horizontal',
nameMaxWidth,
contentMaxWidth = 'auto',
className,
itemClassName,
copyPosition = 'outside',
qa,
}: DefinitionListProps) {
const keyStyle = nameMaxWidth
? {
flexBasis: nameMaxWidth,
}
: {};
const keyStyle = getKeyStyles({nameMaxWidth, direction});

const valueStyle =
typeof contentMaxWidth === 'number'
? {
flexBasis: contentMaxWidth,
maxWidth: contentMaxWidth,
}
: {};
const valueStyle = getValueStyles({contentMaxWidth, direction});

const normalizedItems = React.useMemo(() => {
return getFlattenItems(items).map((value, index) => ({...value, key: index}));
}, [items]);

return (
<dl className={b({responsive}, className)} data-qa={qa}>
<dl className={b({responsive, vertical: direction === 'vertical'}, className)} data-qa={qa}>
{normalizedItems.map((item) => {
if (isGroup(item)) {
const {key, label} = item;
Expand All @@ -62,6 +61,7 @@ export function DefinitionList({
style={keyStyle}
>
<Term
direction={direction}
name={name}
nameTitle={nameTitle}
note={note}
Expand Down
19 changes: 10 additions & 9 deletions src/components/DefinitionList/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ The component to display definition list with term and definition separated by d

### PropTypes

| Property | Type | Required | Default | Description |
| :-------------- | :---------------------- | :-------: | :------ | :----------------------------------------------------------- |
| [items](#items) | `DefinitionListItem[]` | yes | | Items of the list |
| responsive | `boolean` | | | If set to `true` list will take 100% width of its parent |
| nameMaxWidth | `number` | | | Maximum width of term |
| contentMaxWidth | `number \| 'auto'` | | 'auto' | Maximum width of definition |
| className | `string` | | | Class name for the list container |
| itemClassName | `string` | | | Class name for the list item |
| copyPosition | `'inside' \| 'outside'` | 'outside' | | If set to `inside`, copy icon will be placed over definition |
| Property | Type | Required | Default | Description |
| :-------------- | :----------------------------- | :-------: | :----------- | :-------------------------------------------------------------------------------------------------- |
| [items](#items) | `DefinitionListItem[]` | yes | | Items of the list |
| responsive | `boolean` | | | If set to `true` list will take 100% width of its parent |
| direction | `'horizontal'` \| `'vertical'` | | 'horizontal' | If set to `vertical` content will be located under name and list will take 100% width of its parent |
| nameMaxWidth | `number` | | | Maximum width of term |
| contentMaxWidth | `number \| 'auto'` | | 'auto' | Maximum width of definition |
| className | `string` | | | Class name for the list container |
| itemClassName | `string` | | | Class name for the list item |
| copyPosition | `'inside' \| 'outside'` | 'outside' | | If set to `inside`, copy icon will be placed over definition |

#### Items

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,11 @@ export const ListWithIconInside = TemplateWithIconInside.bind({});

const groupedItems = [
{
label: 'Compute',
label: 'Group 1',
items: [{name: 'Link', content: 'value'}],
},
{
label: 'VPC',
label: 'Group 2',
items: [
{name: 'Number value', content: 2},
{name: 'Node value', content: <strong>value</strong>},
Expand All @@ -181,7 +181,27 @@ const groupedItems = [
{name: 'Simple value', content: 2},
{name: 'Something else', content: <strong>value</strong>},
{name: 'Foo bar', content: 'value'},
{label: 'Test', items: [{name: 'Node value', content: <strong>value</strong>}]},
{
label: 'Group 3',
items: [
{
name: 'String long value with copy',
content:
'The HTML <dl> element represents a description list. The element encloses a list of groups of terms (specified using the <dt> element) and descriptions (provided by <dd> elements). Common uses for this element are to implement a glossary or to display metadata (a list of key-value pairs)',
copyText:
'The HTML <dl> element represents a description list. The element encloses a list of groups of terms (specified using the <dt> element) and descriptions (provided by <dd> elements). Common uses for this element are to implement a glossary or to display metadata (a list of key-value pairs)',
},
{
name: 'String long looooooooooooooong looooooooooooooong looooooooooooooong looooooooooooooong value',
multilineName: true,
note: 'This is multiline value',
content:
'https://example.com/long-long/like/beyond/the/farthest/lands/long/path/to/handle?and=some&list=of&query=parameters&that=is&overcomplicated=maybe&with=some&token=inside&not=really&readable=but&sometimes=useful',
copyText:
'https://example.com/long-long/like/beyond/the/farthest/lands/long/path/to/handle?and=some&list=of&query=parameters&that=is&overcomplicated=maybe&with=some&token=inside&not=really&readable=but&sometimes=useful',
},
],
},
];

export const GroupedItems = DefaultTemplate.bind({});
Expand All @@ -190,3 +210,14 @@ GroupedItems.args = {
responsive: false,
contentMaxWidth: 480,
};

const TemplateVertical: StoryFn<DefinitionListProps> = (args) => {
return <DefinitionList {...args} />;
};
export const VerticalList = TemplateVertical.bind({});
VerticalList.args = {
items: groupedItems,
direction: 'vertical',
contentMaxWidth: 'auto',
copyPosition: 'inside',
};
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,9 @@ describe('components: DefinitionList', () => {
expect(component).toBeVisible();
expect(component).toHaveClass(b('definition'));
});
it('should render vertical view', () => {
getComponent({direction: 'vertical'});
const component = screen.getByTestId(qaAttribute);
expect(component).toHaveClass(b({vertical: true}));
});
});
12 changes: 8 additions & 4 deletions src/components/DefinitionList/components/Term.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';

import {HelpPopover} from '../../HelpPopover';
import {DefinitionListItemNote, DefinitionListSingleItem} from '../types';
import {DefinitionListDirection, DefinitionListItemNote, DefinitionListSingleItem} from '../types';
import {b, getTitle} from '../utils';

interface NoteElementsProps {
Expand Down Expand Up @@ -30,9 +30,11 @@ function NoteElement({note}: NoteElementsProps) {
}

export interface TermProps
extends Pick<DefinitionListSingleItem, 'note' | 'name' | 'nameTitle' | 'multilineName'> {}
extends Pick<DefinitionListSingleItem, 'note' | 'name' | 'nameTitle' | 'multilineName'> {
direction?: DefinitionListDirection;
}

export function Term({note, name, nameTitle, multilineName}: TermProps) {
export function Term({note, name, nameTitle, multilineName, direction}: TermProps) {
const noteElement = (
<React.Fragment>
&nbsp;
Expand All @@ -46,7 +48,9 @@ export function Term({note, name, nameTitle, multilineName}: TermProps) {
{multilineName && noteElement}
</div>
{!multilineName && noteElement}
<div className={b('dots', {'with-note': Boolean(note)})} />
{direction === 'horizontal' && (
<div className={b('dots', {'with-note': Boolean(note)})} />
)}
</React.Fragment>
);
}
2 changes: 1 addition & 1 deletion src/components/DefinitionList/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {DefinitionList} from './DefinitionList';
export type {DefinitionListProps, DefinitionListItem} from './types';
export type {DefinitionListProps, DefinitionListItem, DefinitionListSingleItem} from './types';
3 changes: 3 additions & 0 deletions src/components/DefinitionList/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ export interface DefinitionListItemGrouped extends DefinitionListSingleItem {

export type DefinitionListItem = DefinitionListSingleItem | DefinitionListGroup;

export type DefinitionListDirection = 'vertical' | 'horizontal';

export interface DefinitionListProps extends QAProps {
items: DefinitionListItem[];
copyPosition?: 'inside' | 'outside';
responsive?: boolean;
direction?: DefinitionListDirection;
nameMaxWidth?: number;
contentMaxWidth?: number | 'auto';
className?: string;
Expand Down
27 changes: 27 additions & 0 deletions src/components/DefinitionList/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
DefinitionListGroup,
DefinitionListItem,
DefinitionListItemGrouped,
DefinitionListProps,
DefinitionListSingleItem,
} from './types';

Expand Down Expand Up @@ -48,3 +49,29 @@ export function getTitle(title?: string, content?: React.ReactNode) {

return undefined;
}

export function getKeyStyles({
nameMaxWidth,
direction,
}: Pick<DefinitionListProps, 'nameMaxWidth' | 'direction'>) {
if (!nameMaxWidth) {
return {};
}
if (direction === 'vertical') {
return {maxWidth: nameMaxWidth};
}
return {flexBasis: nameMaxWidth};
}

export function getValueStyles({
contentMaxWidth,
direction,
}: Pick<DefinitionListProps, 'contentMaxWidth' | 'direction'>) {
if (!(typeof contentMaxWidth === 'number')) {
return {};
}
if (direction === 'vertical') {
return {maxWidth: contentMaxWidth};
}
return {flexBasis: contentMaxWidth, maxWidth: contentMaxWidth};
}

0 comments on commit b94ee82

Please sign in to comment.