import * as React from 'react'; import { Animated, GestureResponderEvent, NativeSyntheticEvent, Platform, Pressable, StyleProp, StyleSheet, TextLayoutEventData, View, ViewStyle, } from 'react-native'; import { useInternalTheme } from '../../core/theming'; import type { ThemeProp } from '../../types'; import Badge from '../Badge'; import Icon, { IconSource } from '../Icon'; import Text from '../Typography/Text'; export type Props = React.ComponentPropsWithRef & { /** * The label text of the item. */ label?: string; /** * Badge to show on the icon, can be `true` to show a dot, `string` or `number` to show text. */ badge?: string | number | boolean; /** * Whether the item is disabled. */ disabled?: boolean; /** * @renamed Renamed from 'icon' to 'focusedIcon' in v5.x * Icon to use as the focused destination icon, can be a string, an image source or a react component */ focusedIcon?: IconSource; /** * @renamed Renamed from 'icon' to 'focusedIcon' in v5.x * Icon to use as the unfocused destination icon, can be a string, an image source or a react component */ unfocusedIcon?: IconSource; /** * Whether to highlight the drawer item as active. */ active?: boolean; /** * Function to execute on press. */ onPress?: (e: GestureResponderEvent) => void; /** * Specifies the largest possible scale a label font can reach. */ labelMaxFontSizeMultiplier?: number; /** * Accessibility label for the button. This is read by the screen reader when the user taps the button. */ accessibilityLabel?: string; style?: StyleProp; /** * @optional */ theme?: ThemeProp; /** * TestID used for testing purposes */ testID?: string; }; const badgeSize = 8; const iconSize = 24; const itemSize = 56; const outlineHeight = 32; /** * Note: Available in v5.x with theme version 3 * * Collapsed component used to show an action item with an icon and optionally label in a navigation drawer. * * ## Usage * ```js * import * as React from 'react'; * import { Drawer } from 'react-native-paper'; * * const MyComponent = () => ( * * ); * * export default MyComponent; * ``` */ const DrawerCollapsedItem = ({ focusedIcon, unfocusedIcon, label, active, theme: themeOverrides, style, onPress, disabled, accessibilityLabel, badge = false, testID = 'drawer-collapsed-item', labelMaxFontSizeMultiplier, ...rest }: Props) => { const theme = useInternalTheme(themeOverrides); const { isV3 } = theme; const { scale } = theme.animation; const [numOfLines, setNumOfLines] = React.useState(1); const { current: animScale } = React.useRef( new Animated.Value(active ? 1 : 0.5) ); React.useEffect(() => { if (!active) { animScale.setValue(0.5); } }, [animScale, active]); if (!isV3) { return null; } const handlePressOut = () => { Animated.timing(animScale, { toValue: 1, duration: 150 * scale, useNativeDriver: true, }).start(); }; const iconPadding = ((!label ? itemSize : outlineHeight) - iconSize) / 2; const backgroundColor = active ? theme.colors.secondaryContainer : 'transparent'; const labelColor = active ? theme.colors.onSurface : theme.colors.onSurfaceVariant; const iconColor = active ? theme.colors.onSecondaryContainer : theme.colors.onSurfaceVariant; const onTextLayout = ({ nativeEvent, }: NativeSyntheticEvent) => { setNumOfLines(nativeEvent.lines.length); }; // Label is cut off on Android, when centered "labelMedium" text // has more than 4 lines, so there is a need to decrease the letter spacing. const androidLetterSpacingStyle = Platform.OS === 'android' && numOfLines > 4 && styles.letterSpacing; const labelTextStyle = { color: labelColor, ...(isV3 ? theme.fonts.labelMedium : {}), }; const icon = !active && unfocusedIcon !== undefined ? unfocusedIcon : focusedIcon; return ( {/* eslint-disable-next-line react-native-a11y/has-accessibility-props */} {badge && ( {typeof badge === 'boolean' ? ( ) : ( {badge} )} )} {label ? ( {label} ) : null} ); }; DrawerCollapsedItem.displayName = 'Drawer.CollapsedItem'; const styles = StyleSheet.create({ wrapper: { width: 80, marginBottom: 12, minHeight: itemSize, alignItems: 'center', }, outline: { width: itemSize, height: outlineHeight, borderRadius: itemSize / 2, alignItems: 'center', justifyContent: 'center', }, roundedOutline: { height: itemSize, }, icon: { position: 'absolute', }, letterSpacing: { letterSpacing: 0.3, alignSelf: 'stretch', }, label: { marginHorizontal: 12, marginTop: 4, textAlign: 'center', }, badgeContainer: { position: 'absolute', left: 20, bottom: 20, zIndex: 2, }, }); export default DrawerCollapsedItem;