aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/organisms/widgets
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-10-06 17:48:03 +0200
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:14:41 +0100
commit12a03a9a72f7895d571dbaeeb245d92aa277a610 (patch)
tree41b6b07928e4f5e101b7ea5d8389bb4325bbac76 /src/components/organisms/widgets
parentfb860884857da73ee5b5e897745301cdf1d770a2 (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')
-rw-r--r--src/components/organisms/widgets/image-widget.stories.tsx69
-rw-r--r--src/components/organisms/widgets/image-widget.test.tsx23
-rw-r--r--src/components/organisms/widgets/image-widget.tsx20
-rw-r--r--src/components/organisms/widgets/links-list-widget.stories.tsx37
-rw-r--r--src/components/organisms/widgets/links-list-widget.test.tsx34
-rw-r--r--src/components/organisms/widgets/links-list-widget.tsx17
-rw-r--r--src/components/organisms/widgets/sharing.stories.tsx32
-rw-r--r--src/components/organisms/widgets/sharing.tsx27
-rw-r--r--src/components/organisms/widgets/social-media.stories.tsx30
-rw-r--r--src/components/organisms/widgets/social-media.test.tsx15
-rw-r--r--src/components/organisms/widgets/social-media.tsx8
-rw-r--r--src/components/organisms/widgets/table-of-contents.test.tsx8
-rw-r--r--src/components/organisms/widgets/table-of-contents.tsx8
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}
/>
);
};