UNPKG

react-native-ui-lib

Version:

<p align="center"> <img src="https://user-images.githubusercontent.com/1780255/105469025-56759000-5ca0-11eb-993d-3568c1fd54f4.png" height="250px" style="display:block"/> </p> <p align="center">UI Toolset & Components Library for React Native</p> <p a

263 lines (236 loc) • 6.86 kB
import _pt from "prop-types"; import _ from 'lodash'; import React, { useCallback } from 'react'; import { StyleSheet } from 'react-native'; import Assets from "../../assets"; import { asBaseComponent } from "../../commons/new"; import { BorderRadiuses, Spacings } from "../../style"; import Avatar from "../avatar"; import Badge from "../badge"; import Text from "../text"; import TouchableOpacity from "../touchableOpacity"; import View from "../view"; import Icon from "../icon"; const DEFAULT_SIZE = 26; /** * @description: Chip component * @extends: TouchableOpacity * @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/ChipScreen.tsx * @image: https://user-images.githubusercontent.com/1780255/119636022-e9743180-be1c-11eb-8f02-22eeab6558cd.png */ const Chip = ({ avatarProps, backgroundColor, badgeProps, useCounter, borderRadius = BorderRadiuses.br100, containerStyle, onDismiss, dismissColor, dismissIcon = Assets.icons.x, dismissIconStyle, dismissContainerStyle, iconProps, iconSource, iconStyle, rightIconSource, leftElement, rightElement, label, labelStyle, onPress, resetSpacings, size = DEFAULT_SIZE, useSizeAsMinimum = true, testID, ...others }) => { const renderIcon = useCallback(iconPosition => { const isLeftIcon = iconPosition === 'left'; return <Icon source={isLeftIcon ? iconSource : rightIconSource} testID={`${testID}.icon`} {...iconProps} style={[getMargins('iconSource'), iconStyle]} />; }, [iconSource, rightIconSource, iconStyle, iconProps]); const renderBadge = useCallback(() => { return <Badge size={20} testID={`${testID}.counter`} backgroundColor={useCounter ? 'transparent' : undefined} {...badgeProps} // @ts-ignore containerStyle={[getMargins('badge'), badgeProps.containerStyle]} />; }, [badgeProps]); const renderOnDismiss = useCallback(() => { return <TouchableOpacity style={[getMargins('dismiss'), dismissContainerStyle]} onPress={onDismiss} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} testID={`${testID}.dismiss`}> <Icon source={dismissIcon} tintColor={dismissColor} style={[dismissIconStyle]} accessibilityLabel="dismiss" testID={`${testID}.dismissIcon`} /> </TouchableOpacity>; }, [dismissContainerStyle, onDismiss, dismissIcon, dismissIconStyle]); const renderAvatar = useCallback(() => { return <Avatar size={20} testID={`${testID}.avatar`} {...avatarProps} // @ts-ignore containerStyle={[getMargins('avatar'), avatarProps.containerStyle]} />; }, [avatarProps]); const renderLabel = useCallback(() => { return <Text text90M numberOfLines={1} style={[styles.label, getMargins('label'), labelStyle]} testID={`${testID}.label`}> {!!label && label} </Text>; }, [label, labelStyle]); const getMargins = useCallback(element => { if (!resetSpacings) { switch (element) { case 'label': if (avatarProps) { return { marginRight: Spacings.s2, marginLeft: Spacings.s1 }; } if (badgeProps) { return { marginLeft: Spacings.s3, marginRight: Spacings.s1 }; } if (rightElement && leftElement) { return { marginHorizontally: 2 }; } if (iconSource || leftElement) { return { marginLeft: 2, marginRight: Spacings.s3 }; } if (rightIconSource || rightElement) { return { marginLeft: Spacings.s3, marginRight: 2 }; } if (onDismiss) { return { marginLeft: Spacings.s3, marginRight: Spacings.s2 }; } else { return { marginHorizontal: Spacings.s3 }; } case 'avatar': return { marginLeft: 2 }; case 'badge': return { marginRight: Spacings.s1 }; case 'dismiss': return { marginRight: Spacings.s2 }; } } }, [avatarProps, badgeProps, iconSource, rightIconSource, onDismiss]); const getContainerSize = useCallback(() => { const width = useSizeAsMinimum ? 'minWidth' : 'width'; const height = useSizeAsMinimum ? 'minHeight' : 'height'; return typeof size === 'object' ? { [width]: _.get(size, 'width'), [height]: _.get(size, 'height') } : { [width]: size, [height]: size }; }, [size]); const Container = onPress ? TouchableOpacity : View; return <Container activeOpacity={1} onPress={onPress} style={[styles.container, { backgroundColor }, { borderRadius }, containerStyle, getContainerSize()]} testID={testID} {...others}> {avatarProps && renderAvatar()} {iconSource && renderIcon('left')} {leftElement} {label && renderLabel()} {rightElement} {rightIconSource && renderIcon('right')} {badgeProps && renderBadge()} {onDismiss && renderOnDismiss()} </Container>; }; Chip.propTypes = { /** * Chip's size. Number or a width and height object. */ /*GENERAL*/ size: _pt.oneOfType([_pt.number, _pt.shape({ width: _pt.number.isRequired, height: _pt.number.isRequired })]), /** * On Chip press callback */ onPress: _pt.func, /** * Chip's background color */ backgroundColor: _pt.string, /** * The Chip borderRadius */ borderRadius: _pt.number, /** * Uses size as minWidth and minHeight - default is true */ useSizeAsMinimum: _pt.bool, /** * Disables all internal elements default spacings. Helps reach a custom design */ resetSpacings: _pt.bool, /** * Used as testing identifier */ testID: _pt.string, /** * Main Chip text */ /*LABEL*/ label: _pt.string, /** * Display badge as counter (no background) */ useCounter: _pt.bool, /** * Left custom element */ /*LEFT ELEMENT*/ leftElement: _pt.element, /** * Right custom element */ /*RIGHT ELEMENT*/ rightElement: _pt.element, /** * Adds a dismiss button and serves as its callback */ /*DISMISS ('x' button)*/ onDismiss: _pt.func, /** * Dismiss color */ dismissColor: _pt.string }; Chip.displayName = 'Chip'; const styles = StyleSheet.create({ container: { alignItems: 'center', justifyContent: 'center', flexDirection: 'row', borderWidth: 1, borderRadius: BorderRadiuses.br100 }, label: { alignItems: 'center', justifyContent: 'center' } }); export default asBaseComponent(Chip);