import React from "react"; import { Text as RNText, TextStyle } from "react-native"; import responsiveSize from "../../../utils/responsive-size"; import { textStyleFunctions, TextStyleProps, } from "../../../theme/src/style-functions"; import { AtomComponentProps, FinalPearlTheme } from "../../../theme/src/types"; import { useTheme } from "../../../hooks/useTheme"; import { pearl } from "../../../pearl"; type BaseTextProps = React.ComponentProps & { /** * Whether to slightly scale the font size based on the screen dimensions * * @default true */ scaleFontSize?: boolean; }; /** * Builds a font configuration object based on the provided text style and whether font scaling is allowed. * * @param textStyle - The text style to build the font configuration from. * @param allowFontScaling - Whether font scaling is allowed. * @returns A font configuration object. */ export const buildFontConfig = ( textStyle: TextStyle, allowFontScaling: boolean, theme: FinalPearlTheme ): object => { let fontWeight: string | number = textStyle.fontWeight ?? "400"; if (!!theme.fontWeights[fontWeight]) fontWeight = theme.fontWeights[fontWeight]; const fontStyle = textStyle.fontStyle ?? "normal"; let fontSize = textStyle.fontSize; let lineHeight = textStyle.lineHeight; if (allowFontScaling) { fontSize = responsiveSize(fontSize); lineHeight = responsiveSize(lineHeight); } const initialFontFamily = textStyle.fontFamily; if (!initialFontFamily || !theme.fontConfig[initialFontFamily]) { throw new Error( `Font family "${initialFontFamily}" does not exist in the theme.fontConfig` ); } const finalFontFamily = theme.fontConfig[initialFontFamily][fontWeight][fontStyle]; return { fontSize, fontWeight, fontFamily: finalFontFamily, fontStyle, }; }; /** * CustomText is a forwardRef component that applies a font configuration to the provided text style. * * @param scaleFontSize - Whether to slightly scale the font size based on the screen dimensions. * @param props - The props to apply the font configuration to. * @param ref - The ref to forward. * @returns A component with the font configuration applied. */ const CustomText = React.forwardRef( ( { scaleFontSize = true, ...props }: AtomComponentProps<"Text", BaseTextProps, TextStyleProps>, ref: any ) => { const { theme } = useTheme(); // Apply the font configuration to the provided text style. props.style = React.useMemo(() => { return { includeFontPadding: false, ...(props.style as any), ...buildFontConfig(props.style as TextStyle, scaleFontSize, theme), }; }, [props.style, scaleFontSize, theme]); return ( {props.children} ); } ); /** * Text is the component which controls the typography across your app. By default, it renders a component */ const Text = pearl, TextStyleProps>( CustomText, { componentName: "Text", type: "atom", animatable: true, }, textStyleFunctions ); export type TextProps = React.ComponentProps; Text.displayName = "Text"; export default Text;