import * as React from "react"; import { AccessibilityState, Animated, Platform, StyleProp, StyleSheet, TouchableWithoutFeedback, View, ViewStyle, } from "react-native"; import color from "color"; import { SvgIcon } from "../Icon"; import Surface from "../Surface"; import Text from "../Text"; import TouchableRipple from "../TouchableRipple/TouchableRipple"; import { black, white } from "../theme/colors"; import { DefaultTheme, ThemeContext } from "styled-components"; import CheckIcon from "@mdi/svg/svg/check.svg"; import CloseCircleIcon from "@mdi/svg/svg/close-circle.svg"; import type { EllipsizeProp } from "../types"; type Props = React.ComponentProps & { /** * Mode of the chip. * - `flat` - flat chip without outline. * - `outlined` - chip with an outline. */ mode?: "flat" | "outlined"; /** * Text content of the `Chip`. */ children: React.ReactNode; /** * Icon to display for the `Chip`. Both icon and avatar cannot be specified. */ icon?: React.ReactElement; /** * Avatar to display for the `Chip`. Both icon and avatar cannot be specified. */ avatar?: React.ReactNode; /** * Whether chip is selected. */ selected?: boolean; /** * Whether to style the chip color as selected. */ selectedColor?: string; /** * Whether the chip is disabled. A disabled chip is greyed out and `onPress` is not called on touch. */ disabled?: boolean; /** * Accessibility label for the chip. This is read by the screen reader when the user taps the chip. */ accessibilityLabel?: string; /** * Accessibility label for the close icon. This is read by the screen reader when the user taps the close icon. */ closeIconAccessibilityLabel?: string; /** * Function to execute on press. */ onPress?: () => void; /** * Function to execute on long press. */ onLongPress?: () => void; /** * Function to execute on close button press. The close button appears only when this prop is specified. */ onClose?: () => void; /** * Style of chip's text */ textStyle?: any; style?: StyleProp; /** * @optional */ theme?: DefaultTheme; /** * Pass down testID from chip props to touchable for Detox tests. */ testID?: string; /** * Ellipsize Mode for the children text */ ellipsizeMode?: EllipsizeProp; }; /** * Chips can be used to display entities in small blocks. * *
*
* *
Flat chip
*
*
* *
Outlined chip
*
*
* * ## Usage * ```js * import * as React from 'react'; * import Chip from 'react-native-simple-elements/components/Chip'; * * const MyComponent = () => ( * console.log('Pressed')}>Example Chip * ); * * export default MyComponent; * ``` */ const Chip = ({ mode = "flat", children, icon, avatar, selected = false, disabled = false, accessibilityLabel, closeIconAccessibilityLabel = "Close", onPress, onLongPress, onClose, textStyle, style, testID, selectedColor, ellipsizeMode, ...rest }: Props) => { const theme = React.useContext(ThemeContext); const { current: elevation } = React.useRef( new Animated.Value(0) ); const handlePressIn = () => { const { scale } = theme.animation; Animated.timing(elevation, { toValue: 4, duration: 200 * scale, useNativeDriver: true, }).start(); }; const handlePressOut = () => { const { scale } = theme.animation; Animated.timing(elevation, { toValue: 0, duration: 150 * scale, useNativeDriver: true, }).start(); }; const { dark, colors } = theme; const defaultBackgroundColor = mode === "outlined" ? colors.surface : dark ? "#383838" : "#ebebeb"; const { backgroundColor = defaultBackgroundColor, borderRadius = 16, } = (StyleSheet.flatten(style) || {}) as ViewStyle; const borderColor = mode === "outlined" ? color( selectedColor !== undefined ? selectedColor : color(dark ? white : black) ) .alpha(0.29) .rgb() .string() : backgroundColor; const textColor = disabled ? colors.disabled : color(selectedColor !== undefined ? selectedColor : colors.text) .alpha(0.87) .rgb() .string(); const iconColor = disabled ? colors.disabled : color(selectedColor !== undefined ? selectedColor : colors.text) .alpha(0.54) .rgb() .string(); const backgroundColorString = typeof backgroundColor === "string" ? backgroundColor : defaultBackgroundColor; const selectedBackgroundColor = (dark ? color(backgroundColorString).lighten(mode === "outlined" ? 0.2 : 0.4) : color(backgroundColorString).darken(mode === "outlined" ? 0.08 : 0.2) ) .rgb() .string(); const underlayColor = selectedColor ? color(selectedColor).fade(0.5).rgb().string() : selectedBackgroundColor; const accessibilityTraits = ["button"]; const accessibilityState: AccessibilityState = { selected, disabled, }; if (selected) { accessibilityTraits.push("selected"); } if (disabled) { accessibilityTraits.push("disabled"); } return ( } {...rest} > {avatar && !icon ? ( {React.isValidElement(avatar) ? React.cloneElement(avatar, { style: [styles.avatar, avatar.props.style], }) : avatar} ) : null} {icon || selected ? ( {icon ? ( ) : ( )} ) : null} {children} {onClose ? ( ) : null} ); }; const styles = StyleSheet.create({ container: { borderWidth: StyleSheet.hairlineWidth, borderStyle: "solid", flexDirection: "row", }, content: { flexDirection: "row", alignItems: "center", paddingLeft: 4, position: "relative", }, icon: { padding: 4, alignSelf: "center", }, closeIcon: { marginRight: 4, }, text: { minHeight: 24, lineHeight: 24, textAlignVertical: "center", marginVertical: 4, }, avatar: { width: 24, height: 24, borderRadius: 12, }, avatarWrapper: { marginRight: 4, }, avatarSelected: { position: "absolute", top: 4, left: 4, backgroundColor: "rgba(0, 0, 0, .29)", }, closeButtonStyle: { position: "absolute", right: 0, height: "100%", justifyContent: "center", alignItems: "center", }, }); export default Chip;