From de9264702de99d2c209f762393d5c82f4546abb5 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Wed, 3 Jul 2024 12:40:12 +0300 Subject: [PATCH 1/2] feat(DefinitionList): add mobile view --- .../DefinitionList/DefinitionList.scss | 19 ++++++++++ .../DefinitionList/DefinitionList.tsx | 28 +++++++------- src/components/DefinitionList/README.md | 1 + .../__stories__/DefinitionList.stories.tsx | 37 +++++++++++++++++-- .../__tests__/DefinitionList.test.tsx | 5 +++ .../DefinitionList/components/Term.tsx | 8 ++-- src/components/DefinitionList/index.ts | 2 +- src/components/DefinitionList/types.ts | 1 + src/components/DefinitionList/utils.ts | 27 ++++++++++++++ 9 files changed, 107 insertions(+), 21 deletions(-) diff --git a/src/components/DefinitionList/DefinitionList.scss b/src/components/DefinitionList/DefinitionList.scss index 482fa58f..15d4a14c 100644 --- a/src/components/DefinitionList/DefinitionList.scss +++ b/src/components/DefinitionList/DefinitionList.scss @@ -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); + } +} diff --git a/src/components/DefinitionList/DefinitionList.tsx b/src/components/DefinitionList/DefinitionList.tsx index 3f2c41ec..de350f93 100644 --- a/src/components/DefinitionList/DefinitionList.tsx +++ b/src/components/DefinitionList/DefinitionList.tsx @@ -4,13 +4,22 @@ 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, + vertical, nameMaxWidth, contentMaxWidth = 'auto', className, @@ -18,26 +27,16 @@ export function DefinitionList({ copyPosition = 'outside', qa, }: DefinitionListProps) { - const keyStyle = nameMaxWidth - ? { - flexBasis: nameMaxWidth, - } - : {}; + const keyStyle = getKeyStyles({nameMaxWidth, vertical}); - const valueStyle = - typeof contentMaxWidth === 'number' - ? { - flexBasis: contentMaxWidth, - maxWidth: contentMaxWidth, - } - : {}; + const valueStyle = getValueStyles({contentMaxWidth, vertical}); const normalizedItems = React.useMemo(() => { return getFlattenItems(items).map((value, index) => ({...value, key: index})); }, [items]); return ( -
+
{normalizedItems.map((item) => { if (isGroup(item)) { const {key, label} = item; @@ -62,6 +61,7 @@ export function DefinitionList({ style={keyStyle} > value}, @@ -181,7 +181,27 @@ const groupedItems = [ {name: 'Simple value', content: 2}, {name: 'Something else', content: value}, {name: 'Foo bar', content: 'value'}, - {label: 'Test', items: [{name: 'Node value', content: value}]}, + { + label: 'Group 3', + items: [ + { + name: 'String long value with copy', + content: + 'The HTML
element represents a description list. The element encloses a list of groups of terms (specified using the
element) and descriptions (provided by
elements). Common uses for this element are to implement a glossary or to display metadata (a list of key-value pairs)', + copyText: + 'The HTML
element represents a description list. The element encloses a list of groups of terms (specified using the
element) and descriptions (provided by
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¬=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¬=really&readable=but&sometimes=useful', + }, + ], + }, ]; export const GroupedItems = DefaultTemplate.bind({}); @@ -190,3 +210,14 @@ GroupedItems.args = { responsive: false, contentMaxWidth: 480, }; + +const TemplateVertical: StoryFn = (args) => { + return ; +}; +export const VerticalList = TemplateVertical.bind({}); +VerticalList.args = { + items: groupedItems, + vertical: true, + contentMaxWidth: 'auto', + copyPosition: 'inside', +}; diff --git a/src/components/DefinitionList/__tests__/DefinitionList.test.tsx b/src/components/DefinitionList/__tests__/DefinitionList.test.tsx index 72c7b640..68d5a903 100644 --- a/src/components/DefinitionList/__tests__/DefinitionList.test.tsx +++ b/src/components/DefinitionList/__tests__/DefinitionList.test.tsx @@ -95,4 +95,9 @@ describe('components: DefinitionList', () => { expect(component).toBeVisible(); expect(component).toHaveClass(b('definition')); }); + it('should render vertical view', () => { + getComponent({vertical: true}); + const component = screen.getByTestId(qaAttribute); + expect(component).toHaveClass(b({vertical: true})); + }); }); diff --git a/src/components/DefinitionList/components/Term.tsx b/src/components/DefinitionList/components/Term.tsx index 7e3ccbd9..97e270bc 100644 --- a/src/components/DefinitionList/components/Term.tsx +++ b/src/components/DefinitionList/components/Term.tsx @@ -30,9 +30,11 @@ function NoteElement({note}: NoteElementsProps) { } export interface TermProps - extends Pick {} + extends Pick { + vertical?: boolean; +} -export function Term({note, name, nameTitle, multilineName}: TermProps) { +export function Term({note, name, nameTitle, multilineName, vertical}: TermProps) { const noteElement = (   @@ -46,7 +48,7 @@ export function Term({note, name, nameTitle, multilineName}: TermProps) { {multilineName && noteElement} {!multilineName && noteElement} -
+ {!vertical &&
} ); } diff --git a/src/components/DefinitionList/index.ts b/src/components/DefinitionList/index.ts index cfe7f5f0..3b199e51 100644 --- a/src/components/DefinitionList/index.ts +++ b/src/components/DefinitionList/index.ts @@ -1,2 +1,2 @@ export {DefinitionList} from './DefinitionList'; -export type {DefinitionListProps, DefinitionListItem} from './types'; +export type {DefinitionListProps, DefinitionListItem, DefinitionListSingleItem} from './types'; diff --git a/src/components/DefinitionList/types.ts b/src/components/DefinitionList/types.ts index 4238a13c..3889a800 100644 --- a/src/components/DefinitionList/types.ts +++ b/src/components/DefinitionList/types.ts @@ -30,6 +30,7 @@ export interface DefinitionListProps extends QAProps { items: DefinitionListItem[]; copyPosition?: 'inside' | 'outside'; responsive?: boolean; + vertical?: boolean; nameMaxWidth?: number; contentMaxWidth?: number | 'auto'; className?: string; diff --git a/src/components/DefinitionList/utils.ts b/src/components/DefinitionList/utils.ts index d209f14f..6d205e59 100644 --- a/src/components/DefinitionList/utils.ts +++ b/src/components/DefinitionList/utils.ts @@ -6,6 +6,7 @@ import type { DefinitionListGroup, DefinitionListItem, DefinitionListItemGrouped, + DefinitionListProps, DefinitionListSingleItem, } from './types'; @@ -48,3 +49,29 @@ export function getTitle(title?: string, content?: React.ReactNode) { return undefined; } + +export function getKeyStyles({ + nameMaxWidth, + vertical, +}: Pick) { + if (!nameMaxWidth) { + return {}; + } + if (vertical) { + return {maxWidth: nameMaxWidth}; + } + return {flexBasis: nameMaxWidth}; +} + +export function getValueStyles({ + contentMaxWidth, + vertical, +}: Pick) { + if (!(typeof contentMaxWidth === 'number')) { + return {}; + } + if (vertical) { + return {maxWidth: contentMaxWidth}; + } + return {flexBasis: contentMaxWidth, maxWidth: contentMaxWidth}; +} From ad36bd3aba7ad87cd02cf77f1f9ac0515a771fd0 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Tue, 9 Jul 2024 12:32:01 +0300 Subject: [PATCH 2/2] fix: code-review --- .../DefinitionList/DefinitionList.tsx | 10 +++++----- src/components/DefinitionList/README.md | 20 +++++++++---------- .../__stories__/DefinitionList.stories.tsx | 2 +- .../__tests__/DefinitionList.test.tsx | 2 +- .../DefinitionList/components/Term.tsx | 10 ++++++---- src/components/DefinitionList/types.ts | 4 +++- src/components/DefinitionList/utils.ts | 12 +++++------ 7 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/components/DefinitionList/DefinitionList.tsx b/src/components/DefinitionList/DefinitionList.tsx index de350f93..f04dfe86 100644 --- a/src/components/DefinitionList/DefinitionList.tsx +++ b/src/components/DefinitionList/DefinitionList.tsx @@ -19,7 +19,7 @@ import './DefinitionList.scss'; export function DefinitionList({ items, responsive, - vertical, + direction = 'horizontal', nameMaxWidth, contentMaxWidth = 'auto', className, @@ -27,16 +27,16 @@ export function DefinitionList({ copyPosition = 'outside', qa, }: DefinitionListProps) { - const keyStyle = getKeyStyles({nameMaxWidth, vertical}); + const keyStyle = getKeyStyles({nameMaxWidth, direction}); - const valueStyle = getValueStyles({contentMaxWidth, vertical}); + const valueStyle = getValueStyles({contentMaxWidth, direction}); const normalizedItems = React.useMemo(() => { return getFlattenItems(items).map((value, index) => ({...value, key: index})); }, [items]); return ( -
+
{normalizedItems.map((item) => { if (isGroup(item)) { const {key, label} = item; @@ -61,7 +61,7 @@ export function DefinitionList({ style={keyStyle} > = (args) => { export const VerticalList = TemplateVertical.bind({}); VerticalList.args = { items: groupedItems, - vertical: true, + direction: 'vertical', contentMaxWidth: 'auto', copyPosition: 'inside', }; diff --git a/src/components/DefinitionList/__tests__/DefinitionList.test.tsx b/src/components/DefinitionList/__tests__/DefinitionList.test.tsx index 68d5a903..3299326b 100644 --- a/src/components/DefinitionList/__tests__/DefinitionList.test.tsx +++ b/src/components/DefinitionList/__tests__/DefinitionList.test.tsx @@ -96,7 +96,7 @@ describe('components: DefinitionList', () => { expect(component).toHaveClass(b('definition')); }); it('should render vertical view', () => { - getComponent({vertical: true}); + getComponent({direction: 'vertical'}); const component = screen.getByTestId(qaAttribute); expect(component).toHaveClass(b({vertical: true})); }); diff --git a/src/components/DefinitionList/components/Term.tsx b/src/components/DefinitionList/components/Term.tsx index 97e270bc..34c35df7 100644 --- a/src/components/DefinitionList/components/Term.tsx +++ b/src/components/DefinitionList/components/Term.tsx @@ -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 { @@ -31,10 +31,10 @@ function NoteElement({note}: NoteElementsProps) { export interface TermProps extends Pick { - vertical?: boolean; + direction?: DefinitionListDirection; } -export function Term({note, name, nameTitle, multilineName, vertical}: TermProps) { +export function Term({note, name, nameTitle, multilineName, direction}: TermProps) { const noteElement = (   @@ -48,7 +48,9 @@ export function Term({note, name, nameTitle, multilineName, vertical}: TermProps {multilineName && noteElement}
{!multilineName && noteElement} - {!vertical &&
} + {direction === 'horizontal' && ( +
+ )} ); } diff --git a/src/components/DefinitionList/types.ts b/src/components/DefinitionList/types.ts index 3889a800..cd55a30c 100644 --- a/src/components/DefinitionList/types.ts +++ b/src/components/DefinitionList/types.ts @@ -26,11 +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; - vertical?: boolean; + direction?: DefinitionListDirection; nameMaxWidth?: number; contentMaxWidth?: number | 'auto'; className?: string; diff --git a/src/components/DefinitionList/utils.ts b/src/components/DefinitionList/utils.ts index 6d205e59..62eb2f60 100644 --- a/src/components/DefinitionList/utils.ts +++ b/src/components/DefinitionList/utils.ts @@ -52,12 +52,12 @@ export function getTitle(title?: string, content?: React.ReactNode) { export function getKeyStyles({ nameMaxWidth, - vertical, -}: Pick) { + direction, +}: Pick) { if (!nameMaxWidth) { return {}; } - if (vertical) { + if (direction === 'vertical') { return {maxWidth: nameMaxWidth}; } return {flexBasis: nameMaxWidth}; @@ -65,12 +65,12 @@ export function getKeyStyles({ export function getValueStyles({ contentMaxWidth, - vertical, -}: Pick) { + direction, +}: Pick) { if (!(typeof contentMaxWidth === 'number')) { return {}; } - if (vertical) { + if (direction === 'vertical') { return {maxWidth: contentMaxWidth}; } return {flexBasis: contentMaxWidth, maxWidth: contentMaxWidth};