diff options
| author | Armand Philippot <git@armandphilippot.com> | 2023-10-06 17:48:03 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2023-11-11 18:14:41 +0100 |
| commit | 12a03a9a72f7895d571dbaeeb245d92aa277a610 (patch) | |
| tree | 41b6b07928e4f5e101b7ea5d8389bb4325bbac76 /src/components/organisms/widgets | |
| parent | fb860884857da73ee5b5e897745301cdf1d770a2 (diff) | |
refactor(components): merge HeadingButton and Widget components
The HeadingButton component was only used inside Widget component and
it is not very useful on its own so I merge the two components in a
new Collapsible component.
Diffstat (limited to 'src/components/organisms/widgets')
13 files changed, 136 insertions, 192 deletions
diff --git a/src/components/organisms/widgets/image-widget.stories.tsx b/src/components/organisms/widgets/image-widget.stories.tsx index 9460060..e9857bf 100644 --- a/src/components/organisms/widgets/image-widget.stories.tsx +++ b/src/components/organisms/widgets/image-widget.stories.tsx @@ -1,4 +1,5 @@ -import { ComponentMeta, ComponentStory } from '@storybook/react'; +import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Heading } from '../../atoms'; import { ImageWidget } from './image-widget'; /** @@ -52,16 +53,6 @@ export default { required: false, }, }, - expanded: { - control: { - type: 'boolean', - }, - description: 'The state of the widget.', - type: { - name: 'boolean', - required: true, - }, - }, image: { description: 'An image object.', type: { @@ -83,28 +74,6 @@ export default { required: false, }, }, - level: { - control: { - type: 'number', - min: 1, - max: 6, - }, - description: 'The widget title level (hn).', - type: { - name: 'number', - required: true, - }, - }, - title: { - control: { - type: 'text', - }, - description: 'The widget title.', - type: { - name: 'string', - required: true, - }, - }, url: { control: { type: 'text', @@ -128,7 +97,7 @@ const Template: ComponentStory<typeof ImageWidget> = (args) => ( const image = { alt: 'Et perferendis quaerat', height: 480, - src: 'http://placeimg.com/640/480/nature', + src: 'http://picsum.photos/640/480', width: 640, }; @@ -138,10 +107,12 @@ const image = { export const AlignLeft = Template.bind({}); AlignLeft.args = { alignment: 'left', - expanded: true, + heading: ( + <Heading isFake level={3}> + Quo et totam + </Heading> + ), image, - level: 2, - title: 'Quo et totam', }; /** @@ -150,10 +121,12 @@ AlignLeft.args = { export const AlignCenter = Template.bind({}); AlignCenter.args = { alignment: 'center', - expanded: true, + heading: ( + <Heading isFake level={3}> + Quo et totam + </Heading> + ), image, - level: 2, - title: 'Quo et totam', }; /** @@ -162,10 +135,12 @@ AlignCenter.args = { export const AlignRight = Template.bind({}); AlignRight.args = { alignment: 'right', - expanded: true, + heading: ( + <Heading isFake level={3}> + Quo et totam + </Heading> + ), image, - level: 2, - title: 'Quo et totam', }; /** @@ -174,8 +149,10 @@ AlignRight.args = { export const WithDescription = Template.bind({}); WithDescription.args = { description: 'Sint enim harum', - expanded: true, + heading: ( + <Heading isFake level={3}> + Quo et totam + </Heading> + ), image, - level: 2, - title: 'Quo et totam', }; diff --git a/src/components/organisms/widgets/image-widget.test.tsx b/src/components/organisms/widgets/image-widget.test.tsx index 7f3ccd8..3d48947 100644 --- a/src/components/organisms/widgets/image-widget.test.tsx +++ b/src/components/organisms/widgets/image-widget.test.tsx @@ -1,5 +1,6 @@ import { describe, expect, it } from '@jest/globals'; -import { render, screen } from '../../../../tests/utils'; +import { render, screen as rtlScreen } from '@testing-library/react'; +import { Heading } from '../../atoms'; import { ImageWidget } from './image-widget'; const description = 'Ut vitae sit'; @@ -20,26 +21,22 @@ describe('ImageWidget', () => { it('renders an image', () => { render( <ImageWidget - expanded={true} + heading={<Heading level={titleLevel}>{title}</Heading>} image={img} - title={title} - level={titleLevel} /> ); - expect(screen.getByRole('img', { name: img.alt })).toBeInTheDocument(); + expect(rtlScreen.getByRole('img', { name: img.alt })).toBeInTheDocument(); }); - it('renders a link', () => { + it('renders an image with a link', () => { render( <ImageWidget - expanded={true} + heading={<Heading level={titleLevel}>{title}</Heading>} image={img} - title={title} - level={titleLevel} url={url} /> ); - expect(screen.getByRole('link', { name: img.alt })).toHaveAttribute( + expect(rtlScreen.getByRole('link', { name: img.alt })).toHaveAttribute( 'href', url ); @@ -48,13 +45,11 @@ describe('ImageWidget', () => { it('renders a description', () => { render( <ImageWidget - expanded={true} + heading={<Heading level={titleLevel}>{title}</Heading>} image={img} description={description} - title={title} - level={titleLevel} /> ); - expect(screen.getByText(description)).toBeInTheDocument(); + expect(rtlScreen.getByText(description)).toBeInTheDocument(); }); }); diff --git a/src/components/organisms/widgets/image-widget.tsx b/src/components/organisms/widgets/image-widget.tsx index f3dc92f..07c4b11 100644 --- a/src/components/organisms/widgets/image-widget.tsx +++ b/src/components/organisms/widgets/image-widget.tsx @@ -1,9 +1,9 @@ -import { FC } from 'react'; +import type { FC } from 'react'; import { ResponsiveImage, type ResponsiveImageProps, - Widget, - type WidgetProps, + Collapsible, + type CollapsibleProps, } from '../../molecules'; import styles from './image-widget.module.scss'; @@ -14,9 +14,9 @@ export type Image = Pick< 'alt' | 'height' | 'src' | 'width' >; -export type ImageWidgetProps = Pick< - WidgetProps, - 'className' | 'expanded' | 'level' | 'title' +export type ImageWidgetProps = Omit< + CollapsibleProps, + 'children' | 'onToggle' > & { /** * The content alignment. @@ -51,19 +51,23 @@ export const ImageWidget: FC<ImageWidgetProps> = ({ description, image, imageClassName = '', + isCollapsed, url, ...props }) => { const alignmentClass = `widget--${alignment}`; return ( - <Widget className={`${styles[alignmentClass]} ${className}`} {...props}> + <Collapsible + {...props} + className={`${styles[alignmentClass]} ${className}`} + > <ResponsiveImage {...image} caption={description} className={`${styles.figure} ${imageClassName}`} target={url} /> - </Widget> + </Collapsible> ); }; diff --git a/src/components/organisms/widgets/links-list-widget.stories.tsx b/src/components/organisms/widgets/links-list-widget.stories.tsx index 2180de4..6e5f170 100644 --- a/src/components/organisms/widgets/links-list-widget.stories.tsx +++ b/src/components/organisms/widgets/links-list-widget.stories.tsx @@ -1,4 +1,5 @@ import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Heading } from '../../atoms'; import { LinksListWidget } from './links-list-widget'; /** @@ -32,28 +33,6 @@ export default { value: {}, }, }, - level: { - control: { - type: 'number', - min: 1, - max: 6, - }, - description: 'The heading level.', - type: { - name: 'number', - required: true, - }, - }, - title: { - control: { - type: 'text', - }, - description: 'The widget title.', - type: { - name: 'string', - required: true, - }, - }, }, } as ComponentMeta<typeof LinksListWidget>; @@ -89,9 +68,12 @@ const items = [ */ export const Unordered = Template.bind({}); Unordered.args = { + heading: ( + <Heading isFake level={3}> + Quo et totam + </Heading> + ), items, - level: 2, - title: 'A list of links', }; /** @@ -99,8 +81,11 @@ Unordered.args = { */ export const Ordered = Template.bind({}); Ordered.args = { + heading: ( + <Heading isFake level={3}> + Quo et totam + </Heading> + ), isOrdered: true, items, - level: 2, - title: 'A list of links', }; diff --git a/src/components/organisms/widgets/links-list-widget.test.tsx b/src/components/organisms/widgets/links-list-widget.test.tsx index 6323e19..2a914e7 100644 --- a/src/components/organisms/widgets/links-list-widget.test.tsx +++ b/src/components/organisms/widgets/links-list-widget.test.tsx @@ -1,5 +1,6 @@ import { describe, expect, it } from '@jest/globals'; -import { render, screen as rtlScreen } from '../../../../tests/utils'; +import { render, screen as rtlScreen } from '@testing-library/react'; +import { Heading } from '../../atoms'; import { LinksListWidget } from './links-list-widget'; const title = 'Voluptatem minus autem'; @@ -12,19 +13,42 @@ const items = [ describe('LinksListWidget', () => { it('renders a widget title', () => { - render(<LinksListWidget items={items} title={title} level={2} />); + render( + <LinksListWidget + heading={<Heading level={3}>{title}</Heading>} + items={items} + /> + ); expect( - rtlScreen.getByRole('heading', { level: 2, name: new RegExp(title, 'i') }) + rtlScreen.getByRole('heading', { level: 3, name: new RegExp(title, 'i') }) ).toBeInTheDocument(); }); it('renders the correct number of items', () => { - render(<LinksListWidget items={items} title={title} level={2} />); + render( + <LinksListWidget + heading={ + <Heading isFake level={3}> + {title} + </Heading> + } + items={items} + /> + ); expect(rtlScreen.getAllByRole('listitem')).toHaveLength(items.length); }); it('renders some links', () => { - render(<LinksListWidget items={items} title={title} level={2} />); + render( + <LinksListWidget + heading={ + <Heading isFake level={3}> + {title} + </Heading> + } + items={items} + /> + ); expect( rtlScreen.getByRole('link', { name: items[0].name }) ).toHaveAttribute('href', items[0].url); diff --git a/src/components/organisms/widgets/links-list-widget.tsx b/src/components/organisms/widgets/links-list-widget.tsx index 8f71efd..17a5884 100644 --- a/src/components/organisms/widgets/links-list-widget.tsx +++ b/src/components/organisms/widgets/links-list-widget.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react'; import { slugify } from '../../../utils/helpers'; import { Link, List, ListItem } from '../../atoms'; -import { Widget, type WidgetProps } from '../../molecules'; +import { Collapsible, type CollapsibleProps } from '../../molecules'; import styles from './links-list-widget.module.scss'; export type LinksListItems = { @@ -19,7 +19,10 @@ export type LinksListItems = { url: string; }; -export type LinksListWidgetProps = Pick<WidgetProps, 'level' | 'title'> & { +export type LinksListWidgetProps = Omit< + CollapsibleProps, + 'children' | 'disablePadding' | 'hasBorders' +> & { className?: string; /** * Should the links be ordered? @@ -71,13 +74,7 @@ export const LinksListWidget: FC<LinksListWidgetProps> = ({ )); return ( - <Widget - {...props} - className={styles.widget} - expanded={true} - withBorders={true} - withScroll={true} - > + <Collapsible {...props} className={styles.widget} disablePadding hasBorders> <List className={`${styles.list} ${styles[listKindClass]} ${className}`} hideMarker @@ -85,6 +82,6 @@ export const LinksListWidget: FC<LinksListWidgetProps> = ({ > {getListItems(items)} </List> - </Widget> + </Collapsible> ); }; diff --git a/src/components/organisms/widgets/sharing.stories.tsx b/src/components/organisms/widgets/sharing.stories.tsx index 3f4a79e..d2be621 100644 --- a/src/components/organisms/widgets/sharing.stories.tsx +++ b/src/components/organisms/widgets/sharing.stories.tsx @@ -1,4 +1,4 @@ -import { ComponentMeta, ComponentStory } from '@storybook/react'; +import type { ComponentMeta, ComponentStory } from '@storybook/react'; import { Sharing as SharingWidget } from './sharing'; /** @@ -29,36 +29,6 @@ export default { value: {}, }, }, - expanded: { - control: { - type: null, - }, - description: 'Default widget state (expanded or collapsed).', - table: { - category: 'Options', - defaultValue: { summary: true }, - }, - type: { - name: 'boolean', - required: false, - }, - }, - level: { - control: { - type: 'number', - min: 1, - max: 6, - }, - description: 'The heading level.', - table: { - category: 'Options', - defaultValue: { summary: 2 }, - }, - type: { - name: 'number', - required: false, - }, - }, media: { control: { type: null, diff --git a/src/components/organisms/widgets/sharing.tsx b/src/components/organisms/widgets/sharing.tsx index eeffb71..47ec49d 100644 --- a/src/components/organisms/widgets/sharing.tsx +++ b/src/components/organisms/widgets/sharing.tsx @@ -1,7 +1,7 @@ import type { FC } from 'react'; import { useIntl } from 'react-intl'; -import { SharingLink, type SharingMedium } from '../../atoms'; -import { Widget, type WidgetProps } from '../../molecules'; +import { Heading, SharingLink, type SharingMedium } from '../../atoms'; +import { Collapsible, type CollapsibleProps } from '../../molecules'; import styles from './sharing.module.scss'; /** @@ -80,7 +80,7 @@ export type SharingData = { url: string; }; -export type SharingProps = { +export type SharingProps = Omit<CollapsibleProps, 'children' | 'heading'> & { /** * Set additional classnames to the sharing links list. */ @@ -90,14 +90,6 @@ export type SharingProps = { */ data: SharingData; /** - * The widget default state. - */ - expanded?: WidgetProps['expanded']; - /** - * The HTML heading level. - */ - level?: WidgetProps['level']; - /** * A list of active and ordered sharing medium. */ media: SharingMedium[]; @@ -112,8 +104,6 @@ export const Sharing: FC<SharingProps> = ({ className = '', data, media, - expanded = true, - level = 2, ...props }) => { const listClass = `${styles.list} ${className}`; @@ -255,8 +245,15 @@ export const Sharing: FC<SharingProps> = ({ )); return ( - <Widget {...props} expanded={expanded} level={level} title={widgetTitle}> + <Collapsible + {...props} + heading={ + <Heading isFake level={3}> + {widgetTitle} + </Heading> + } + > <ul className={listClass}>{getItems()}</ul> - </Widget> + </Collapsible> ); }; diff --git a/src/components/organisms/widgets/social-media.stories.tsx b/src/components/organisms/widgets/social-media.stories.tsx index 6da3f3a..8064157 100644 --- a/src/components/organisms/widgets/social-media.stories.tsx +++ b/src/components/organisms/widgets/social-media.stories.tsx @@ -1,4 +1,5 @@ import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Heading } from '../../atoms'; import { SocialMedia as SocialMediaWidget, type Media } from './social-media'; /** @@ -8,18 +9,6 @@ export default { title: 'Organisms/Widgets', component: SocialMediaWidget, argTypes: { - level: { - control: { - type: 'number', - min: 1, - max: 6, - }, - description: 'The heading level.', - type: { - name: 'number', - required: true, - }, - }, media: { description: 'The links data.', type: { @@ -28,16 +17,6 @@ export default { value: {}, }, }, - title: { - control: { - type: 'text', - }, - description: 'The widget title.', - type: { - name: 'string', - required: true, - }, - }, }, } as ComponentMeta<typeof SocialMediaWidget>; @@ -55,7 +34,10 @@ const media: Media[] = [ */ export const SocialMedia = Template.bind({}); SocialMedia.args = { + heading: ( + <Heading isFake level={3}> + Follow me + </Heading> + ), media, - title: 'Follow me', - level: 2, }; diff --git a/src/components/organisms/widgets/social-media.test.tsx b/src/components/organisms/widgets/social-media.test.tsx index 2cd3afb..ead29d9 100644 --- a/src/components/organisms/widgets/social-media.test.tsx +++ b/src/components/organisms/widgets/social-media.test.tsx @@ -1,6 +1,7 @@ import { describe, expect, it } from '@jest/globals'; import { render, screen as rtlScreen } from '../../../../tests/utils'; import { SocialMedia, type Media } from './social-media'; +import { Heading } from 'src/components/atoms'; const media: Media[] = [ { icon: 'Github', id: 'github', label: 'Github', url: '#' }, @@ -20,7 +21,12 @@ jest.mock('@assets/images/social-media/twitter.svg', () => 'svg-file'); describe('SocialMedia', () => { it('renders the widget title', () => { - render(<SocialMedia media={media} title={title} level={titleLevel} />); + render( + <SocialMedia + heading={<Heading level={titleLevel}>{title}</Heading>} + media={media} + /> + ); expect( rtlScreen.getByRole('heading', { level: titleLevel, @@ -30,7 +36,12 @@ describe('SocialMedia', () => { }); it('renders the correct number of items', () => { - render(<SocialMedia media={media} title={title} level={titleLevel} />); + render( + <SocialMedia + heading={<Heading level={titleLevel}>{title}</Heading>} + media={media} + /> + ); expect(rtlScreen.getAllByRole('listitem')).toHaveLength(media.length); }); }); diff --git a/src/components/organisms/widgets/social-media.tsx b/src/components/organisms/widgets/social-media.tsx index ddeb09c..14c8fe6 100644 --- a/src/components/organisms/widgets/social-media.tsx +++ b/src/components/organisms/widgets/social-media.tsx @@ -1,13 +1,13 @@ import type { FC } from 'react'; import { List, ListItem, SocialLink, type SocialLinkProps } from '../../atoms'; -import { Widget, type WidgetProps } from '../../molecules'; +import { Collapsible, type CollapsibleProps } from '../../molecules'; import styles from './social-media.module.scss'; export type Media = Required< Pick<SocialLinkProps, 'icon' | 'id' | 'label' | 'url'> >; -export type SocialMediaProps = Pick<WidgetProps, 'level' | 'title'> & { +export type SocialMediaProps = Omit<CollapsibleProps, 'children'> & { media: Media[]; }; @@ -31,10 +31,10 @@ export const SocialMedia: FC<SocialMediaProps> = ({ media, ...props }) => { )); return ( - <Widget expanded={true} {...props}> + <Collapsible {...props}> <List className={styles.list} hideMarker isInline spacing="xs"> {getItems(media)} </List> - </Widget> + </Collapsible> ); }; diff --git a/src/components/organisms/widgets/table-of-contents.test.tsx b/src/components/organisms/widgets/table-of-contents.test.tsx index f0917b8..f5b2a87 100644 --- a/src/components/organisms/widgets/table-of-contents.test.tsx +++ b/src/components/organisms/widgets/table-of-contents.test.tsx @@ -1,13 +1,11 @@ import { describe, expect, it } from '@jest/globals'; -import { render, screen } from '../../../../tests/utils'; +import { render, screen as rtlScreen } from '../../../../tests/utils'; import { TableOfContents } from './table-of-contents'; describe('TableOfContents', () => { - it('renders the ToC title', () => { + it('renders a title', () => { const divEl = document.createElement('div'); render(<TableOfContents wrapper={divEl} />); - expect( - screen.getByRole('heading', { level: 2, name: /Table of Contents/i }) - ).toBeInTheDocument(); + expect(rtlScreen.getByText(/Table of Contents/i)).toBeInTheDocument(); }); }); diff --git a/src/components/organisms/widgets/table-of-contents.tsx b/src/components/organisms/widgets/table-of-contents.tsx index e67b495..8892485 100644 --- a/src/components/organisms/widgets/table-of-contents.tsx +++ b/src/components/organisms/widgets/table-of-contents.tsx @@ -3,6 +3,7 @@ import { useIntl } from 'react-intl'; import { useHeadingsTree, type Heading } from '../../../utils/hooks'; import { type LinksListItems, LinksListWidget } from './links-list-widget'; import styles from './table-of-contents.module.scss'; +import { Heading as HeadingComponent } from 'src/components/atoms'; type TableOfContentsProps = { /** @@ -43,10 +44,13 @@ export const TableOfContents: FC<TableOfContentsProps> = ({ wrapper }) => { return ( <LinksListWidget className={styles.list} + heading={ + <HeadingComponent isFake level={3}> + {title} + </HeadingComponent> + } isOrdered items={getItems(headingsTree)} - level={2} - title={title} /> ); }; |
