import React from 'react' import { StyleSheet, Text as ReactNativeText, Platform } from 'react-native' import type { TextStyle as ReactNativeTextStyle, TextProps as ReactNativeTextProps, StyleProp, } from 'react-native' import { useTheme } from '../../hooks' import { tokens } from '../../vendor/tapestry/tokens' // ================================= // ====== Constants ================ // ================================= // TextStyle extends ViewStyle, which includes border properties. // CCA has issues with borders on Text on iOS. (https://github.com/planningcenter/chat-mobile/pull/177) // Our pattern is to apply boarders to a parent View instead. type BorderKeys = | 'borderWidth' | 'borderBottomWidth' | 'borderLeftWidth' | 'borderRightWidth' | 'borderTopWidth' | 'borderColor' | 'borderBottomColor' | 'borderLeftColor' | 'borderRightColor' | 'borderTopColor' | 'borderStyle' export type TextStyle = Omit & { [K in BorderKeys]?: never } const VARIANTS = { plain: 'plain', secondary: 'secondary', tertiary: 'tertiary', footnote: 'footnote', } as const type VariantUnion = (typeof VARIANTS)[keyof typeof VARIANTS] type VariantStyles = Record // ================================= // ====== Component ================ // ================================= export interface TextProps extends Omit { /** * Changes the styles and size of the text. */ variant?: VariantUnion /** * Text styles (border and background properties are not allowed) */ style?: StyleProp } export function Text({ style, variant = 'plain', children, ...props }: TextProps) { const styles = useStyles() const variantStyleMap: VariantStyles = { [VARIANTS.plain]: styles.plain, [VARIANTS.secondary]: styles.secondary, [VARIANTS.tertiary]: styles.tertiary, [VARIANTS.footnote]: styles.footnote, } return ( {children} ) } // ================================= // ====== Styles =================== // ================================= const useStyles = () => { const { colors } = useTheme() return StyleSheet.create({ base: { ...Platform.select({ android: { fontFamily: 'normal', // This forces the text to be normal weight when the "Bold font" accessibility setting is enabled. While this is not ideal, it fixes a bug where the text without a hard coded fontWeight gets cut off on Android. https://github.com/facebook/react-native/issues/15114 }, default: null, // iOS needs to specify its own font family otherwise the italic style won't work. (Used in message_markdown.tsx) It's "Bold font" accessibility setting works as expected. }), }, plain: { color: colors.textColorDefaultPrimary, fontSize: tokens.fontSizeMd, }, // This is a dupe of the plain variant to support the legacy API. // Once we move to the new Doxy font scale we can remove it. // See: https://www.figma.com/design/ZR0ZP6FdbOBOK3fUSpRr0Q/CC-Redux-2025?node-id=156-1069&m=dev secondary: { color: colors.textColorDefaultPrimary, fontSize: tokens.fontSizeMd, }, tertiary: { color: colors.textColorDefaultSecondary, fontSize: tokens.fontSizeSm, }, footnote: { color: colors.textColorDefaultSecondary, fontSize: tokens.fontSizeXs, }, }) }