import type { SVGAttributes } from 'react'; import { HamburgerIcon, type HamburgerIconProps } from './hamburger-icon'; import styles from './icon.module.scss'; import { PlusMinusIcon, type PlusMinusIconProps, type PlusMinusIconShape, } from './plus-minus-icon'; import { type SVGIconShape, SVGPaths, type SVGPathsProps } from './svg-paths'; export type IconShape = | SVGIconShape | PlusMinusIconShape | 'hamburger' | 'help'; export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'; type SVGIconProps = Omit< SVGAttributes, 'children' | 'viewBox' | 'xmlns' > & { /** * Describe the icon. */ description?: string; /** * Define an accessible title for the icon. */ heading?: string; }; type IconBaseProps = T extends 'hamburger' ? HamburgerIconProps : T extends 'minus' | 'plus' ? PlusMinusIconProps : SVGIconProps; type AdditionalProps = Pick< SVGPathsProps, 'orientation' > & { /** * The icon shape. */ shape: T; /** * The icon size. * * @default 'md' */ size?: IconSize; }; export type IconProps = IconBaseProps & Pick & AdditionalProps; type BuildClassNameConfig = Pick< IconProps, 'className' > & Pick, 'shape' | 'size'>; const buildClassName = ({ className, shape, size, }: BuildClassNameConfig) => { const classNames = ['icon', `icon--${shape}`, `icon--${size}`].map( (key) => styles[key] ); if (className) classNames.push(className); return classNames.join(' '); }; type ExtractedProps = 'className' | 'orientation' | 'shape' | 'size'; export const Icon = ({ className = '', orientation, shape, size = 'md', ...props }: IconProps) => { const iconClass = buildClassName({ className, shape, size }); if (shape === 'hamburger') return ( , ExtractedProps>)} className={iconClass} /> ); if (shape === 'minus' || shape === 'plus') return ( , ExtractedProps>)} className={iconClass} shape={shape} /> ); const viewBox = shape === 'cc-by-sa' ? '0 0 100 40' : '0 0 100 100'; // Without casting Typescript complains because of props generic type const { heading, description, ...remainingProps } = props as Omit< IconProps, ExtractedProps >; return ( {heading ? {heading} : null} {description ? {description} : null} ); };