From 12a03a9a72f7895d571dbaeeb245d92aa277a610 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 6 Oct 2023 17:48:03 +0200 Subject: 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. --- .../organisms/widgets/image-widget.stories.tsx | 69 ++++++++-------------- .../organisms/widgets/image-widget.test.tsx | 23 +++----- src/components/organisms/widgets/image-widget.tsx | 20 ++++--- .../widgets/links-list-widget.stories.tsx | 37 ++++-------- .../organisms/widgets/links-list-widget.test.tsx | 34 +++++++++-- .../organisms/widgets/links-list-widget.tsx | 17 +++--- .../organisms/widgets/sharing.stories.tsx | 32 +--------- src/components/organisms/widgets/sharing.tsx | 27 ++++----- .../organisms/widgets/social-media.stories.tsx | 30 ++-------- .../organisms/widgets/social-media.test.tsx | 15 ++++- src/components/organisms/widgets/social-media.tsx | 8 +-- .../organisms/widgets/table-of-contents.test.tsx | 8 +-- .../organisms/widgets/table-of-contents.tsx | 8 ++- 13 files changed, 136 insertions(+), 192 deletions(-) (limited to 'src/components/organisms/widgets') 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 = (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: ( + + Quo et totam + + ), 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: ( + + Quo et totam + + ), 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: ( + + Quo et totam + + ), 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: ( + + Quo et totam + + ), 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( {title}} 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( {title}} 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( {title}} 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 = ({ description, image, imageClassName = '', + isCollapsed, url, ...props }) => { const alignmentClass = `widget--${alignment}`; return ( - + - + ); }; 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; @@ -89,9 +68,12 @@ const items = [ */ export const Unordered = Template.bind({}); Unordered.args = { + heading: ( + + Quo et totam + + ), items, - level: 2, - title: 'A list of links', }; /** @@ -99,8 +81,11 @@ Unordered.args = { */ export const Ordered = Template.bind({}); Ordered.args = { + heading: ( + + Quo et totam + + ), 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(); + render( + {title}} + 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(); + render( + + {title} + + } + items={items} + /> + ); expect(rtlScreen.getAllByRole('listitem')).toHaveLength(items.length); }); it('renders some links', () => { - render(); + render( + + {title} + + } + 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 & { +export type LinksListWidgetProps = Omit< + CollapsibleProps, + 'children' | 'disablePadding' | 'hasBorders' +> & { className?: string; /** * Should the links be ordered? @@ -71,13 +74,7 @@ export const LinksListWidget: FC = ({ )); return ( - + = ({ > {getListItems(items)} - + ); }; 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 & { /** * Set additional classnames to the sharing links list. */ @@ -89,14 +89,6 @@ export type SharingProps = { * The page data to share. */ data: SharingData; - /** - * The widget default state. - */ - expanded?: WidgetProps['expanded']; - /** - * The HTML heading level. - */ - level?: WidgetProps['level']; /** * A list of active and ordered sharing medium. */ @@ -112,8 +104,6 @@ export const Sharing: FC = ({ className = '', data, media, - expanded = true, - level = 2, ...props }) => { const listClass = `${styles.list} ${className}`; @@ -255,8 +245,15 @@ export const Sharing: FC = ({ )); return ( - + + {widgetTitle} + + } + >
    {getItems()}
-
+ ); }; 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; @@ -55,7 +34,10 @@ const media: Media[] = [ */ export const SocialMedia = Template.bind({}); SocialMedia.args = { + heading: ( + + Follow me + + ), 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(); + render( + {title}} + media={media} + /> + ); expect( rtlScreen.getByRole('heading', { level: titleLevel, @@ -30,7 +36,12 @@ describe('SocialMedia', () => { }); it('renders the correct number of items', () => { - render(); + render( + {title}} + 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 >; -export type SocialMediaProps = Pick & { +export type SocialMediaProps = Omit & { media: Media[]; }; @@ -31,10 +31,10 @@ export const SocialMedia: FC = ({ media, ...props }) => { )); return ( - + {getItems(media)} - + ); }; 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(); - 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 = ({ wrapper }) => { return ( + {title} + + } isOrdered items={getItems(headingsTree)} - level={2} - title={title} /> ); }; -- cgit v1.2.3