import { createElement, type HTMLAttributes } from 'react' import classnames from 'classnames' import { type OverrideClassName } from '~components/types/OverrideClassName' import styles from './Heading.module.css' const VARIANTS_24PX_OR_GREATER = ['display-0', 'heading-1', 'heading-2'] export type HeadingVariants = | 'display-0' | 'composable-header-title' | 'heading-1' | 'heading-2' | 'heading-3' | 'heading-4' | 'heading-5' | 'heading-6' export type AllowedHeadingTags = | 'pre' | 'p' | 'div' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' export type AllowedHeadingColors = | 'dark' | 'dark-reduced-opacity' | 'white' | 'white-reduced-opacity' | 'positive' | 'negative' export type HeadingProps = { children: React.ReactNode /** * HTML elements that are allowed on Headings. When not supplied, the tag is inferred from * the variant. E.g. display-0 will infer h1 */ tag?: AllowedHeadingTags /** * Allowed heading variants */ variant: HeadingVariants color?: AllowedHeadingColors } & OverrideClassName> /** * {@link https://cultureamp.atlassian.net/wiki/spaces/DesignSystem/pages/3074885298/Typography#Headings Guidance} * {@link https://cultureamp.design/?path=/docs/components-typography-heading--display-0 Storybook} */ export const Heading = ({ children, tag, variant, color = 'dark', classNameOverride, ...restProps }: HeadingProps): JSX.Element => { const inferredTag = tag ?? translateHeadingLevelToTag(variant) const className = classnames( styles.heading, styles[variant], classNameOverride, styles[color], VARIANTS_24PX_OR_GREATER.includes(variant) ? styles.large : styles.small, ) return createElement(inferredTag, { ...restProps, className }, children) } Heading.displayName = 'Heading' /** * A helper to infer the tag when not explicitly passed as a prop * @param headingLevel Level of the heading */ const translateHeadingLevelToTag = (headingLevel: HeadingVariants): string => { switch (headingLevel) { case 'display-0': case 'composable-header-title': case 'heading-1': return 'h1' case 'heading-2': return 'h2' case 'heading-3': return 'h3' case 'heading-4': return 'h4' case 'heading-5': return 'h5' case 'heading-6': default: return 'h6' } }