All checks were successful
continuous-integration/drone/push Build is passing
71 lines
2.1 KiB
TypeScript
71 lines
2.1 KiB
TypeScript
import * as tailwindColors from 'tailwindcss/colors';
|
|
import type { CSSProperties, ElementType, ReactNode } from 'react';
|
|
|
|
type ChipVariant = 'solid' | 'outlined';
|
|
|
|
type ChipProps<T extends ElementType> = {
|
|
variant?: ChipVariant;
|
|
// Tailwind color token, e.g. "cyan-700", "indigo-500", "rose-600".
|
|
tone?: string;
|
|
as?: T;
|
|
className?: string;
|
|
children: ReactNode;
|
|
};
|
|
|
|
const variantClassMap: Record<ChipVariant, string> = {
|
|
solid: 'chip-solid',
|
|
outlined: 'chip-outlined',
|
|
};
|
|
|
|
type TailwindPalette = Record<string, string>;
|
|
|
|
function resolveTailwindToneColor(tone: string | undefined): string | null {
|
|
const normalizedTone = tone?.trim().toLowerCase();
|
|
if (normalizedTone == null || normalizedTone === '') {
|
|
return null;
|
|
}
|
|
|
|
const colorSource = tailwindColors as unknown as Record<string, unknown>;
|
|
const lastDashIndex = normalizedTone.lastIndexOf('-');
|
|
|
|
if (lastDashIndex === -1) {
|
|
const direct = colorSource[normalizedTone];
|
|
return typeof direct === 'string' ? direct : null;
|
|
}
|
|
|
|
const colorName = normalizedTone.slice(0, lastDashIndex);
|
|
const shade = normalizedTone.slice(lastDashIndex + 1);
|
|
const palette = colorSource[colorName];
|
|
|
|
if (palette == null || typeof palette !== 'object') {
|
|
return null;
|
|
}
|
|
|
|
const shadeColor = (palette as TailwindPalette)[shade];
|
|
return typeof shadeColor === 'string' ? shadeColor : null;
|
|
}
|
|
|
|
export function Chip<T extends ElementType = 'span'>({
|
|
variant = 'solid',
|
|
tone,
|
|
as,
|
|
className = '',
|
|
children,
|
|
}: Readonly<ChipProps<T>>) {
|
|
const Component = as ?? ('span' as ElementType);
|
|
const toneColor = resolveTailwindToneColor(tone);
|
|
const toneStyle: CSSProperties | undefined =
|
|
toneColor == null
|
|
? undefined
|
|
: variant === 'solid'
|
|
? { borderColor: toneColor, backgroundColor: toneColor, color: '#ffffff' }
|
|
: { borderColor: toneColor, color: toneColor };
|
|
const classes = `chip-root ${variantClassMap[variant]} ${className}`.trim();
|
|
|
|
return (
|
|
<Component className={classes} style={toneStyle}>
|
|
{children}
|
|
</Component>
|
|
);
|
|
}
|