From c153f93dc8691a71dc76aad3dd618298da9d238a Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Tue, 17 Oct 2023 19:46:08 +0200 Subject: refactor(components): rewrite Card component * make the component more generic * merge `` and `` styles into card component to avoid repeating the same structure * remove most of the props to use composition However the CSS is a bit complex because of the two variants... Also, the component should be refactored when the CSS pseudo-class `:has` has enough support: the provider and the `cover` and `meta` props should be removed. --- src/components/molecules/card/card.tsx | 112 +++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/components/molecules/card/card.tsx (limited to 'src/components/molecules/card/card.tsx') diff --git a/src/components/molecules/card/card.tsx b/src/components/molecules/card/card.tsx new file mode 100644 index 0000000..788b040 --- /dev/null +++ b/src/components/molecules/card/card.tsx @@ -0,0 +1,112 @@ +import { + forwardRef, + type HTMLAttributes, + type ForwardedRef, + type ReactNode, + type ReactElement, +} from 'react'; +import { Article, ButtonLink, type ButtonLinkProps } from '../../atoms'; +import { CardCoverProvider, CardFooterMetaProvider } from './card-provider'; +import styles from './card.module.scss'; + +type CardBaseProps = T extends string + ? Omit + : Omit, 'children'>; + +export type CardProps = CardBaseProps & { + /** + * The card contents. + */ + children: ReactNode; + /** + * The card cover. You need to add a `` as children to use it. + */ + cover?: ReactElement; + /** + * Should the contents be centered? + * + * @default false + */ + isCentered?: boolean; + /** + * Link the card to another page. + * + * @default undefined + */ + linkTo?: T; + /** + * The meta to place in the card footer. You need to add a `` + * as children to use it. + */ + meta?: ReactElement; + /** + * The card variant. + * + * @default 1 + */ + variant?: 1 | 2; +}; + +const CardWrapper = ( + { + children, + className = '', + cover, + isCentered = false, + linkTo, + meta, + variant = 1, + ...props + }: CardProps, + ref: ForwardedRef +) => { + const wrapperClass = [ + styles.wrapper, + styles[isCentered ? 'wrapper--centered' : 'wrapper--not-centered'], + styles[linkTo ? 'wrapper--is-link' : 'wrapper--is-block'], + className, + ].join(' '); + const cardClass = [ + styles.card, + styles[cover ? 'card--has-cover' : 'card--no-cover'], + styles[meta ? 'card--has-footer-meta' : 'card--no-footer-meta'], + styles[`card--variant-${variant}`], + ].join(' '); + + return ( + + + {linkTo ? ( + )} + className={wrapperClass} + ref={ref} + // eslint-disable-next-line react/jsx-no-literals -- Shape allowed + shape="auto" + to={linkTo} + > +
{children}
+
+ ) : ( +
)} + className={wrapperClass} + ref={ref as ForwardedRef} + > +
{children}
+
+ )} +
+
+ ); +}; + +/** + * Card component + * + * Render a card with title and some other optional data. + * + * TODO: remove `cover` and `meta` props (and adapt CSS) when support for CSS + * `:has()` pseudo-class will be good enough. + */ +export const Card = forwardRef(CardWrapper); -- cgit v1.2.3