import { Text as RNText, TextStyle, type TextProps, } from 'react-native'; import React, { memo, useMemo } from 'react'; import useTheme from '../hooks/useTheme'; import { ThemeName, themeColors } from '../constants/Colors'; export type Props = TextProps & { themeScheme?: 'light' | 'dark'; variantColor?: 'default' | 'primary' | 'secondary' | ThemeName; variant?: | 'H1' | 'H2' | 'H3' | 'H4' | 'H5' | 'H6' | 'subtitle1' | 'subtitle2' | 'body1' | 'body2' | 'button' | 'caption' | 'overline'; bold?: TextStyle['fontWeight']; size?: TextStyle['fontSize']; center?: boolean; }; const Text = memo(function Text({ style, themeScheme, bold, size, center = false, variantColor = 'default', variant = 'body1', ...otherProps }: Props) { const { currentTheme, themeScheme: defaultThemeScheme } = useTheme(); const colorStyle = useMemo(() => { if (variantColor === 'default') { return { color: currentTheme.foreground }; } if (variantColor === 'secondary') { return { color: currentTheme.muted_foreground }; } if (variantColor === 'primary') { return { color: currentTheme.primary }; } const theme = themeColors.find((t) => t.name === variantColor)?.[themeScheme ?? defaultThemeScheme]; return { color: theme?.primary || currentTheme.primary_foreground }; }, [currentTheme, themeScheme, defaultThemeScheme, variantColor]); const textVariantStyle = useMemo(() => { const variants: Record, TextStyle> = { H1: { fontSize: 96, fontWeight: '100', letterSpacing: -1.5 }, H2: { fontSize: 60, fontWeight: '100', letterSpacing: -0.5 }, H3: { fontSize: 48, fontWeight: '400' }, H4: { fontSize: 34, fontWeight: '400', letterSpacing: 0.25 }, H5: { fontSize: 24, fontWeight: '400' }, H6: { fontSize: 20, fontWeight: '500', letterSpacing: 0.15 }, subtitle1: { fontSize: 16, fontWeight: '400', letterSpacing: 0.15 }, subtitle2: { fontSize: 14, fontWeight: '500', letterSpacing: 0.1 }, body1: { fontSize: 16, fontWeight: '400', letterSpacing: 0.5 }, body2: { fontSize: 14, fontWeight: '400', letterSpacing: 0.25 }, button: { fontSize: 14, fontWeight: '500', letterSpacing: 1.25 }, caption: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4 }, overline: { fontSize: 10, fontWeight: '400', letterSpacing: 1.5 }, }; return variants[variant] || { fontSize: 16, fontWeight: '400' }; }, [variant]); if (!currentTheme) return <>; const combinedStyles = useMemo(() => { return [ { textAlign: center ? 'center' as 'center' : 'auto' as 'auto', opacity: otherProps?.disabled ? 0.5 : 1 }, colorStyle, textVariantStyle, bold ? { fontWeight: bold } : {}, size ? { fontSize: size } : {}, style, ]; }, [center, otherProps?.disabled, colorStyle, textVariantStyle, bold, size, style]); return ; }); export default Text;