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

109 lines (99 loc) 4 kB
import React, { useCallback, useMemo, useRef, useState, forwardRef } from 'react'; import { StyleSheet } from 'react-native'; import { isUndefined, map } from 'lodash'; import { Constants } from "../../commons/new"; import { useCombinedRefs } from "../../hooks"; import TextField from "../TextField"; import Chip from "../../components/chip"; const removeIcon = require("./assets/xSmall.png"); export let ChipsInputChangeReason; (function (ChipsInputChangeReason) { ChipsInputChangeReason["Added"] = "added"; ChipsInputChangeReason["Removed"] = "removed"; })(ChipsInputChangeReason || (ChipsInputChangeReason = {})); const ChipsInput = forwardRef((props, refToForward) => { const fieldRef = useCombinedRefs(refToForward); const { chips = [], defaultChipProps, invalidChipProps, leadingAccessory, onChange, fieldStyle, maxChips, ...others } = props; const [markedForRemoval, setMarkedForRemoval] = useState(undefined); const fieldValue = useRef(others.value); const addChip = useCallback(() => { const reachedMaximum = maxChips && chips?.length >= maxChips; if (fieldValue.current && !reachedMaximum) { const newChip = { label: fieldValue.current }; setMarkedForRemoval(undefined); // @ts-expect-error fieldRef.current.clear(); fieldValue.current = ''; /* NOTE: Delay change event to give clear field time to complete and avoid a flickering */ setTimeout(() => { onChange?.([...chips, newChip], ChipsInputChangeReason.Added, newChip); }, 0); } }, [onChange, chips, maxChips]); const removeMarkedChip = useCallback(() => { if (!isUndefined(markedForRemoval)) { const removedChip = chips?.splice(markedForRemoval, 1); onChange?.([...chips], ChipsInputChangeReason.Removed, removedChip?.[0]); setMarkedForRemoval(undefined); } }, [chips, markedForRemoval, onChange]); const onChipPress = useCallback(({ customValue: index }) => { const selectedChip = chips[index]; selectedChip?.onPress?.(); setMarkedForRemoval(index); }, [chips]); const onChangeText = useCallback(value => { fieldValue.current = value; props.onChangeText?.(value); if (!isUndefined(markedForRemoval)) { setMarkedForRemoval(undefined); } }, [props.onChangeText, markedForRemoval]); const onKeyPress = useCallback(event => { props.onKeyPress?.(event); const keyCode = event?.nativeEvent?.key; const pressedBackspace = keyCode === Constants.backspaceKey; if (pressedBackspace && !fieldValue.current) { if (isUndefined(markedForRemoval) || markedForRemoval !== chips.length - 1) { setMarkedForRemoval(chips.length - 1); } else { removeMarkedChip(); } } }, [chips, props.onKeyPress, markedForRemoval, removeMarkedChip]); const chipList = useMemo(() => { return <> {leadingAccessory} {map(chips, (chip, index) => { const isMarkedForRemoval = index === markedForRemoval; return <Chip key={index} customValue={index} // resetSpacings // paddingH-s2 marginR-s2 marginB-s2 dismissIcon={removeIcon} {...defaultChipProps} {...chip.invalid ? invalidChipProps : undefined} {...chip} onPress={onChipPress} onDismiss={isMarkedForRemoval ? removeMarkedChip : undefined} />; })} </>; }, [chips, leadingAccessory, defaultChipProps, removeMarkedChip, markedForRemoval]); return <TextField // @ts-expect-error ref={fieldRef} leadingAccessory={chipList} blurOnSubmit={false} {...others} onChangeText={onChangeText} onSubmitEditing={addChip} fieldStyle={[fieldStyle, styles.fieldStyle]} onKeyPress={onKeyPress} accessibilityHint={props.editable ? 'press keyboard delete button to remove last tag' : undefined} />; }); const styles = StyleSheet.create({ fieldStyle: { flexWrap: 'wrap' } }); // @ts-expect-error ChipsInput.changeReasons = { ADDED: 'added', REMOVED: 'removed' }; export default ChipsInput;