From a6ff5eee45215effb3344cb5d631a27a7c0369aa Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 22 Sep 2023 19:34:01 +0200 Subject: refactor(components): rewrite form components --- src/components/atoms/modal/index.ts | 1 + src/components/atoms/modal/modal.module.scss | 66 ++++++++++++++++++++++++++++ src/components/atoms/modal/modal.stories.tsx | 59 +++++++++++++++++++++++++ src/components/atoms/modal/modal.test.tsx | 25 +++++++++++ src/components/atoms/modal/modal.tsx | 49 +++++++++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 src/components/atoms/modal/index.ts create mode 100644 src/components/atoms/modal/modal.module.scss create mode 100644 src/components/atoms/modal/modal.stories.tsx create mode 100644 src/components/atoms/modal/modal.test.tsx create mode 100644 src/components/atoms/modal/modal.tsx (limited to 'src/components/atoms/modal') diff --git a/src/components/atoms/modal/index.ts b/src/components/atoms/modal/index.ts new file mode 100644 index 0000000..133aa74 --- /dev/null +++ b/src/components/atoms/modal/index.ts @@ -0,0 +1 @@ +export * from './modal'; diff --git a/src/components/atoms/modal/modal.module.scss b/src/components/atoms/modal/modal.module.scss new file mode 100644 index 0000000..6650235 --- /dev/null +++ b/src/components/atoms/modal/modal.module.scss @@ -0,0 +1,66 @@ +@use "../../../styles/abstracts/functions" as fun; +@use "../../../styles/abstracts/mixins" as mix; + +.modal { + position: relative; + box-shadow: + fun.convert-px(0.2) fun.convert-px(0.2) fun.convert-px(0.3) 0 + var(--color-shadow), + fun.convert-px(1.5) fun.convert-px(1.5) fun.convert-px(2.5) + fun.convert-px(-0.3) var(--color-shadow), + fun.convert-px(4.7) fun.convert-px(4.7) fun.convert-px(8) fun.convert-px(-1) + var(--color-shadow); + + &--primary { + padding: clamp(var(--spacing-xs), 2.5vw, var(--spacing-md)); + background: var(--color-bg-secondary); + border: fun.convert-px(3) solid; + border-image: radial-gradient( + ellipse at top, + var(--color-primary-lighter) 20%, + var(--color-primary) 100% + ) + 1; + + .title { + margin-bottom: var(--spacing-2xs); + } + + @include mix.media("screen") { + @include mix.dimensions(null, "sm") { + border-left: none; + border-right: none; + } + } + } + + &--secondary { + padding: clamp(var(--spacing-xs), 2.2vw, var(--spacing-sm)); + background: var(--color-bg); + border: fun.convert-px(2) solid var(--color-primary-dark); + border-radius: fun.convert-px(3); + + .title { + padding-inline: var(--spacing-xs); + background: var(--color-bg); + border: fun.convert-px(1) solid var(--color-primary-dark); + box-shadow: fun.convert-px(1) fun.convert-px(1) 0 0 var(--color-shadow); + color: var(--color-primary-darker); + font-variant: small-caps; + + > * { + margin-block: 0; + } + } + } + + &--secondary#{&}--has-title { + --title-height: #{fun.convert-px(40)}; + + .title { + width: fit-content; + height: var(--title-height); + margin: calc(var(--title-height) * -1) auto var(--spacing-xs); + } + } +} diff --git a/src/components/atoms/modal/modal.stories.tsx b/src/components/atoms/modal/modal.stories.tsx new file mode 100644 index 0000000..d0c2f0b --- /dev/null +++ b/src/components/atoms/modal/modal.stories.tsx @@ -0,0 +1,59 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Modal } from './modal'; +import { Heading } from '../headings'; + +/** + * Switch - Storybook Meta + */ +export default { + title: 'Atoms/Modals', + component: Modal, + args: {}, + argTypes: {}, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ; + +/** + * Modal Stories - Primary + */ +export const Primary = Template.bind({}); +Primary.args = { + children: + 'Inventore natus dignissimos aut illum modi asperiores. Et voluptatibus delectus.', +}; + +/** + * Modal Stories - Primary With Heading + */ +export const PrimaryWithHeading = Template.bind({}); +PrimaryWithHeading.args = { + children: + 'Inventore natus dignissimos aut illum modi asperiores. Et voluptatibus delectus.', + heading: Aut provident eum, +}; + +/** + * Modal Stories - Secondary + */ +export const Secondary = Template.bind({}); +Secondary.args = { + children: + 'Inventore natus dignissimos aut illum modi asperiores. Et voluptatibus delectus.', + kind: 'secondary', +}; + +/** + * Modal Stories - Secondary with heading + */ +export const SecondaryWithHeading = Template.bind({}); +SecondaryWithHeading.args = { + children: + 'Inventore natus dignissimos aut illum modi asperiores. Et voluptatibus delectus.', + heading: ( + + Aut provident eum + + ), + kind: 'secondary', +}; diff --git a/src/components/atoms/modal/modal.test.tsx b/src/components/atoms/modal/modal.test.tsx new file mode 100644 index 0000000..5f32d02 --- /dev/null +++ b/src/components/atoms/modal/modal.test.tsx @@ -0,0 +1,25 @@ +import { render, screen } from '../../../../tests/utils'; +import { Heading } from '../headings'; +import { Modal } from './modal'; + +const title = 'A custom title'; +const children = + 'Labore ullam delectus sit modi quam dolores. Ratione id sint aliquid facilis ipsum. Unde necessitatibus provident minus.'; + +describe('Modal', () => { + it('renders a title', () => { + const level = 2; + + render( + {title}}> + {children} + + ); + expect(screen.getByRole('heading', { level })).toHaveTextContent(title); + }); + + it('renders the modal body', () => { + render({children}); + expect(screen.getByText(children)).toBeInTheDocument(); + }); +}); diff --git a/src/components/atoms/modal/modal.tsx b/src/components/atoms/modal/modal.tsx new file mode 100644 index 0000000..78b4f6e --- /dev/null +++ b/src/components/atoms/modal/modal.tsx @@ -0,0 +1,49 @@ +import { + ForwardRefRenderFunction, + HTMLAttributes, + ReactElement, + ReactNode, + forwardRef, +} from 'react'; +import { HeadingProps } from '../headings'; +import styles from './modal.module.scss'; + +export type ModalProps = HTMLAttributes & { + /** + * The modal body. + */ + children: ReactNode; + /** + * The modal title. + */ + heading?: ReactElement; + /** + * The modal kind. + * + * @default 'primary' + */ + kind?: 'primary' | 'secondary'; +}; + +const ModalWithRef: ForwardRefRenderFunction = ( + { children, className = '', heading, kind = 'primary', ...props }, + ref +) => { + const headingModifier = heading ? 'modal--has-title' : ''; + const kindModifier = `modal--${kind}`; + const modalClass = `${styles.modal} ${styles[headingModifier]} ${styles[kindModifier]} ${className}`; + + return ( +
+ {heading ?
{heading}
: null} + {children} +
+ ); +}; + +/** + * Modal component + * + * Render a modal component. + */ +export const Modal = forwardRef(ModalWithRef); -- cgit v1.2.3