UNPKG

react-native-element-dropdown

Version:

React Native Element Dropdown is a library that provides a customizable dropdown component for React Native applications.

533 lines (532 loc) 22.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _assign2 = _interopRequireDefault(require("lodash/assign")); var _differenceWith2 = _interopRequireDefault(require("lodash/differenceWith")); var _get3 = _interopRequireDefault(require("lodash/get")); var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _toolkits = require("../../toolkits"); var _useDeviceOrientation = require("../../useDeviceOrientation"); var _TextInput = _interopRequireDefault(require("../TextInput")); var _styles = require("./styles"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } const { isTablet } = _toolkits.useDetectDevice; const ic_down = require('../../assets/down.png'); const statusBarHeight = _reactNative.StatusBar.currentHeight || 0; const MultiSelectComponent = /*#__PURE__*/_react.default.forwardRef((props, currentRef) => { const orientation = (0, _useDeviceOrientation.useDeviceOrientation)(); const { testID, itemTestIDField, onChange, data = [], value, style = {}, labelField, valueField, searchField, selectedStyle, selectedTextStyle, itemContainerStyle, itemTextStyle, iconStyle, selectedTextProps = {}, activeColor = '#F6F7F8', containerStyle, fontFamily, placeholderStyle, iconColor = 'gray', inputSearchStyle, searchPlaceholder, searchPlaceholderTextColor = 'gray', placeholder = 'Select item', search = false, maxHeight = 340, minHeight = 0, maxSelect, disable = false, keyboardAvoiding = true, inside = false, inverted = true, renderItem, renderLeftIcon, renderRightIcon, renderSelectedItem, renderInputSearch, onFocus, onBlur, showsVerticalScrollIndicator = true, dropdownPosition = 'auto', flatListProps, alwaysRenderSelectedItem = false, searchQuery, backgroundColor, onChangeText, confirmSelectItem, confirmUnSelectItem, onConfirmSelectItem, accessibilityLabel, itemAccessibilityLabelField, visibleSelectedItem = true, mode = 'default', excludeItems = [], excludeSearchItems = [] } = props; const ref = (0, _react.useRef)(null); const [visible, setVisible] = (0, _react.useState)(false); const [currentValue, setCurrentValue] = (0, _react.useState)([]); const [listData, setListData] = (0, _react.useState)(data); const [, setKey] = (0, _react.useState)(Math.random()); const [position, setPosition] = (0, _react.useState)(); const [keyboardHeight, setKeyboardHeight] = (0, _react.useState)(0); const [searchText, setSearchText] = (0, _react.useState)(''); const { width: W, height: H } = _reactNative.Dimensions.get('window'); const styleContainerVertical = (0, _react.useMemo)(() => { return { backgroundColor: 'rgba(0,0,0,0.1)', alignItems: 'center' }; }, []); const styleHorizontal = (0, _react.useMemo)(() => { return { width: orientation === 'LANDSCAPE' ? W / 2 : '100%', alignSelf: 'center' }; }, [W, orientation]); (0, _react.useImperativeHandle)(currentRef, () => { return { open: eventOpen, close: eventClose }; }); (0, _react.useEffect)(() => { return eventClose; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const excludeData = (0, _react.useCallback)(data => { if (excludeItems.length > 0) { const getData = (0, _differenceWith2.default)(data, excludeItems, (obj1, obj2) => (0, _get3.default)(obj1, valueField) === (0, _get3.default)(obj2, valueField)); return getData || []; } else { return data || []; } }, [excludeItems, valueField]); (0, _react.useEffect)(() => { if (data && searchText.length === 0) { const filterData = excludeData(data); setListData([...filterData]); } if (searchText) { onSearch(searchText); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [data, searchText]); const eventOpen = () => { if (!disable) { _measure(); setVisible(true); if (onFocus) { onFocus(); } if (searchText.length > 0) { onSearch(searchText); } } }; const eventClose = () => { if (!disable) { setVisible(false); if (onBlur) { onBlur(); } } }; const font = (0, _react.useCallback)(() => { if (fontFamily) { return { fontFamily: fontFamily }; } else { return {}; } }, [fontFamily]); const getValue = (0, _react.useCallback)(() => { setCurrentValue(value ? [...value] : []); }, [value]); const _measure = (0, _react.useCallback)(() => { if (ref && ref !== null && ref !== void 0 && ref.current) { ref.current.measureInWindow((pageX, pageY, width, height) => { let isFull = isTablet ? false : mode === 'modal' || orientation === 'LANDSCAPE'; if (mode === 'auto') { isFull = false; } const top = isFull ? 20 : height + pageY + 2; const bottom = H - top + height; const left = _reactNative.I18nManager.isRTL ? W - width - pageX : pageX; setPosition({ isFull, width: Math.floor(width), top: Math.floor(top + statusBarHeight), bottom: Math.floor(bottom - statusBarHeight), left: Math.floor(left), height: Math.floor(height) }); }); } }, [H, W, orientation, mode]); const onKeyboardDidShow = (0, _react.useCallback)(e => { _measure(); setKeyboardHeight(e.endCoordinates.height); }, [_measure]); const onKeyboardDidHide = (0, _react.useCallback)(() => { setKeyboardHeight(0); _measure(); }, [_measure]); (0, _react.useEffect)(() => { const susbcriptionKeyboardDidShow = _reactNative.Keyboard.addListener('keyboardDidShow', onKeyboardDidShow); const susbcriptionKeyboardDidHide = _reactNative.Keyboard.addListener('keyboardDidHide', onKeyboardDidHide); return () => { if (typeof (susbcriptionKeyboardDidShow === null || susbcriptionKeyboardDidShow === void 0 ? void 0 : susbcriptionKeyboardDidShow.remove) === 'function') { susbcriptionKeyboardDidShow.remove(); } if (typeof (susbcriptionKeyboardDidHide === null || susbcriptionKeyboardDidHide === void 0 ? void 0 : susbcriptionKeyboardDidHide.remove) === 'function') { susbcriptionKeyboardDidHide.remove(); } }; }, [onKeyboardDidHide, onKeyboardDidShow]); (0, _react.useEffect)(() => { getValue(); }, [getValue, value]); const showOrClose = (0, _react.useCallback)(() => { if (!disable) { const visibleStatus = !visible; if (keyboardHeight > 0 && !visibleStatus) { return _reactNative.Keyboard.dismiss(); } _measure(); setVisible(visibleStatus); if (data) { const filterData = excludeData(data); setListData(filterData); } if (visibleStatus) { if (onFocus) { onFocus(); } } else { if (onBlur) { onBlur(); } } if (searchText.length > 0) { onSearch(searchText); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [disable, keyboardHeight, visible, _measure, data, searchText, onFocus, onBlur]); const onSearch = (0, _react.useCallback)(text => { if (text.length > 0) { const defaultFilterFunction = e => { var _get2; const item = (_get2 = (0, _get3.default)(e, searchField || labelField)) === null || _get2 === void 0 ? void 0 : _get2.toLowerCase().replace(/\s/g, '').normalize('NFD').replace(/[\u0300-\u036f]/g, ''); const key = text.toLowerCase().replace(/\s/g, '').normalize('NFD').replace(/[\u0300-\u036f]/g, ''); return item.indexOf(key) >= 0; }; const propSearchFunction = e => { const labelText = (0, _get3.default)(e, searchField || labelField); return searchQuery === null || searchQuery === void 0 ? void 0 : searchQuery(text, labelText); }; const dataSearch = data.filter(searchQuery ? propSearchFunction : defaultFilterFunction); if (excludeSearchItems.length > 0 || excludeItems.length > 0) { const excludeSearchData = (0, _differenceWith2.default)(dataSearch, excludeSearchItems, (obj1, obj2) => (0, _get3.default)(obj1, valueField) === (0, _get3.default)(obj2, valueField)); const filterData = excludeData(excludeSearchData); setListData(filterData); } else { setListData(dataSearch); } } else { const filterData = excludeData(data); setListData(filterData); } }, [data, searchQuery, excludeSearchItems, excludeItems, searchField, labelField, valueField, excludeData]); const onSelect = (0, _react.useCallback)(item => { const newCurrentValue = [...currentValue]; const index = newCurrentValue.findIndex(e => e === (0, _get3.default)(item, valueField)); if (index > -1) { newCurrentValue.splice(index, 1); } else { if (maxSelect) { if (newCurrentValue.length < maxSelect) { newCurrentValue.push((0, _get3.default)(item, valueField)); } } else { newCurrentValue.push((0, _get3.default)(item, valueField)); } } if (onConfirmSelectItem) { if (index > -1) { if (confirmUnSelectItem) { onConfirmSelectItem(newCurrentValue); } else { onChange(newCurrentValue); } } else { if (confirmSelectItem) { onConfirmSelectItem(newCurrentValue); } else { onChange(newCurrentValue); } } } else { onChange(newCurrentValue); } setKey(Math.random()); }, [confirmSelectItem, confirmUnSelectItem, currentValue, maxSelect, onChange, onConfirmSelectItem, valueField]); const _renderDropdown = () => { return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableWithoutFeedback, { testID: testID, accessible: !!accessibilityLabel, accessibilityLabel: accessibilityLabel, onPress: showOrClose }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _styles.styles.dropdown }, renderLeftIcon === null || renderLeftIcon === void 0 ? void 0 : renderLeftIcon(visible), /*#__PURE__*/_react.default.createElement(_reactNative.Text, _extends({ style: _reactNative.StyleSheet.flatten([_styles.styles.textItem, placeholderStyle, font()]) }, selectedTextProps), placeholder), renderRightIcon ? renderRightIcon(visible) : /*#__PURE__*/_react.default.createElement(_reactNative.Image, { source: ic_down, style: _reactNative.StyleSheet.flatten([_styles.styles.icon, { tintColor: iconColor }, iconStyle]) }))); }; const checkSelected = (0, _react.useCallback)(item => { const index = currentValue.findIndex(e => e === (0, _get3.default)(item, valueField)); return index > -1; }, [currentValue, valueField]); const _renderItem = (0, _react.useCallback)(_ref => { let { item, index } = _ref; const selected = checkSelected(item); (0, _assign2.default)(item, { _index: index }); return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableHighlight, { key: index.toString(), testID: (0, _get3.default)(item, itemTestIDField || labelField), accessible: !!accessibilityLabel, accessibilityLabel: (0, _get3.default)(item, itemAccessibilityLabelField || labelField), underlayColor: activeColor, onPress: () => onSelect(item) }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _reactNative.StyleSheet.flatten([itemContainerStyle, selected && { backgroundColor: activeColor, ..._styles.styles.wrapItem }]) }, renderItem ? renderItem(item, selected) : /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _styles.styles.item }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, { style: _reactNative.StyleSheet.flatten([_styles.styles.textItem, itemTextStyle, font()]) }, (0, _get3.default)(item, labelField))))); }, [accessibilityLabel, activeColor, checkSelected, font, itemAccessibilityLabelField, itemContainerStyle, itemTestIDField, itemTextStyle, labelField, onSelect, renderItem]); const renderSearch = (0, _react.useCallback)(() => { if (search) { if (renderInputSearch) { return renderInputSearch(text => { if (onChangeText) { setSearchText(text); onChangeText(text); } onSearch(text); }); } else { return /*#__PURE__*/_react.default.createElement(_TextInput.default, { testID: testID + ' input', accessibilityLabel: accessibilityLabel + ' input', style: [_styles.styles.input, inputSearchStyle], inputStyle: [inputSearchStyle, font()], autoCorrect: false, placeholder: searchPlaceholder, onChangeText: e => { if (onChangeText) { setSearchText(e); onChangeText(e); } onSearch(e); }, showIcon: true, placeholderTextColor: searchPlaceholderTextColor, iconStyle: [{ tintColor: iconColor }, iconStyle] }); } } return null; }, [accessibilityLabel, font, iconColor, iconStyle, inputSearchStyle, onChangeText, onSearch, renderInputSearch, search, searchPlaceholder, searchPlaceholderTextColor, testID]); const _renderList = (0, _react.useCallback)(isTopPosition => { const isInverted = !inverted ? false : isTopPosition; const _renderListHelper = () => { return /*#__PURE__*/_react.default.createElement(_reactNative.FlatList, _extends({ testID: testID + ' flatlist', accessibilityLabel: accessibilityLabel + ' flatlist' }, flatListProps, { keyboardShouldPersistTaps: "handled", data: listData, inverted: isTopPosition ? inverted : false, renderItem: _renderItem, keyExtractor: (_item, index) => index.toString(), showsVerticalScrollIndicator: showsVerticalScrollIndicator })); }; return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableWithoutFeedback, null, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _styles.styles.flexShrink }, isInverted && _renderListHelper(), renderSearch(), !isInverted && _renderListHelper())); }, [_renderItem, accessibilityLabel, flatListProps, listData, inverted, renderSearch, showsVerticalScrollIndicator, testID]); const _renderModal = (0, _react.useCallback)(() => { if (visible && position) { const { isFull, width, height, top, bottom, left } = position; const onAutoPosition = () => { if (keyboardHeight > 0) { return bottom < keyboardHeight + height; } return bottom < (search ? 150 : 100); }; if (width && top && bottom) { const styleVertical = { left: left, maxHeight: maxHeight, minHeight: minHeight }; const isTopPosition = dropdownPosition === 'auto' ? onAutoPosition() : dropdownPosition === 'top'; let keyboardStyle = {}; let extendHeight = !isTopPosition ? top : bottom; if (keyboardAvoiding && keyboardHeight > 0 && isTopPosition && dropdownPosition === 'auto') { extendHeight = keyboardHeight; } return /*#__PURE__*/_react.default.createElement(_reactNative.Modal, { transparent: true, statusBarTranslucent: true, visible: visible, supportedOrientations: ['landscape', 'portrait'], onRequestClose: showOrClose }, /*#__PURE__*/_react.default.createElement(_reactNative.TouchableWithoutFeedback, { onPress: showOrClose }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _reactNative.StyleSheet.flatten([_styles.styles.flex1, isFull && styleContainerVertical, backgroundColor && { backgroundColor: backgroundColor }, keyboardStyle]) }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _reactNative.StyleSheet.flatten([_styles.styles.flex1, !isTopPosition ? { paddingTop: extendHeight } : { justifyContent: 'flex-end', paddingBottom: extendHeight }, isFull && _styles.styles.fullScreen]) }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _reactNative.StyleSheet.flatten([_styles.styles.container, isFull ? styleHorizontal : styleVertical, { width }, containerStyle]) }, _renderList(isTopPosition)))))); } return null; } return null; }, [visible, search, position, keyboardHeight, maxHeight, minHeight, dropdownPosition, keyboardAvoiding, showOrClose, styleContainerVertical, backgroundColor, containerStyle, styleHorizontal, _renderList]); const unSelect = item => { if (!disable) { onSelect(item); } }; const _renderItemSelected = inside => { const list = data.filter(e => { const check = value === null || value === void 0 ? void 0 : value.indexOf((0, _get3.default)(e, valueField)); if (check !== -1) { return e; } }); return /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _reactNative.StyleSheet.flatten([_styles.styles.rowSelectedItem, inside && _styles.styles.flex1]) }, list.map(e => { if (renderSelectedItem) { return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableWithoutFeedback, { testID: (0, _get3.default)(e, itemTestIDField || labelField), accessible: !!accessibilityLabel, accessibilityLabel: (0, _get3.default)(e, itemAccessibilityLabelField || labelField), key: (0, _get3.default)(e, labelField), onPress: () => unSelect(e) }, renderSelectedItem(e, () => { unSelect(e); })); } else { return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableWithoutFeedback, { testID: (0, _get3.default)(e, itemTestIDField || labelField), accessible: !!accessibilityLabel, accessibilityLabel: (0, _get3.default)(e, itemAccessibilityLabelField || labelField), key: (0, _get3.default)(e, labelField), onPress: () => unSelect(e) }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _reactNative.StyleSheet.flatten([_styles.styles.selectedItem, selectedStyle]) }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, { style: _reactNative.StyleSheet.flatten([_styles.styles.selectedTextLeftItem, selectedTextStyle, font()]) }, (0, _get3.default)(e, labelField)), /*#__PURE__*/_react.default.createElement(_reactNative.Text, { style: _reactNative.StyleSheet.flatten([_styles.styles.selectedTextItem, selectedTextStyle]) }, "\u24E7"))); } })); }; const _renderInside = () => { return /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _reactNative.StyleSheet.flatten([_styles.styles.mainWrap, style]), ref: ref, onLayout: _measure }, _renderDropdownInside(), _renderModal()); }; const _renderDropdownInside = () => { return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableWithoutFeedback, { testID: testID, accessible: !!accessibilityLabel, accessibilityLabel: accessibilityLabel, onPress: showOrClose }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _styles.styles.dropdownInside }, renderLeftIcon === null || renderLeftIcon === void 0 ? void 0 : renderLeftIcon(), value && (value === null || value === void 0 ? void 0 : value.length) > 0 ? _renderItemSelected(true) : /*#__PURE__*/_react.default.createElement(_reactNative.Text, { style: _reactNative.StyleSheet.flatten([_styles.styles.textItem, placeholderStyle, font()]) }, placeholder), renderRightIcon ? renderRightIcon() : /*#__PURE__*/_react.default.createElement(_reactNative.Image, { source: ic_down, style: _reactNative.StyleSheet.flatten([_styles.styles.icon, { tintColor: iconColor }, iconStyle]) }))); }; if (inside) { return _renderInside(); } return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: _reactNative.StyleSheet.flatten([_styles.styles.mainWrap, style]), ref: ref, onLayout: _measure }, _renderDropdown(), _renderModal()), (!visible || alwaysRenderSelectedItem) && visibleSelectedItem && _renderItemSelected(false)); }); var _default = MultiSelectComponent; exports.default = _default; //# sourceMappingURL=index.js.map