import { Animated } from 'react-native'; import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; import { StyledView, StyledText, StyledIcon } from './StyledBadge'; import BadgeStatus from './Status'; import BadgeCount from './Count'; import type { BasicBadgeProps, IconBadgeProps } from './types'; import { DEFAULT_MAX_NUMBER } from './constants'; export type BadgeProps = BasicBadgeProps | IconBadgeProps; const getPaddingState = (content: string): 'narrowContent' | 'wideContent' => content.length > 1 ? 'wideContent' : 'narrowContent'; const Badge = ({ content: originalContent, visible = true, max = DEFAULT_MAX_NUMBER, intent = 'danger', style, testID, size = 'medium', variant = 'filled', icon, ...nativeProps }: BadgeProps): ReactElement => { const { current: opacity } = React.useRef( new Animated.Value(visible ? 1 : 0) ); const isFirstRendering = React.useRef(true); React.useEffect(() => { // Do not run animation on very first rendering if (isFirstRendering.current) { isFirstRendering.current = false; return; } Animated.timing(opacity, { toValue: visible ? 1 : 0, duration: 150, useNativeDriver: true, }).start(); }, [visible, opacity]); const isIconBadge = !!icon; const isStringBadge = !isIconBadge && typeof originalContent === 'string'; const content = useMemo(() => { if (isIconBadge) { return ''; } return typeof originalContent === 'number' && originalContent > max ? `${max}+` : String(originalContent); }, [isIconBadge, originalContent, max]); return ( {isIconBadge ? ( ) : ( {content} )} ); }; export default Object.assign(Badge, { Status: BadgeStatus, Count: BadgeCount, });