import type {ReactNode} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {StyleSheet, Text, View} from 'react-native'; import {useTheme} from '../../theme/ThemeProvider'; import type {A11yProps} from '../../types'; export type BadgeProps = A11yProps & { /** Number or short text. Numbers above `max` render as `${max}+`. */ value?: number | string; max?: number; /** Small dot without text. */ dot?: boolean; color?: string; textColor?: string; /** Height of the badge (and diameter of the dot). */ size?: number; /** Corner used when wrapping `children`. */ position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'; /** Hide the badge but keep the children. */ visible?: boolean; style?: StyleProp; /** Element the badge is attached to. Without children the badge renders inline. */ children?: ReactNode; }; export const Badge = ({ accessibilityLabel, children, color, dot, max = 99, position = 'top-right', size, style, testID, textColor = '#FFFFFF', value, visible = true, }: BadgeProps) => { const {colors} = useTheme(); const badgeColor = color ?? colors.secondary; const badgeSize = size ?? (dot ? 10 : 18); const label = typeof value === 'number' && value > max ? `${max}+` : value?.toString(); const shouldShow = visible && (dot || (label !== undefined && label !== '' && label !== '0')); const badge = shouldShow ? ( {!dot && ( {label} )} ) : null; if (!children) { return badge; } return ( {children} {badge} ); }; const styles = StyleSheet.create({ wrapper: { alignSelf: 'flex-start', }, badge: { alignItems: 'center', justifyContent: 'center', alignSelf: 'flex-start', }, attached: { position: 'absolute', zIndex: 1, }, });