bigbuffet-rw/app/soapbox/components/ui/text/text.tsx

130 lines
3.4 KiB
TypeScript
Raw Normal View History

2022-03-21 11:09:01 -07:00
import classNames from 'classnames';
import React from 'react';
type Themes = 'default' | 'danger' | 'primary' | 'muted' | 'subtle' | 'success' | 'inherit' | 'white'
type Weights = 'normal' | 'medium' | 'semibold' | 'bold'
type Sizes = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'
type Alignments = 'left' | 'center' | 'right'
type TrackingSizes = 'normal' | 'wide'
2022-04-12 06:50:04 -07:00
type TransformProperties = 'uppercase' | 'normal'
2022-03-21 11:09:01 -07:00
type Families = 'sans' | 'mono'
2022-04-27 07:11:21 -07:00
type Tags = 'abbr' | 'p' | 'span' | 'pre' | 'time' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label'
2022-03-21 11:09:01 -07:00
const themes = {
2022-03-23 17:18:37 -07:00
default: 'text-gray-900 dark:text-gray-100',
2022-03-21 11:09:01 -07:00
danger: 'text-danger-600',
primary: 'text-primary-600',
2022-03-23 17:18:37 -07:00
muted: 'text-gray-500 dark:text-gray-400',
subtle: 'text-gray-400 dark:text-gray-500',
2022-03-21 11:09:01 -07:00
success: 'text-success-600',
inherit: 'text-inherit',
white: 'text-white',
};
const weights = {
normal: 'font-normal',
medium: 'font-medium',
semibold: 'font-semibold',
bold: 'font-bold',
};
const sizes = {
xs: 'text-xs',
sm: 'text-sm',
md: 'text-md',
lg: 'text-lg',
xl: 'text-xl',
'2xl': 'text-2xl',
'3xl': 'text-3xl',
};
const alignments = {
left: 'text-left',
center: 'text-center',
right: 'text-right',
};
const trackingSizes = {
normal: 'tracking-normal',
wide: 'tracking-wide',
};
2022-04-12 06:50:04 -07:00
const transformProperties = {
normal: 'normal-case',
uppercase: 'uppercase',
};
2022-03-21 11:09:01 -07:00
const families = {
sans: 'font-sans',
mono: 'font-mono',
};
interface IText extends Pick<React.HTMLAttributes<HTMLParagraphElement>, 'dangerouslySetInnerHTML'> {
/** How to align the text. */
2022-03-21 11:09:01 -07:00
align?: Alignments,
/** Extra class names for the outer element. */
2022-03-21 11:09:01 -07:00
className?: string,
/** Typeface of the text. */
2022-03-21 11:09:01 -07:00
family?: Families,
2022-04-27 07:11:21 -07:00
/** The "for" attribute specifies which form element a label is bound to. */
htmlFor?: string,
/** Font size of the text. */
2022-03-21 11:09:01 -07:00
size?: Sizes,
/** HTML element name of the outer element. */
2022-03-21 11:09:01 -07:00
tag?: Tags,
/** Theme for the text. */
2022-03-21 11:09:01 -07:00
theme?: Themes,
/** Letter-spacing of the text. */
2022-03-21 11:09:01 -07:00
tracking?: TrackingSizes,
/** Transform (eg uppercase) for the text. */
2022-04-12 06:50:04 -07:00
transform?: TransformProperties,
/** Whether to truncate the text if its container is too small. */
2022-03-21 11:09:01 -07:00
truncate?: boolean,
/** Font weight of the text. */
2022-03-21 11:09:01 -07:00
weight?: Weights
}
/** UI-friendly text container with dark mode support. */
2022-03-21 11:09:01 -07:00
const Text: React.FC<IText> = React.forwardRef(
(props: IText, ref: React.LegacyRef<any>) => {
const {
align,
className,
family = 'sans',
size = 'md',
tag = 'p',
theme = 'default',
tracking = 'normal',
2022-04-12 06:50:04 -07:00
transform = 'normal',
2022-03-21 11:09:01 -07:00
truncate = false,
weight = 'normal',
...filteredProps
} = props;
const Comp: React.ElementType = tag;
const alignmentClass = typeof align === 'string' ? alignments[align] : '';
2022-03-21 11:09:01 -07:00
return (
<Comp
{...filteredProps}
ref={ref}
style={tag === 'abbr' ? { textDecoration: 'underline dotted' } : undefined}
2022-03-21 11:09:01 -07:00
className={classNames({
'cursor-default': tag === 'abbr',
truncate: truncate,
[sizes[size]]: true,
[themes[theme]]: true,
[weights[weight]]: true,
[trackingSizes[tracking]]: true,
[families[family]]: true,
[alignmentClass]: typeof align !== 'undefined',
2022-04-12 06:50:04 -07:00
[transformProperties[transform]]: typeof transform !== 'undefined',
}, className)}
2022-03-21 11:09:01 -07:00
/>
);
},
);
export default Text;