Skip to content

Instantly share code, notes, and snippets.

@ortense
Created December 19, 2023 22:52
Show Gist options
  • Save ortense/fda53d33c1b0536da15fa7559c67916e to your computer and use it in GitHub Desktop.
Save ortense/fda53d33c1b0536da15fa7559c67916e to your computer and use it in GitHub Desktop.
Typography react component
import { Typography, TypographyProps } from './Typography'
import { Size } from './types'
export type HeadingLevel = '1' | '2' | '3' | '4' | '5' | '6'
export type HeadingProps = Omit<TypographyProps, 'size'> & {
level?: HeadingLevel
}
export const HeadingLevelSize: Record<HeadingLevel, Size> = {
1: 'immense',
2: 'enormous',
3: 'huge',
4: 'larger',
5: 'large',
6: 'regular',
} as const
export function Heading({ level = '1', as: Component = `h${level}`, ...props }: HeadingProps) {
return <Typography size={HeadingLevelSize[level]} as={Component} {...props} />
}
export * from './Typography'
export * from './Text'
export * from './Heading'
export * from './types'
import { Typography, TypographyProps } from './Typography'
import { Size } from './types'
export type TextLevel = '1' | '2' | '3' | '4' | '5'
const TextLevelSize: Record<TextLevel, Size> = {
1: 'larger',
2: 'large',
3: 'regular',
4: 'small',
5: 'tiny',
} as const
export type TextProps = Omit<TypographyProps, 'size'> & {
level?: TextLevel
}
export function Text({ level = '3', as: Component = 'p', ...props }: TextProps) {
return <Typography size={TextLevelSize[level]} as={Component} {...props} />
}
export type Size =
| 'tiny'
| 'small'
| 'regular'
| 'large'
| 'larger'
| 'huge'
| 'enormous'
| 'immense'
| 'colossal'
export type TypographyTag =
| 'a'
| 'abbr'
| 'address'
| 'b'
| 'bdi'
| 'bdo'
| 'blockquote'
| 'caption'
| 'cite'
| 'code'
| 'dd'
| 'details'
| 'figcaption'
| 'h1'
| 'h2'
| 'h3'
| 'h4'
| 'h5'
| 'h6'
| 'kbd'
| 'label'
| 'legend'
| 'li'
| 'option'
| 'p'
| 'q'
| 'rt'
| 'rp'
| 'ruby'
| 'span'
| 'strong'
| 'time'
| 'td'
| 'th'
:root {
--size-tiny: 0.5rem;
--size-small: 0.7rem;
--size-regular: 1rem;
--size-large: 1.3rem;
--size-larger: 1.7rem;
--size-huge: 2.2rem;
--size-enormous: 2.85rem;
--size-immense: 3.7rem;
--size-colossal: 4.85rem;
--font-scale-tiny: var(--size-tiny);
--font-scale-small: var(--size-small);
--font-scale-regular: var(--size-regular);
--font-scale-large: var(--size-large);
--font-scale-larger: var(--size-larger);
--font-scale-huge: var(--size-huge);
--font-scale-enormous: var(--size-enormous);
--font-scale-immense: var(--size-immense);
--font-scale-colossal: var(--size-colossal);
}
.Typography {
--typography-font-size: var(--font-scale-regular);
font-size: var(--typography-font-size);
}
.Typography.tiny { --typography-font-size: var(--font-scale-tiny) }
.Typography.small { --typography-font-size: var(--font-scale-small) }
.Typography.regular { --typography-font-size: var(--font-scale-regular) }
.Typography.large { --typography-font-size: var(--font-scale-large) }
.Typography.larger { --typography-font-size: var(--font-scale-larger) }
.Typography.huge { --typography-font-size: var(--font-scale-huge) }
.Typography.enormous { --typography-font-size: var(--font-scale-enormous) }
.Typography.immense { --typography-font-size: var(--font-scale-immense) }
.Typography.colossal { --typography-font-size: var(--font-scale-colossal) }
import { HTMLAttributes, ReactElement, ReactNode, cloneElement, isValidElement } from 'react'
import styles from './Typography.module.css'
import { Size, TypographyTag } from './types'
export type TypographyProps = HTMLAttributes<HTMLSpanElement> & {
children: ReactNode
asChildren?: boolean
as?: TypographyTag
size?: Size
}
export function Typography({ size = 'regular', className, children, ...props }: TypographyProps) {
const classValue = `${styles.Typography} ${styles[size]}${className ? ` ${className}` : ''}`;
if ('asChildren' in props && isValidElement(children)) {
const { asChildren, ...rest } = props
const element = children as ReactElement
return cloneElement(children as ReactElement, {
className: `${element.props.className || ''} ${classValue}`.trim(),
...rest
})
}
if ('as' in props) {
const { as: Component = 'span', ...rest } = props
return <Component className={classValue} {...rest}>{children}</Component>
}
return <span {...props}>{children}</span>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment